Compare commits

...

291 Commits

Author SHA1 Message Date
Cameron Gutman f1be5365bb Version 12.0.2 2023-11-01 20:35:57 -05:00
Cameron Gutman c356862ac1 Avoid unnecessary reinitialization of PS4/PS5 gamepads during stream exit
onInputDeviceChanged() is triggered by starting/stopping pointer capture, so we should
unregister our callbacks before that happens to avoid triggering several gamepad context
reinitializations right as the stream is exiting
2023-10-29 16:45:07 -05:00
Cameron Gutman fc77322f59 Merge remote-tracking branch 'origin/weblate' 2023-10-29 15:51:59 -05:00
Cameron Gutman 032e944d49 Update moonlight-common-c with multi-homed host fix 2023-10-29 15:34:09 -05:00
Cameron Gutman 0da47da8d8 Move shortcut creation/updates off the main thread for the common cases
These caused quite a few ANRs due to long Binder calls in ShortcutManager.getDynamicShortcuts()
2023-10-26 00:24:44 -05:00
Cameron Gutman ebfe843299 Don't process incoming input device requests from the host after we've stopped 2023-10-26 00:05:24 -05:00
Cameron Gutman 827d2362b7 Don't create LightsSessions for devices without an RGB LED 2023-10-25 23:53:35 -05:00
Cameron Gutman 4fa1eb4088 Fix max FPS detection on Lollipop and earlier 2023-10-25 23:47:40 -05:00
Cameron Gutman 885b59fd52 Fix NPE when receiving non-view-associated mouse events with absolute mouse mode enabled 2023-10-25 23:13:54 -05:00
Cameron Gutman ff5d9f72aa Fix ANRs trying to get battery state during controller arrival 2023-10-25 23:13:11 -05:00
Marocco2 030bb91789 Translated using Weblate (Italian)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2023-10-22 09:01:23 +00:00
Jorys Paulin 34788b2808 Translated using Weblate (French)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-10-19 06:09:40 +02:00
Cameron Gutman abc4123c52 Version 12.0.1 2023-10-17 22:39:49 -05:00
Cameron Gutman 26f8c0842e Merge remote-tracking branch 'origin/weblate' 2023-10-16 23:57:21 -05:00
Cameron Gutman d430d83ba8 Add clickpad button emulation combo (Select+L1) 2023-10-16 23:56:56 -05:00
Cameron Gutman a52f189fb1 Update ShieldControllerExtensions to fix crash in getBatteryPercentage() 2023-10-16 23:55:39 -05:00
Cameron Gutman dc1045b69e Don't lie to our own clickpad heuristics when overriding the controller type 2023-10-16 23:38:12 -05:00
Cameron Gutman 3a89dbf4ab Update moonlight-common-c 2023-10-16 23:17:08 -05:00
Cameron Gutman d69b4eca1e Disable gamepad motion sensors by default on Android 12 due to an OS bug 2023-10-16 23:16:55 -05:00
Marocco2 568bba82f0 Translated using Weblate (Italian)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2023-10-16 04:19:16 +00:00
Smoukus b52e6c88ec Translated using Weblate (German)
Currently translated at 92.5% (224 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2023-10-16 04:19:14 +00:00
Cameron Gutman 720595091e Change AV1 bitrate multiplier to match HEVC 2023-10-15 12:49:42 -05:00
Cameron Gutman fe929c8e58 Fix debug build assert 2023-10-13 23:23:42 -05:00
Cameron Gutman 9ecec1eb3c Add support for H.264/HEVC bitstreams with multiple sets of parameter set NALUs 2023-10-13 23:21:50 -05:00
Cameron Gutman 79532f6f14 Version 12.0 2023-10-13 23:02:46 -05:00
Cameron Gutman b400ba385e Update moonlight-common-c 2023-10-12 00:33:55 -05:00
Cameron Gutman 9915007f30 Check for a null UsbManager object
Apparently this can happen on some (broken?) devices
2023-10-12 00:22:28 -05:00
Cameron Gutman 0168a55596 Propagate the controller number to the standalone DS4 touchpad device 2023-10-07 23:26:26 -05:00
Cameron Gutman 229eff49fb Consume unhandled gamepad mouse events to prevent duplicate mouse actions 2023-10-07 23:04:36 -05:00
Cameron Gutman 0e3b472f78 Fix DS4 clickpad button on devices that expose the touchpad as a mouse 2023-10-07 22:58:07 -05:00
Cameron Gutman 5f29b30d34 Fix DS4 clickpad button on Nvidia Shield (again) 2023-10-07 22:53:19 -05:00
Cameron Gutman 9480363362 Update fastlane metadata with new features 2023-10-07 21:07:53 -05:00
Cameron Gutman 5dd80edde4 Wait 1 second after input device reconfiguration to enable motion sensors 2023-10-07 21:07:02 -05:00
Cameron Gutman 2243cf2017 Rewrite NsdManagerDiscoveryAgent lifecycle to avoid listener reuse 2023-10-07 20:42:13 -05:00
Cameron Gutman d7791c8543 Adjust default bitrate logic to match new Qt logic 2023-10-07 19:54:02 -05:00
Cameron Gutman 30822c1ba5 Only check for motion sensors on Sony or Nintendo gamepads on Android 12
This works around a bug in Android 12 that leads to random crashes when input devices change.
2023-10-07 19:07:15 -05:00
Cameron Gutman d250f4dc60 Move battery updates to a background HandlerThread
They can cause long Binder transactions that lead to ANRs.
2023-10-07 00:49:03 -05:00
Cameron Gutman bc27492206 Split ControllerHandler teardown into stop() and destroy() functions 2023-10-07 00:35:36 -05:00
Cameron Gutman 2b63203a5b Update moonlight-common-c 2023-10-06 23:12:21 -05:00
Cameron Gutman dc9a26f57b Update to AGP 8.1.2 2023-10-06 23:11:41 -05:00
Jorys Paulin 6f2d7464ba Translated using Weblate (French)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-09-30 19:01:03 +02:00
Jen Kung-chih 6996c101b4 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-09-24 23:00:42 +02:00
Cameron Gutman 99dc773c7a Merge remote-tracking branch 'origin/weblate' 2023-09-23 12:59:56 -04:00
Cameron Gutman 6ec3f9455a Update moonlight-common-c with frame corruption fixes 2023-09-23 12:58:57 -04:00
Cameron Gutman 6589a568e2 Add freeform window metadata for ChromeOS 2023-09-23 02:48:53 -04:00
Cameron Gutman 55da48e28c Remove USB options from settings page if USB host mode is not supported 2023-09-23 02:21:53 -04:00
Cameron Gutman 081cca48fb Implement cursor visibility and quit key shortcuts
Fixes #1255
2023-09-23 02:20:26 -04:00
137615 6b6a93725c Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-09-20 12:01:18 +00:00
137615 c280a52d33 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2023-09-20 12:01:17 +00:00
sanhoe b659439f0b Translated using Weblate (Korean)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2023-09-20 12:01:16 +00:00
gallegonovato 6453b3c45c Translated using Weblate (Spanish)
Currently translated at 100.0% (242 of 242 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2023-09-20 12:01:15 +00:00
Cameron Gutman 978a879c43 Batch async control stream callbacks 2023-09-18 23:25:59 -05:00
Cameron Gutman 833ef3630b Invoke control stream callbacks on a separate thread 2023-09-17 15:00:21 -05:00
Cameron Gutman 024b8c93bc Merge remote-tracking branch 'origin/weblate' 2023-09-16 23:12:05 -05:00
Cameron Gutman d32c4f86a7 Fix unguarded use of Lollipop API 2023-09-16 22:53:13 -05:00
Cameron Gutman cafc4450b2 Override controller type when motion sensor emulation is enabled
Without this, the host will still select an Xbox controller even if it can't support motion sensors.
2023-09-16 22:48:38 -05:00
Cameron Gutman 7d69b53958 Tweak preference strings 2023-09-16 22:27:01 -05:00
Cameron Gutman 4d3e883e49 Correct sensors for device orientation 2023-09-16 22:26:11 -05:00
Cameron Gutman 8f9a687872 Add device sensor fallback option
Correction for device orientation is not implemented yet
2023-09-16 20:25:54 -05:00
Cameron Gutman 08d509d831 Use the device vibrator for devices with built-in gamepads 2023-09-16 19:14:22 -05:00
Cameron Gutman b06dec8449 Fix detection of G Cloud gamepad as an internal controller 2023-09-16 19:09:40 -05:00
Cameron Gutman 28c93b934b Update moonlight-common-c 2023-09-16 16:03:52 -05:00
Cameron Gutman 394a57a26d Disable native touch passthrough for now 2023-09-16 15:59:07 -05:00
bittin1ddc447d824349b2 3856b57a6f Translated using Weblate (Swedish)
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/sv/
2023-09-08 11:59:27 +02:00
Zan 1456 9a3a076890 Translated using Weblate (Hungarian)
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/hu/
2023-09-08 11:59:26 +02:00
Cameron Gutman 314dfcddcf Link to Sunshine 2023-09-03 18:05:00 -05:00
Cameron Gutman 1a85bda997 Update to AGP 8.1.1 2023-09-02 23:32:30 -05:00
Cameron Gutman e8b30d5a88 Set KEY_PRIORITY during low latency option probing 2023-09-02 23:32:16 -05:00
Cameron Gutman 96bd1a7799 Update moonlight-common-c 2023-09-02 22:46:59 -05:00
sanhoe cb0a1f13bc Translated using Weblate (Korean)
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2023-08-08 04:53:26 +02:00
Cameron Gutman e92fdeef47 Fix RGB LED capability flag on Android 12 and 13 2023-08-03 23:02:11 -05:00
Cameron Gutman 62bae62386 Fix end of stream toast for AV1 2023-08-03 21:10:06 -05:00
Cameron Gutman 2636d79b86 Fix handling of ACTION_CANCEL for multi-pointer gestures 2023-08-03 02:29:55 -05:00
Cameron Gutman c9c1ef91fd Fix mishandling ACTION_MOVE events for native pen/touch events 2023-07-27 23:15:26 -05:00
weng weng ce7bba3e09 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2023-07-26 13:04:56 +02:00
S. MohammadMahdi Zamanian bfd53f39bd Added translation using Weblate (Persian) 2023-07-26 09:23:11 +02:00
Cameron Gutman 554fee037c Fix race condition when stopDiscovery() is called during onServiceFound()/onServiceLost() 2023-07-25 18:46:31 -05:00
Cameron Gutman 67b2853ef0 Add contact area and orientation for pen/touch events 2023-07-22 17:18:57 -05:00
Cameron Gutman 0e29e13d03 Use private API to detect clickpads on Android O and earlier 2023-07-22 14:34:27 -05:00
Jen Kung-chih 35f2a238e9 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-07-19 18:05:46 +02:00
Jorys Paulin fcb34ab6ee Translated using Weblate (French)
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-07-13 11:51:59 +02:00
Cameron Gutman 3fbf682785 Pass gamepad touch input natively by default
Most devices will have a touchscreen which already provides mouse input
and Steam Input is can provide gamepad touchpad mouse control if desired.
2023-07-12 01:21:35 -05:00
Cameron Gutman 16086a6d3f Send the touchpad button on the gamepad even when using the touchpad for mouse control 2023-07-12 01:16:33 -05:00
Cameron Gutman 18b6aae381 Disable gamepad sensors while in PiP mode 2023-07-12 01:07:14 -05:00
Cameron Gutman 642c353164 Fix handling of onInputDeviceChanged when using sensors and lights
DS4 triggers this path when we release our pointer capture on activity pause
2023-07-12 00:32:28 -05:00
Cameron Gutman 42f64e5e88 Rename videoformat_hevcauto translations to videoformat_auto 2023-07-11 20:18:31 -05:00
Cameron Gutman 6af748b2cc Remove videoformat_hevcauto translations that still reference HEVC 2023-07-11 20:12:10 -05:00
Cameron Gutman 4fe97b69c7 Fix invalid format string 2023-07-11 20:10:52 -05:00
Cameron Gutman 04d46272dd Remove now unused videoformat_hevcnever string 2023-07-11 20:10:38 -05:00
Cameron Gutman 1c0290dc7a Merge remote-tracking branch 'origin/weblate' 2023-07-11 20:05:21 -05:00
Cameron Gutman 38588402e3 Use NsdManager for mDNS discovery on Android 14 2023-07-11 19:58:50 -05:00
Luna Jernberg dfe3b8888d Translated using Weblate (Swedish)
Currently translated at 99.5% (238 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/sv/
2023-07-11 17:49:16 +02:00
ThomasTech e8f4022f1e Translated using Weblate (French)
Currently translated at 95.3% (228 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-07-11 17:49:15 +02:00
gallegonovato e37bb32c82 Translated using Weblate (Spanish)
Currently translated at 100.0% (239 of 239 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2023-07-11 17:49:15 +02:00
Cameron Gutman 1f72c82acb Consolidate AV1 and HEVC options into a single preference 2023-07-09 15:04:26 -05:00
Cameron Gutman e6876926a4 Add options to control gamepad touchpad and motion and reorganize input settings 2023-07-09 14:46:46 -05:00
Cameron Gutman 2b8a43ab13 Update locale selections to add Hebrew, Swedish, and Indonesian languages 2023-07-09 14:00:14 -05:00
Cameron Gutman 8737466368 Merge branch 'weblate' of github.com:moonlight-stream/moonlight-android 2023-07-09 13:47:07 -05:00
Cameron Gutman 83916fa43e Map the Menu key for keyboards 2023-07-08 23:21:19 -05:00
Cameron Gutman 1fe5a12a45 Update moonlight-common-c 2023-07-08 23:19:33 -05:00
Cameron Gutman fa7f3115ed Add AV1 autoselection by performance point criteria 2023-07-07 23:09:05 -05:00
Cameron Gutman 4dc6143440 Override the stock DS4 touchpad button mapping for Shield devices
Nvidia's stock mapping treats the clickpad as a second select button.
2023-07-05 23:00:54 -05:00
Cameron Gutman f1503aa56c Implement battery reporting for Shield controllers 2023-07-05 18:57:01 -05:00
Cameron Gutman 67f344b755 Move serverCodecModeSupport into SERVER_INFORMATION struct 2023-07-02 23:56:34 -05:00
Cameron Gutman f1bcc217a9 Update to new HDR support option in moonlight-common-c 2023-07-02 23:48:19 -05:00
Cameron Gutman 458460515d Plumb AV1 preference and rework HEVC preference to match 2023-07-02 23:48:13 -05:00
Cameron Gutman 3a78095574 Initial implementation of AV1 2023-07-02 22:49:42 -05:00
Cameron Gutman d6bbfa1af1 Fix unmapped paddle and share button presses 2023-07-02 20:32:57 -05:00
Cameron Gutman 4e1b778f31 Import some SDL code and use it for controller classification
Imported as of 4aee17b039981f2bb79892f3d3e3e17bd6b66530
2023-07-02 20:20:55 -05:00
Cameron Gutman 5f4496036c Don't use GameManager loading flag
This is meant to affect CPU throttling, which we don't need.
2023-07-02 19:08:58 -05:00
Cameron Gutman d4079940b4 Implement controller LED and battery state extensions 2023-07-02 19:03:31 -05:00
Cameron Gutman 803ad116fb Pull in latest moonlight-common-c change 2023-06-28 17:28:41 -05:00
Cameron Gutman 27701eda49 Handle paddle buttons on Xbox Elite controllers 2023-06-28 17:28:25 -05:00
Cameron Gutman 71c831b02d Handle 2-direction d-pad key events 2023-06-28 17:22:05 -05:00
Cameron Gutman 0d72a0e009 Implement latest pen/touch protocol updates 2023-06-27 22:21:39 -05:00
Cameron Gutman 69a4502f90 Fix pen/touch coordinates when reported from the background touch view 2023-06-25 00:50:17 -05:00
Cameron Gutman daaa7f4e63 Fix pen rotation values 2023-06-25 00:26:32 -05:00
Cameron Gutman d1579e9b0d Support PS4/PS5 touchpad click on older kernels 2023-06-24 23:45:31 -05:00
Cameron Gutman 5890fff240 Add pen and touch events 2023-06-24 23:13:59 -05:00
Cameron Gutman d6f6307050 Fix units of gyro motion and deduplicate sensor events 2023-06-24 23:12:28 -05:00
Cameron Gutman 6bf9c31860 Pull in updated moonlight-common-c pen/touch APIs 2023-06-24 21:29:44 -05:00
Cameron Gutman a2e628f3f8 Add controller arrival metadata support 2023-06-24 20:23:43 -05:00
Cameron Gutman 8f5416ff31 Target Android 14 2023-06-24 19:38:34 -05:00
Cameron Gutman db86f18133 Use new per-activity predictive back support on Android 14
We can't enable it on the Game activity, but we an use it for all other activities.
2023-06-24 19:38:07 -05:00
Cameron Gutman 419e4e656e Use an explicit intent for requesting USB permission 2023-06-24 19:37:12 -05:00
Cameron Gutman eed4327d26 Add controller touchpad support 2023-06-24 19:09:10 -05:00
Cameron Gutman 5c6eaf2602 Add controller gyro and accelerometer support 2023-06-24 19:06:58 -05:00
Cameron Gutman 71169ed740 Add trigger rumble support 2023-06-24 17:59:10 -05:00
Cameron Gutman dca8d93aa8 Add Share button mapping for Xbox Series X controller 2023-06-24 16:16:02 -05:00
Cameron Gutman 6cb152f602 Increase gamepad limit to 16 for Sunshine hosts 2023-06-24 16:15:00 -05:00
Cameron Gutman ddefda3afa Plumb new Sunshine protocol extensions 2023-06-24 15:19:50 -05:00
Cameron Gutman 7f15f45beb Only display the host processing latency if it was present 2023-06-24 15:00:54 -05:00
Timothy Lusk 46f887efec Add host processing latency to performance stats overlay 2023-06-24 14:19:05 -05:00
semjon00 90afecd766 Add option to stream at device native FPS
Useful for phones with overclocked refresh rate
2023-06-24 14:16:49 -05:00
Cameron Gutman 388343c3ee Update to AGP 8.0.2 2023-06-24 14:15:38 -05:00
ns6089 c8df37e89e Compensate for choreographer vsync offset 2023-06-24 13:52:20 -05:00
Clxff H3r4ld0 cc85d5c343 Translated using Weblate (Indonesian)
Currently translated at 79.5% (183 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/id/
2023-05-27 17:50:51 +02:00
Jorys Paulin f8437cdb8f Translated using Weblate (French)
Currently translated at 100.0% (230 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-05-21 16:51:09 +02:00
shakedex c99a210905 Translated using Weblate (Hebrew)
Currently translated at 57.3% (132 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/he/
2023-04-30 10:50:54 +02:00
Yutaro Urata e33673c9e9 Translated using Weblate (Japanese)
Currently translated at 51.7% (119 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ja/
2023-04-30 10:50:53 +02:00
shakedex 79283e93cb Translated using Weblate (Hebrew)
Currently translated at 50.4% (116 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/he/
2023-04-27 01:51:19 +02:00
shakedex a60e85a3a4 Added translation using Weblate (Hebrew) 2023-04-25 23:56:54 +02:00
Simon Nilsson 80910ed38d Translated using Weblate (Swedish)
Currently translated at 100.0% (230 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/sv/
2023-03-31 22:09:41 +02:00
Simon Nilsson 825a338474 Added translation using Weblate (Swedish) 2023-03-29 16:56:54 +02:00
Cameron Gutman 19b6e94824 Add horizontal scrolling in mouse emulation mode 2023-03-04 12:31:31 -06:00
Cameron Gutman 0b581011c5 Version 11.0 2023-02-28 21:31:32 -06:00
Cliff Heraldo 6b7669bb75 Translated using Weblate (Indonesian)
Currently translated at 32.1% (74 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/id/
2023-02-27 10:37:51 +01:00
Cameron Gutman 67bcc56c6d Remove strict codec recovery timeout
Codec recovery depends on incoming frames, so it cannot be reliably time-constrained
2023-02-26 13:26:01 -06:00
Cameron Gutman 7d8cfa3c6a Remove URL filtering to fix wiki links to outside pages 2023-02-25 20:37:49 -06:00
Cameron Gutman f659af29da Fix mDNS detection of hosts with the same IP address
This is the case for PCs running GFE and Sunshine side-by-side.
2023-02-25 20:29:51 -06:00
Cameron Gutman 94b202f7b6 Update moonlight-common-c 2023-02-25 13:13:05 -06:00
Cameron Gutman ca86fdafab Merge remote-tracking branch 'origin/weblate' 2023-02-25 13:01:55 -06:00
Cameron Gutman 370dbb1a10 Send non-ASCII soft keys as UTF-8 2023-02-25 12:49:55 -06:00
luten145 f77543cd9b Added clipboard support
You can paste Android's clipboard contents.
2023-02-25 12:30:58 -06:00
Steffen_LT 7104e0d725 Relative mouse fix on Chromebooks with touchscreens 2023-02-25 12:28:49 -06:00
weng weng 230a67cac0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (230 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2023-02-24 08:36:54 +01:00
Jen Kung-chih a695f38974 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (230 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-02-23 07:38:22 +01:00
Cameron Gutman 151c09f098 Merge remote-tracking branch 'origin/weblate' 2023-02-21 22:44:00 -06:00
gallegonovato 8200f5690d Translated using Weblate (Spanish)
Currently translated at 100.0% (230 of 230 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2023-02-22 05:43:42 +01:00
Cameron Gutman 77a8cf2704 Remove the touchscreen trackpad option hiding entirely
Fixes #1184
2023-02-21 22:42:35 -06:00
Cameron Gutman fe424961e1 Update Fastlane metadata 2023-02-21 22:37:24 -06:00
Cameron Gutman b668cb78ff Update to AGP 7.4.1 2023-02-21 22:36:04 -06:00
bladeoner 48278419b0 Update Gradle to version 7.6 2023-02-21 22:29:32 -06:00
Cameron Gutman 632da03667 Merge remote-tracking branch 'origin/weblate' 2023-02-21 02:15:03 -06:00
Cameron Gutman d36b73fc1b Fix crash with IPv4-mapped IPv6 addresses 2023-02-20 23:31:53 -06:00
Cameron Gutman 292ed35555 Update moonlight-common-c 2023-02-20 23:24:32 -06:00
Cameron Gutman 02d0ad496f Fix error message being displayed even after successful WoL 2023-02-20 23:01:46 -06:00
Cameron Gutman eb2fc7af40 Add GameStream EOL notice for GFE PCs 2023-02-20 23:01:08 -06:00
Cameron Gutman 6550deedbb Fix handling of missing addresses 2023-02-20 22:35:27 -06:00
Cameron Gutman 80acd9b9eb Modernize HTTPS launch/resume for Sunshine 2023-02-20 22:04:41 -06:00
Cameron Gutman b961636f02 Plumb HDR metadata into MediaCodec 2023-02-20 21:42:45 -06:00
Cameron Gutman f4df0714b5 Implement horizontal scrolling with Sunshine 2023-02-20 19:56:01 -06:00
Cameron Gutman 91dd7b7049 Plumb non-normalized key flag extension for Sunshine 2023-02-20 19:52:52 -06:00
Karim Mreisi 121bef7d2d fix: use address and port for details hash 2023-02-20 13:32:55 -06:00
Karim Mreisi 3a9eabf50b fix: support host names with _
Use a JSON to properly encapsule different computer addresses and their
port, instead of using "_" as separator.

Fix usage of '_' in computer host names / domain names.
2023-02-20 13:32:55 -06:00
bladeoner c8198b4091 Update bug and feature_request forms 2023-02-20 13:25:03 -06:00
Cameron Gutman e4538e4a51 Only remove touchscreen-trackpad option on TV devices
Some VR headset devices can make use of this without a proper touchscreen
2023-02-20 13:22:01 -06:00
Cameron Gutman b47f3ef397 Remove input batching to replace with common-c implementation 2023-02-20 13:19:59 -06:00
Jen Kung-chih 6e096c0ac3 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (229 of 229 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-02-14 07:37:50 +01:00
weng weng ee3b4686bf Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (229 of 229 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2023-02-14 07:37:49 +01:00
gallegonovato 759b77eafe Translated using Weblate (Spanish)
Currently translated at 100.0% (229 of 229 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2023-02-12 22:38:54 +01:00
Cameron Gutman de15ec666f Merge remote-tracking branch 'origin/weblate' 2023-02-11 14:27:49 -06:00
Cameron Gutman 3de86f15af Disable HEVC RFI on platforms with older Tegra BSPs
Fixes #1177
2023-02-11 14:26:54 -06:00
Cameron Gutman 1b9dff719c Remove most NVIDIA-specific references in code 2023-02-11 14:25:54 -06:00
Jorys Paulin abcf4e3d4a Translated using Weblate (French)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2023-02-09 11:38:54 +01:00
Jen Kung-chih 9823abe686 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2023-01-24 09:51:09 +01:00
LUTEN 723e08f69b Translated using Weblate (Korean)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2023-01-12 08:49:04 +01:00
ssantos daf0a0891e Translated using Weblate (Portuguese)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt/
2023-01-10 19:51:36 +01:00
Jen Kung-chih 49dc68f77f Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-12-30 06:51:13 +01:00
gallegonovato f81a1c36cc Translated using Weblate (Spanish)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2022-12-24 15:51:06 +01:00
Dan 9a11a771dd Translated using Weblate (Ukrainian)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2022-12-21 01:50:21 +01:00
Translator-3000 b56a4b8b49 Translated using Weblate (Italian)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-12-19 18:49:33 +01:00
Cameron Gutman 1aa963992b Improve Xbox 360W controller numbering 2022-12-16 00:35:19 -06:00
Cameron Gutman 1b601324d0 Remove automatic detection logic for CONFIG_JOYSTICK_XPAD_LEDS=y
It doesn't work due to Android app sandboxing
2022-12-16 00:20:06 -06:00
Cameron Gutman 1aea723ef0 Rework Xbox360W support to handle multiple controllers 2022-12-15 23:33:48 -06:00
Cameron Gutman 1e828a10b9 Request our desired refresh rate rather than the actual frame rate
This ensures we'll get the highest compatible refresh rate rather than the lowest.
2022-12-15 22:53:25 -06:00
Cameron Gutman 970423f873 Use setFrameRate() instead of preferredDisplayModeId if the modes differ only by refresh rate
This seems to avoid a bug on the Chromecast 4K where it can decide to switch to 4K24 instead of 4K60

Fixes #1151
2022-12-14 23:05:22 -06:00
Cameron Gutman 2d7493fd1e Improve check for kernel support for Xbox360W LED configuration 2022-12-14 21:49:42 -06:00
sivan-koren fa7eb1c4b1 Set Lights on XBOX360 Wireless Controllers for New Android/Google TVs Through 2023 - Fixes: #1061 (#1157) 2022-12-14 21:29:41 -06:00
SpeedPartner 4916af3697 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-12-08 14:47:25 +01:00
Eric 8484bf1cb9 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-12-08 14:47:25 +01:00
SpeedPartner 005afb3c73 Translated using Weblate (Chinese (Simplified))
Currently translated at 98.6% (225 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-12-07 14:04:03 +01:00
Jen Kung-chih 84b0d004b9 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-12-07 11:47:26 +01:00
Cameron Gutman aa41bf8d97 Version 10.11 2022-12-04 13:54:37 -06:00
Cameron Gutman fba9a125bf Merge remote-tracking branch 'origin/weblate' 2022-12-01 18:40:24 -06:00
jonathanmasseurca 27312bd146 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt_BR/
2022-12-02 01:39:46 +01:00
Jen Kung-chih 8f0c267ab8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-12-02 01:39:46 +01:00
Zaraza225 a15d6a6b42 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2022-12-02 01:39:45 +01:00
jonathanmasseurca 8f9061b250 Translated using Weblate (French)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-12-02 01:39:45 +01:00
Cameron Gutman ec57499e08 Handle escaping and unescaping IPv6 addresses in AddressTuple 2022-12-01 18:26:40 -06:00
Cameron Gutman 381598c5b6 Fix handling of IPv6 literals when adding a PC
Fixes #1152
2022-12-01 18:26:40 -06:00
Cameron Gutman 452d020da5 Merge remote-tracking branch 'origin/weblate' 2022-11-30 21:07:34 -06:00
Eric b5f875c2e5 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.1% (226 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-12-01 04:06:55 +01:00
Brandon Goldberg a31daeda96 Translated using Weblate (Spanish)
Currently translated at 100.0% (228 of 228 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2022-12-01 04:06:55 +01:00
Cameron Gutman 437f52f53a Tweak full range option text 2022-11-30 00:16:05 -06:00
Cameron Gutman 33f0f7ecf0 Use Ctrl+Alt+Shift+Z as the unbind toggle to match other Moonlight clients 2022-11-29 23:28:13 -06:00
Cameron Gutman 6777e79e70 Fix inverted mouse capture bug 2022-11-29 23:25:39 -06:00
Cameron Gutman 16d1e6181b Update moonlight-common-c 2022-11-29 19:16:33 -06:00
Cameron Gutman a6c8db6c2c Introduce full range color option 2022-11-29 19:10:19 -06:00
Cameron Gutman 24aa0fecbe Revise HEVC option text 2022-11-29 19:05:30 -06:00
Cameron Gutman 1a776b1990 Add Czech translation to language list
Fixes #1147
2022-11-29 18:42:28 -06:00
Cameron Gutman 27df265c81 Merge remote-tracking branch 'origin/weblate' 2022-11-29 18:37:27 -06:00
Zaraza225 84c0372719 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2022-11-23 21:47:27 +01:00
Cameron Gutman 3879e57c4c Track network changes to invalidate PC online state appropriately 2022-11-21 23:15:19 -06:00
Cameron Gutman dcc3dcdaba Only match ports if the PC is online 2022-11-21 23:00:51 -06:00
Loïc Hesling d166635c7b Translated using Weblate (French)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-11-17 12:47:40 +01:00
Cameron Gutman 33d484b7d1 Remove specific RFI opt-in for Sabrina since it's supported out of the box in Android 12 2022-11-13 19:10:35 -06:00
luten145 26bff28e4d Added MetaKey(WindowKey) Packet
Allows you to use Windows key combinations.

ex) Win+Tab , Win+D
2022-11-13 17:15:22 -06:00
Cameron Gutman 56eddff8d6 Default to Rec 709 on modern devices
Fixes #1138
Closes #1143
2022-11-13 13:47:41 -06:00
Cameron Gutman 37b9133eb6 Correct media performance class check
Media performance class is 12+ even though it has values for 11+
2022-11-13 13:27:43 -06:00
Cameron Gutman 4a64967b1f Ungrab meta key capture when toggling input capture 2022-11-13 13:19:23 -06:00
Translator-3000 23152b1264 Translated using Weblate (Italian)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-11-13 13:50:24 +01:00
Cameron Gutman 00415aac79 Version 10.10 2022-11-11 12:21:25 -06:00
Cameron Gutman cbe602655c Pass active HTTPS port if the HTTP port matches the active address 2022-11-09 20:53:06 -06:00
Cameron Gutman 236d8b7030 Extend timeouts for the PC's active address 2022-11-09 20:31:58 -06:00
Cameron Gutman 392e3c7fe3 Increase connection timeouts when the PC is presumed to be online 2022-11-09 20:22:07 -06:00
Cameron Gutman 57f55e6856 Use the current HTTP port as the default if ExternalPort doesn't exist 2022-11-09 19:56:46 -06:00
Cameron Gutman de54b27013 Plumb HTTPS port into the Game activity to avoid having to look it up again 2022-11-09 19:55:42 -06:00
Dominik Chrástecký c11338039f Translated using Weblate (Czech)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/cs/
2022-11-09 16:47:44 +01:00
Jen Kung-chih e712669d32 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-11-09 16:47:44 +01:00
Brandon Goldberg 3768ae33b7 Translated using Weblate (Spanish)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2022-11-09 16:47:43 +01:00
Cameron Gutman fdc39f0041 Merge remote-tracking branch 'origin/weblate' 2022-11-06 19:04:43 -06:00
Cameron Gutman 7f3b0b03a6 Add C2 equivalents for OMX decoders for futureproofing 2022-11-06 18:17:48 -06:00
Cameron Gutman 4a6a39dd4c Disable HEVC RFI on Fire TV 3 due to decoder hangs 2022-11-06 18:13:19 -06:00
Cameron Gutman 6a8486a076 Fix propagation of external port after guessing 2022-11-06 18:06:18 -06:00
Cameron Gutman 08a8a3043f Update moonlight-common-c with improved high quality audio 2022-11-06 17:37:13 -06:00
Cameron Gutman 7af290b6e1 Implement support for non-default ports with Sunshine
Fixes #1115
2022-11-06 17:36:46 -06:00
Cameron Gutman a896f9a28f Use the HTTPS port specified in the serverinfo response 2022-11-06 15:44:37 -06:00
Cameron Gutman ea003483c4 Plumb port numbers from mDNS discovery 2022-11-06 14:41:02 -06:00
Cameron Gutman 5b73317e30 Fix error handling if the server address cannot be resolved 2022-11-06 14:34:31 -06:00
Howard Wu 1af64b9985 Set forceDarkAllowed to false
Some system like MIUI forced inverse color (which cannot be turned off for games with night mode on) causes games without covers to become white, which like the game title color causes unreadability, this change prevents that problem.

ref https://stackoverflow.com/questions/63777438/how-to-avoid-forced-dark-theme-in-my-app-when-devices-can-force-it-at-app-level
2022-11-04 22:01:08 -05:00
Cameron Gutman af784cf79b Fix typo in boolean logic 2022-11-04 01:22:19 -05:00
Cameron Gutman a2b2131beb Add support for codec flush recovery 2022-11-04 01:20:00 -05:00
Cameron Gutman 2433ce8d24 Fix crashes on Fire OS 8 2022-11-03 23:17:15 -05:00
Cameron Gutman 8b861750e5 Update moonlight-common-c with improved video and audio packet loss handling 2022-11-03 22:20:39 -05:00
Cameron Gutman 99fcd3c669 Improve LAN/WAN detection for IPv6 and cellular connections 2022-11-03 22:19:48 -05:00
Cameron Gutman 0ddd8df272 Use HEVC by default if the decoder supports FEATURE_LowLatency or the media performance class is 12+ 2022-10-31 01:05:01 -05:00
TacoTheDank a96e508ffb Use try-with-resources 2022-10-31 00:33:09 -05:00
이정희 1f21d12d2b Translated using Weblate (Korean)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2022-10-30 15:07:04 +01:00
sanhoe dd782ac4b2 Translated using Weblate (Korean)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2022-10-29 06:12:57 +02:00
Cameron Gutman 51594e00b8 Revert "Use Rec 2020 colorspace for WCG support even if HDR is off on the host"
Rec 2020 conversion causes colors to be blown out in SDR

This reverts commit 6c85f5f8c3.
2022-10-13 01:18:26 -05:00
Cameron Gutman 6c85f5f8c3 Use Rec 2020 colorspace for WCG support even if HDR is off on the host 2022-10-13 00:52:45 -05:00
Cameron Gutman d0432de981 Plumb colorspace and color range into MediaCodecDecoderRenderer 2022-10-13 00:51:15 -05:00
Cameron Gutman 2cbc94e51d Allow a pairing attempt even if the PC is busy
Pairing while busy doesn't work with GFE but works with Sunshine
2022-10-12 22:15:41 -05:00
Cameron Gutman 3ea2aa1f74 Enable HEVC RFI on Fire TV and Chromecast devices 2022-10-12 21:50:40 -05:00
Cameron Gutman 1076b516d6 Enable HEVC RFI for decoders that support low latency options 2022-10-12 21:25:48 -05:00
bruh 4e87d25851 Translated using Weblate (Vietnamese)
Currently translated at 93.8% (212 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/vi/
2022-10-12 18:26:37 +02:00
LedyBacer dadd3c7292 Translated using Weblate (Russian)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2022-10-12 18:26:37 +02:00
Jen Kung-chih 9f8abe35f9 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-10-10 19:59:49 +02:00
Eric 0f869a7414 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-10-10 19:59:49 +02:00
Cameron Gutman aede16c85c Version 10.9 2022-10-07 22:02:56 -05:00
Cameron Gutman 61a82e6394 Merge remote-tracking branch 'origin/weblate' 2022-10-07 21:55:19 -05:00
Sargon-Isa 5a92925d6a Translated using Weblate (German)
Currently translated at 100.0% (226 of 226 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2022-10-08 04:54:57 +02:00
Cameron Gutman fe697c918f Update moonlight-common-c with speculative RFI support 2022-10-07 21:54:00 -05:00
Cameron Gutman bc57a285ce Fix unescaped character 2022-10-04 20:03:10 -05:00
Cameron Gutman 85d8943b64 Merge remote-tracking branch 'origin/weblate' 2022-10-04 19:56:52 -05:00
Cameron Gutman aa6c32968b Add a special termination message for ML_ERROR_FRAME_CONVERSION 2022-10-04 19:51:49 -05:00
Cameron Gutman ad1808fb4e Update moonlight-common-c with further fixes for GFE 3.26 2022-10-04 19:50:49 -05:00
Kamil Szyc 576610e4c3 Translated using Weblate (Polish)
Currently translated at 1.7% (4 of 225 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pl/
2022-10-04 12:24:06 +02:00
Martin Dimitrov ace2266f14 Translated using Weblate (Bulgarian)
Currently translated at 59.5% (134 of 225 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/bg/
2022-10-04 12:24:06 +02:00
Alexandru-Marian Buza 41cedfa6ec Fix requestMetaKeyEvent for Samsung devices with android 10+ (#1134)
Co-authored-by: Alexandru Buza <abuza@iqnox.com>
2022-10-03 22:50:04 -05:00
Cameron Gutman d46fab33b3 Enable HEVC RFI for Exynos decoders 2022-10-03 22:23:59 -05:00
Cameron Gutman 585dc45595 Enable RFI for HEVC on Qualcomm and Nvidia decoders 2022-10-03 21:33:05 -05:00
Cameron Gutman c3c9354a00 Update moonlight-common-c to support reliable RFI for HEVC 2022-10-03 21:32:11 -05:00
Cameron Gutman bdc8d08e65 Switch back to AGP 7.2.2
AGP 7.3.0 produces invalid bytecode for ControllerHandler, causing dex validation errors on Android Jelly Bean and KitKat

Fixes #1132
2022-10-03 21:30:01 -05:00
Cameron Gutman 9c792d3272 Adjust RendererException text to attempt to parse correctly in Google Play App Vitals 2022-10-03 21:28:37 -05:00
Cameron Gutman 23bc4daf9f Refactor input event handling in the Game activity 2022-10-03 21:25:43 -05:00
Kamil Szyc fd85ca2004 Added translation using Weblate (Polish) 2022-10-03 11:42:50 +02:00
Martin Dimitrov aadf88add1 Added translation using Weblate (Bulgarian) 2022-10-02 19:24:17 +02:00
sanhoe f14ce61ee3 Translated using Weblate (Korean)
Currently translated at 100.0% (225 of 225 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2022-09-29 12:16:23 +02:00
Cameron Gutman 539daf5789 Don't adjust maxBytesPerPicDenom and maxBitsPerMbDenom on newer devices 2022-09-23 21:27:27 -05:00
111 changed files with 8326 additions and 1952 deletions
-48
View File
@@ -1,48 +0,0 @@
---
name: Bug report
about: Follow the troubleshooting guide before reporting a bug
---
**READ ME FIRST!**
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
**Describe the bug**
A clear and concise description of what the bug is.
**Steps to reproduce**
Any special steps that are required for the bug to appear.
**Screenshots**
If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
**Affected games**
List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
**Other Moonlight clients**
- Does the issue occur when using Moonlight on PC or iOS?
**Moonlight settings (please complete the following information)**
- Have any settings been adjusted from defaults?
- If so, which settings have been changed?
- Does the problem still occur after reverting settings back to default?
**Gamepad-related issues (please complete if problem is gamepad-related)**
- Do you have any gamepads connected to your host PC directly?
- If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
- Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
- Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
**Device details (please complete the following information)**
- Android version: [e.g. Android 10]
- Device model: [e.g. Samsung Galaxy S21]
**Server PC details (please complete the following information)**
- OS: [e.g. Windows 10 1809]
- GeForce Experience version: [e.g. 3.16.0.140]
- Nvidia GPU driver: [e.g. 417.35]
- Antivirus and firewall software: [e.g. Windows Defender and Windows Firewall]
**Additional context**
Anything else you think may be relevant to the issue or special about your specific setup.
+176
View File
@@ -0,0 +1,176 @@
name: Bug report
description: Follow the troubleshooting guide before reporting a bug
title: "[Issue]: "
labels: bug
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this bug form!
**READ ME FIRST!**
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
- type: textarea
id: describe-bug
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: steps-reproduce
attributes:
label: Steps to reproduce
description: Any special steps that are required for the bug to appear.
validations:
required: true
- type: textarea
id: affected-games
attributes:
label: Affected games
description: List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
validations:
required: true
- type: dropdown
id: other-clients
attributes:
label: Other Moonlight clients
description: Does the issue occur when using Moonlight on PC or iOS?
options:
- "PC"
- "iOS"
validations:
required: true
- type: dropdown
id: settings-adjusted
attributes:
label: Moonlight adjusted settings
description: Have any settings been adjusted from defaults?
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
id: settings-adjusted-settings
attributes:
label: Moonlight adjusted settings (please complete the following information)
description: If the settings have been adjusted, which settings have been changed?
validations:
required: true
- type: dropdown
id: settings-default
attributes:
label: Moonlight default settings
description: Does the problem still occur after reverting settings back to default?
options:
- "Yes"
- "No"
validations:
required: true
- type: dropdown
id: gamepad-connected
attributes:
label: Gamepad-related connection issue
description: Do you have any gamepads connected to your host PC directly?
options:
- "Yes"
- "No"
validations:
required: true
- type: dropdown
id: gamepad-on-screen
attributes:
label: Gamepad-related input issue
description: If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
options:
- "Yes"
- "No"
validations:
required: true
- type: dropdown
id: gamepad-test
attributes:
label: Gamepad-related streaming issue
description: |
Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
options:
- "Yes"
- "No"
validations:
required: true
- type: input
id: android
attributes:
label: Android version
description: What is the Android version?
placeholder: e.g. Android 10
validations:
required: true
- type: input
id: device
attributes:
label: Device model
description: What is the device model?
placeholder: e.g. Samsung Galaxy S21
validations:
required: true
- type: input
id: server-os
attributes:
label: Server PC OS version
description: What is the PC OS version?
placeholder: e.g. Windows 10 1809
validations:
required: true
- type: input
id: server-geforce
attributes:
label: Server PC GeForce Experience version
description: What is the GeForce Experience version?
placeholder: e.g. 3.16.0.140
validations:
required: true
- type: input
id: server-driver
attributes:
label: Server PC Nvidia GPU driver version
description: What is the Nvidia GPU driver version?
placeholder: e.g. 417.35
validations:
required: true
- type: input
id: server-antivirus
attributes:
label: Server PC antivirus and firewall software
description: Which antivirus and firewall software are installed on the Server PC?
placeholder: e.g. Windows Defender and Windows Firewall
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: |
Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: Shell
validations:
required: false
- type: textarea
id: additional
attributes:
label: Additional context
description: Anything else you think may be relevant to the issue or special about your specific setup.
validations:
required: false
-17
View File
@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
@@ -0,0 +1,37 @@
name: Feature request
description: Suggest an idea for this project
title: "[Feature request]: "
labels: enhancement
body:
- type: markdown
attributes:
value: |
Thank you for taking the time to fill out this feature form!
- type: textarea
id: feature
attributes:
label: Is your feature request related to a problem? Please describe.
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Describe the solution you'd like
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Describe alternatives you've considered
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Add any other context or screenshots about the feature request here.
validations:
required: false
+1 -1
View File
@@ -3,7 +3,7 @@
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/232a8tadrrn8jv0k/branch/master?svg=true)](https://ci.appveyor.com/project/cgutman/moonlight-android/branch/master)
[![Translation Status](https://hosted.weblate.org/widgets/moonlight/-/moonlight-android/svg-badge.svg)](https://hosted.weblate.org/projects/moonlight/moonlight-android/)
[Moonlight for Android](https://moonlight-stream.org) is an open source client for NVIDIA GameStream, as used by the NVIDIA Shield.
[Moonlight for Android](https://moonlight-stream.org) is an open source client for NVIDIA GameStream and [Sunshine](https://github.com/LizardByte/Sunshine).
Moonlight for Android will allow you to stream your full collection of games from your Windows PC to your Android device,
whether in your own home or over the internet.
+18 -5
View File
@@ -3,14 +3,16 @@ apply plugin: 'com.android.application'
android {
ndkVersion "23.2.8568313"
compileSdk 33
compileSdk 34
namespace 'com.limelight'
defaultConfig {
minSdk 16
targetSdk 33
targetSdk 34
versionName "10.8.4"
versionCode = 293
versionName "12.0.2"
versionCode = 313
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
ndk.debugSymbolLevel = 'FULL'
@@ -18,6 +20,10 @@ android {
flavorDimensions.add("root")
buildFeatures {
buildConfig = true
}
productFlavors {
root {
// Android O has native mouse capture, so don't show the rooted
@@ -48,6 +54,12 @@ android {
}
}
compileOptions {
encoding "UTF-8"
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
lint {
disable 'MissingTranslation'
lintConfig file('lint.xml')
@@ -129,6 +141,7 @@ dependencies {
implementation 'org.jcodec:jcodec:0.2.3'
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
implementation 'com.squareup.okio:okio:1.17.5'
// 3.5.8 requires minSdk 19, uses StandardCharsets.UTF_8 internally
implementation 'org.jmdns:jmdns:3.5.7'
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0'
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0.1'
}
+36 -21
View File
@@ -1,16 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.limelight">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
<!-- We don't need a MulticastLock on API level 34+ because we use NsdManager for mDNS -->
<uses-permission
android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
android:maxSdkVersion="33" />
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
@@ -26,6 +29,12 @@
<uses-feature
android:name="android.software.leanback"
android:required="false" />
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="false" />
<uses-feature
android:name="android.hardware.sensor.gyroscope"
android:required="false" />
<!-- Disable legacy input emulation on ChromeOS -->
<uses-feature
@@ -76,7 +85,12 @@
android:name=".PcView"
android:exported="true"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -92,37 +106,37 @@
android:noHistory="true"
android:exported="true"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
</activity>
<activity
android:name=".AppView"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
</activity>
<activity
android:name=".preferences.StreamSettings"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:label="Streaming Settings">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
</activity>
<activity
android:name=".preferences.AddComputerManually"
android:resizeableActivity="true"
android:windowSoftInputMode="stateVisible"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:label="Add Computer Manually">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
</activity>
<activity
android:name=".Game"
@@ -130,13 +144,14 @@
android:noHistory="true"
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="false"
android:launchMode="singleTask"
android:excludeFromRecents="true"
android:theme="@style/StreamTheme"
android:preferMinimalPostProcessing="true">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.AppView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
<!-- Special metadata for NVIDIA Shield devices to prevent input buffering
and most importantly, opt out of mouse acceleration while streaming -->
@@ -161,10 +176,10 @@
<activity
android:name=".HelpActivity"
android:resizeableActivity="true"
android:enableOnBackInvokedCallback="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
</activity>
</application>
File diff suppressed because it is too large Load Diff
@@ -71,12 +71,6 @@ public class HelpActivity extends Activity {
refreshBackDispatchState();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return !(url.toUpperCase().startsWith("https://github.com/moonlight-stream/moonlight-docs/wiki/".toUpperCase()) ||
url.toUpperCase().startsWith("http://github.com/moonlight-stream/moonlight-docs/wiki/".toUpperCase()));
}
});
webView.loadUrl(getIntent().getData().toString());
+29 -16
View File
@@ -118,6 +118,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
private final static int VIEW_DETAILS_ID = 8;
private final static int FULL_APP_LIST_ID = 9;
private final static int TEST_NETWORK_ID = 10;
private final static int GAMESTREAM_EOL_ID = 11;
private void initializeViews() {
setContentView(R.layout.activity_pc_view);
@@ -259,6 +260,11 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
updateComputer(details);
}
});
// Add a launcher shortcut for this PC (off the main thread to prevent ANRs)
if (details.pairState == PairState.PAIRED) {
shortcutHelper.createAppViewShortcutForOnlineHost(details);
}
}
}
});
@@ -352,9 +358,13 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
if (computer.details.state == ComputerDetails.State.OFFLINE ||
computer.details.state == ComputerDetails.State.UNKNOWN) {
menu.add(Menu.NONE, WOL_ID, 1, getResources().getString(R.string.pcview_menu_send_wol));
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 2, getResources().getString(R.string.pcview_menu_eol));
}
else if (computer.details.pairState != PairState.PAIRED) {
menu.add(Menu.NONE, PAIR_ID, 1, getResources().getString(R.string.pcview_menu_pair_pc));
if (computer.details.nvidiaServer) {
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 2, getResources().getString(R.string.pcview_menu_eol));
}
}
else {
if (computer.details.runningGameId != 0) {
@@ -362,6 +372,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
menu.add(Menu.NONE, QUIT_ID, 2, getResources().getString(R.string.applist_menu_quit));
}
if (computer.details.nvidiaServer) {
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 3, getResources().getString(R.string.pcview_menu_eol));
}
menu.add(Menu.NONE, FULL_APP_LIST_ID, 4, getResources().getString(R.string.pcview_menu_app_list));
}
@@ -383,10 +397,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
Toast.makeText(PcView.this, getResources().getString(R.string.pair_pc_offline), Toast.LENGTH_SHORT).show();
return;
}
if (computer.runningGameId != 0) {
Toast.makeText(PcView.this, getResources().getString(R.string.pair_pc_ingame), Toast.LENGTH_LONG).show();
return;
}
if (managerBinder == null) {
Toast.makeText(PcView.this, getResources().getString(R.string.error_manager_not_running), Toast.LENGTH_LONG).show();
return;
@@ -404,8 +414,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
stopComputerUpdates(true);
httpConn = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer),
managerBinder.getUniqueId(),
computer.serverCert,
computer.httpsPort, managerBinder.getUniqueId(), computer.serverCert,
PlatformBinding.getCryptoProvider(PcView.this));
if (httpConn.getPairState() == PairState.PAIRED) {
// Don't display any toast, but open the app list
@@ -417,16 +426,22 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
// Spin the dialog off in a thread because it blocks
Dialog.displayDialog(PcView.this, getResources().getString(R.string.pair_pairing_title),
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr, false);
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr+"\n\n"+
getResources().getString(R.string.pair_pairing_help), false);
PairingManager pm = httpConn.getPairingManager();
PairState pairState = pm.pair(httpConn.getServerInfo(), pinStr);
PairState pairState = pm.pair(httpConn.getServerInfo(true), pinStr);
if (pairState == PairState.PIN_WRONG) {
message = getResources().getString(R.string.pair_incorrect_pin);
}
else if (pairState == PairState.FAILED) {
message = getResources().getString(R.string.pair_fail);
if (computer.runningGameId != 0) {
message = getResources().getString(R.string.pair_pc_ingame);
}
else {
message = getResources().getString(R.string.pair_fail);
}
}
else if (pairState == PairState.ALREADY_IN_PROGRESS) {
message = getResources().getString(R.string.pair_already_in_progress);
@@ -533,8 +548,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
String message;
try {
httpConn = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer),
managerBinder.getUniqueId(),
computer.serverCert,
computer.httpsPort, managerBinder.getUniqueId(), computer.serverCert,
PlatformBinding.getCryptoProvider(PcView.this));
if (httpConn.getPairState() == PairingManager.PairState.PAIRED) {
httpConn.unpair();
@@ -657,6 +671,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
ServerHelper.doNetworkTest(PcView.this);
return true;
case GAMESTREAM_EOL_ID:
HelpLauncher.launchGameStreamEolFaq(PcView.this);
return true;
default:
return super.onContextItemSelected(item);
}
@@ -707,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) {
// Replace the information in the existing entry
existingEntry.details = details;
@@ -67,14 +67,12 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
return null;
}
try {
FileInputStream fin = new FileInputStream(f);
try (final FileInputStream fin = new FileInputStream(f)) {
byte[] fileData = new byte[(int) f.length()];
if (fin.read(fileData) != f.length()) {
// Failed to read
fileData = null;
}
fin.close();
return fileData;
} catch (IOException e) {
return null;
@@ -160,32 +158,28 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
}
private void saveCertKeyPair() {
try {
FileOutputStream certOut = new FileOutputStream(certFile);
FileOutputStream keyOut = new FileOutputStream(keyFile);
try (final FileOutputStream certOut = new FileOutputStream(certFile);
final FileOutputStream keyOut = new FileOutputStream(keyFile)
) {
// Write the certificate in OpenSSL PEM format (important for the server)
StringWriter strWriter = new StringWriter();
JcaPEMWriter pemWriter = new JcaPEMWriter(strWriter);
pemWriter.writeObject(cert);
pemWriter.close();
try (final JcaPEMWriter pemWriter = new JcaPEMWriter(strWriter)) {
pemWriter.writeObject(cert);
}
// Line endings MUST be UNIX for the PC to accept the cert properly
OutputStreamWriter certWriter = new OutputStreamWriter(certOut);
String pemStr = strWriter.getBuffer().toString();
for (int i = 0; i < pemStr.length(); i++) {
char c = pemStr.charAt(i);
if (c != '\r')
certWriter.append(c);
try (final OutputStreamWriter certWriter = new OutputStreamWriter(certOut)) {
String pemStr = strWriter.getBuffer().toString();
for (int i = 0; i < pemStr.length(); i++) {
char c = pemStr.charAt(i);
if (c != '\r')
certWriter.append(c);
}
}
certWriter.close();
// Write the private out in PKCS8 format
keyOut.write(key.getEncoded());
certOut.close();
keyOut.close();
LimeLog.info("Saved generated key pair to disk");
} catch (IOException e) {
// This isn't good because it means we'll have
File diff suppressed because it is too large Load Diff
@@ -104,18 +104,20 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
}
}
public static boolean needsShift(int keycode) {
switch (keycode)
{
case KeyEvent.KEYCODE_AT:
case KeyEvent.KEYCODE_POUND:
case KeyEvent.KEYCODE_PLUS:
case KeyEvent.KEYCODE_STAR:
return true;
default:
return false;
public boolean hasNormalizedMapping(int keycode, int deviceId) {
if (deviceId >= 0) {
KeyboardMapping mapping = keyboardMappings.get(deviceId);
if (mapping != null) {
// Try to map this device-specific keycode onto a QWERTY layout.
// GFE assumes incoming keycodes are from a QWERTY keyboard.
int qwertyKeyCode = mapping.getQwertyKeyCodeForDeviceKeyCode(keycode);
if (qwertyKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
return true;
}
}
}
return false;
}
/**
@@ -230,6 +232,10 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
translated = 0x5c;
break;
case KeyEvent.KEYCODE_MENU:
translated = 0x5d;
break;
case KeyEvent.KEYCODE_MINUS:
translated = 0xbd;
break;
@@ -343,20 +349,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
translated = 0x6E;
break;
case KeyEvent.KEYCODE_AT:
translated = 2 + VK_0;
break;
case KeyEvent.KEYCODE_POUND:
translated = 3 + VK_0;
break;
case KeyEvent.KEYCODE_STAR:
translated = 8 + VK_0;
break;
default:
System.out.println("No key for "+keycode);
return 0;
}
}
@@ -15,8 +15,8 @@ import android.view.View;
// is unavailable on this system (ex: DeX, ChromeOS)
@TargetApi(Build.VERSION_CODES.O)
public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptureProvider implements InputManager.InputDeviceListener {
private InputManager inputManager;
private View targetView;
private final InputManager inputManager;
private final View targetView;
public AndroidNativePointerCaptureProvider(Activity activity, View targetView) {
super(activity, targetView);
@@ -44,7 +44,10 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
// with SOURCE_TOUCHSCREEN, SOURCE_KEYBOARD, and SOURCE_MOUSE.
// Upon enabling pointer capture, that device will switch to
// SOURCE_KEYBOARD and SOURCE_TOUCHPAD.
if (device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
// Only skip on non ChromeOS devices cause the ChromeOS pointer else
// gets disabled removing relative mouse capabilities
// on Chromebooks with touchscreens
if (device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN) && !targetView.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management")) {
continue;
}
@@ -59,8 +62,19 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
}
@Override
public void enableCapture() {
super.enableCapture();
public void 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);
targetView.releasePointerCapture();
}
@Override
public void hideCursor() {
super.hideCursor();
// Listen for device events to enable/disable capture
inputManager.registerInputDeviceListener(this, null);
@@ -71,16 +85,12 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
}
}
@Override
public void disableCapture() {
super.disableCapture();
inputManager.unregisterInputDeviceListener(this);
targetView.releasePointerCapture();
}
@Override
public void onWindowFocusChanged(boolean focusActive) {
if (!focusActive || !isCapturing) {
// NB: We have to check cursor visibility here because Android pointer capture
// doesn't support capturing the cursor while it's visible. Enabling pointer
// capture implicitly hides the cursor.
if (!focusActive || !isCapturing || isCursorVisible) {
return;
}
@@ -4,14 +4,13 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.view.MotionEvent;
import android.view.PointerIcon;
import android.view.View;
@TargetApi(Build.VERSION_CODES.N)
public class AndroidPointerIconCaptureProvider extends InputCaptureProvider {
private View targetView;
private Context context;
private final View targetView;
private final Context context;
public AndroidPointerIconCaptureProvider(Activity activity, View targetView) {
this.context = activity;
@@ -23,14 +22,14 @@ public class AndroidPointerIconCaptureProvider extends InputCaptureProvider {
}
@Override
public void enableCapture() {
super.enableCapture();
public void hideCursor() {
super.hideCursor();
targetView.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_NULL));
}
@Override
public void disableCapture() {
super.disableCapture();
public void showCursor() {
super.showCursor();
targetView.setPointerIcon(null);
}
}
@@ -4,12 +4,15 @@ import android.view.MotionEvent;
public abstract class InputCaptureProvider {
protected boolean isCapturing;
protected boolean isCursorVisible;
public void enableCapture() {
isCapturing = true;
hideCursor();
}
public void disableCapture() {
isCapturing = false;
showCursor();
}
public void destroy() {}
@@ -22,6 +25,14 @@ public abstract class InputCaptureProvider {
return isCapturing;
}
public void showCursor() {
isCursorVisible = true;
}
public void hideCursor() {
isCursorVisible = false;
}
public boolean eventHasRelativeMouseAxes(MotionEvent event) {
return false;
}
@@ -22,7 +22,7 @@ public class ShieldCaptureProvider extends InputCaptureProvider {
private static int AXIS_RELATIVE_X;
private static int AXIS_RELATIVE_Y;
private Context context;
private final Context context;
static {
try {
@@ -62,14 +62,14 @@ public class ShieldCaptureProvider extends InputCaptureProvider {
}
@Override
public void enableCapture() {
super.enableCapture();
public void hideCursor() {
super.hideCursor();
setCursorVisibility(false);
}
@Override
public void disableCapture() {
super.disableCapture();
public void showCursor() {
super.showCursor();
setCursorVisibility(true);
}
@@ -8,10 +8,12 @@ public abstract class AbstractController {
private UsbDriverListener listener;
protected short buttonFlags;
protected int buttonFlags, supportedButtonFlags;
protected float leftTrigger, rightTrigger;
protected float rightStickX, rightStickY;
protected float leftStickX, leftStickY;
protected short capabilities;
protected byte type;
public int getControllerId() {
return deviceId;
@@ -25,6 +27,18 @@ public abstract class AbstractController {
return productId;
}
public int getSupportedButtonFlags() {
return supportedButtonFlags;
}
public short getCapabilities() {
return capabilities;
}
public byte getType() {
return type;
}
protected void setButtonFlag(int buttonFlag, int data) {
if (data != 0) {
buttonFlags |= buttonFlag;
@@ -51,6 +65,8 @@ public abstract class AbstractController {
public abstract void rumble(short lowFreqMotor, short highFreqMotor);
public abstract void rumbleTriggers(short leftTrigger, short rightTrigger);
protected void notifyDeviceRemoved() {
listener.deviceRemoved(this);
}
@@ -8,6 +8,8 @@ import android.hardware.usb.UsbInterface;
import android.os.SystemClock;
import com.limelight.LimeLog;
import com.limelight.nvstream.input.ControllerPacket;
import com.limelight.nvstream.jni.MoonBridge;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -25,6 +27,14 @@ public abstract class AbstractXboxController extends AbstractController {
super(deviceId, listener, device.getVendorId(), device.getProductId());
this.device = device;
this.connection = connection;
this.type = MoonBridge.LI_CTYPE_XBOX;
this.capabilities = MoonBridge.LI_CCAP_ANALOG_TRIGGERS | MoonBridge.LI_CCAP_RUMBLE;
this.buttonFlags =
ControllerPacket.A_FLAG | ControllerPacket.B_FLAG | ControllerPacket.X_FLAG | ControllerPacket.Y_FLAG |
ControllerPacket.UP_FLAG | ControllerPacket.DOWN_FLAG | ControllerPacket.LEFT_FLAG | ControllerPacket.RIGHT_FLAG |
ControllerPacket.LB_FLAG | ControllerPacket.RB_FLAG |
ControllerPacket.LS_CLK_FLAG | ControllerPacket.RS_CLK_FLAG |
ControllerPacket.BACK_FLAG | ControllerPacket.PLAY_FLAG | ControllerPacket.SPECIAL_BUTTON_FLAG;
}
private Thread createInputThread() {
@@ -1,7 +1,7 @@
package com.limelight.binding.input.driver;
public interface UsbDriverListener {
void reportControllerState(int controllerId, short buttonFlags,
void reportControllerState(int controllerId, int buttonFlags,
float leftStickX, float leftStickY,
float rightStickX, float rightStickY,
float leftTrigger, float rightTrigger);
@@ -20,6 +20,7 @@ import com.limelight.LimeLog;
import com.limelight.R;
import com.limelight.preferences.PreferenceConfiguration;
import java.io.File;
import java.util.ArrayList;
public class UsbDriverService extends Service implements UsbDriverListener {
@@ -41,7 +42,8 @@ public class UsbDriverService extends Service implements UsbDriverListener {
private int nextDeviceId;
@Override
public void reportControllerState(int controllerId, short buttonFlags, float leftStickX, float leftStickY, float rightStickX, float rightStickY, float leftTrigger, float rightTrigger) {
public void reportControllerState(int controllerId, int buttonFlags, float leftStickX, float leftStickY,
float rightStickX, float rightStickY, float leftTrigger, float rightTrigger) {
// Call through to the client's listener
if (listener != null) {
listener.reportControllerState(controllerId, buttonFlags, leftStickX, leftStickY, rightStickX, rightStickY, leftTrigger, rightTrigger);
@@ -157,7 +159,12 @@ public class UsbDriverService extends Service implements UsbDriverListener {
// just returning a false result or returning 0 enumerated devices,
// they throw an undocumented SecurityException from this call, crashing
// the whole app. :(
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), intentFlags));
// Use an explicit intent to activate our unexported broadcast receiver, as required on Android 14+
Intent i = new Intent(ACTION_USB_PERMISSION);
i.setPackage(getPackageName());
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, i, intentFlags));
} catch (SecurityException e) {
Toast.makeText(this, this.getText(R.string.error_usb_prohibited), Toast.LENGTH_LONG).show();
if (stateListener != null) {
@@ -183,6 +190,9 @@ public class UsbDriverService extends Service implements UsbDriverListener {
else if (Xbox360Controller.canClaimDevice(device)) {
controller = new Xbox360Controller(device, connection, nextDeviceId++, this);
}
else if (Xbox360WirelessDongle.canClaimDevice(device)) {
controller = new Xbox360WirelessDongle(device, connection, nextDeviceId++, this);
}
else {
// Unreachable
return;
@@ -248,13 +258,36 @@ public class UsbDriverService extends Service implements UsbDriverListener {
}
}
public static boolean kernelSupportsXbox360W() {
// Check if this kernel is 4.2+ to see if the xpad driver sets Xbox 360 wireless LEDs
// https://github.com/torvalds/linux/commit/75b7f05d2798ee3a1cc5bbdd54acd0e318a80396
String kernelVersion = System.getProperty("os.version");
if (kernelVersion != null) {
if (kernelVersion.startsWith("2.") || kernelVersion.startsWith("3.") ||
kernelVersion.startsWith("4.0.") || kernelVersion.startsWith("4.1.")) {
// Even if LED devices are present, the driver won't set the initial LED state.
return false;
}
}
// We know we have a kernel that should set Xbox 360 wireless LEDs, but we still don't
// know if CONFIG_JOYSTICK_XPAD_LEDS was enabled during the kernel build. Unfortunately
// it's not possible to detect this reliably due to Android's app sandboxing. Reading
// /proc/config.gz and enumerating /sys/class/leds are both blocked by SELinux on any
// relatively modern device. We will assume that CONFIG_JOYSTICK_XPAD_LEDS=y on these
// kernels and users can override by using the settings option to claim all devices.
return true;
}
public static boolean shouldClaimDevice(UsbDevice device, boolean claimAllAvailable) {
return ((!kernelSupportsXboxOne() || !isRecognizedInputDevice(device) || claimAllAvailable) && XboxOneController.canClaimDevice(device)) ||
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device));
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)) ||
// We must not call isRecognizedInputDevice() because wireless controllers don't share the same product ID as the dongle
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device));
}
private void start() {
if (started) {
if (started || usbManager == null) {
return;
}
@@ -156,4 +156,9 @@ public class Xbox360Controller extends AbstractXboxController {
LimeLog.warning("Rumble transfer failed: "+res);
}
}
@Override
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
// Trigger motors not present on Xbox 360 controllers
}
}
@@ -0,0 +1,150 @@
package com.limelight.binding.input.driver;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.os.Build;
import android.view.InputDevice;
import com.limelight.LimeLog;
import java.nio.ByteBuffer;
public class Xbox360WirelessDongle extends AbstractController {
private UsbDevice device;
private UsbDeviceConnection connection;
private static final int XB360W_IFACE_SUBCLASS = 93;
private static final int XB360W_IFACE_PROTOCOL = 129; // Wireless only
private static final int[] SUPPORTED_VENDORS = {
0x045e, // Microsoft
};
public static boolean canClaimDevice(UsbDevice device) {
for (int supportedVid : SUPPORTED_VENDORS) {
if (device.getVendorId() == supportedVid &&
device.getInterfaceCount() >= 1 &&
device.getInterface(0).getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
device.getInterface(0).getInterfaceSubclass() == XB360W_IFACE_SUBCLASS &&
device.getInterface(0).getInterfaceProtocol() == XB360W_IFACE_PROTOCOL) {
return true;
}
}
return false;
}
public Xbox360WirelessDongle(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
super(deviceId, listener, device.getVendorId(), device.getProductId());
this.device = device;
this.connection = connection;
}
private void sendLedCommandToEndpoint(UsbEndpoint endpoint, int controllerIndex) {
byte[] commandBuffer = {
0x00,
0x00,
0x08,
(byte) (0x40 + (2 + (controllerIndex % 4))),
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00};
int res = connection.bulkTransfer(endpoint, commandBuffer, commandBuffer.length, 3000);
if (res != commandBuffer.length) {
LimeLog.warning("LED set transfer failed: "+res);
}
}
private void sendLedCommandToInterface(UsbInterface iface, int controllerIndex) {
// Claim this interface to kick xpad off it (temporarily)
if (!connection.claimInterface(iface, true)) {
LimeLog.warning("Failed to claim interface: "+iface.getId());
return;
}
// Find the out endpoint for this interface
for (int i = 0; i < iface.getEndpointCount(); i++) {
UsbEndpoint endpt = iface.getEndpoint(i);
if (endpt.getDirection() == UsbConstants.USB_DIR_OUT) {
// Send the LED command
sendLedCommandToEndpoint(endpt, controllerIndex);
break;
}
}
// Release the interface to allow xpad to take over again
connection.releaseInterface(iface);
}
@Override
public boolean start() {
int controllerIndex = 0;
// On KitKat, there is a controller number associated with input devices.
// 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
// matches the order that devices were enumerated by xpad, but it's probably
// better than nothing.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
for (int id : InputDevice.getDeviceIds()) {
InputDevice inputDev = InputDevice.getDevice(id);
if (inputDev == null) {
// Device was removed while looping
continue;
}
// Newer xpad versions use a special product ID (0x02a1) for controllers
// rather than copying the product ID of the dongle itself.
if (inputDev.getVendorId() == device.getVendorId() &&
(inputDev.getProductId() == device.getProductId() ||
inputDev.getProductId() == 0x02a1) &&
inputDev.getControllerNumber() > 0) {
controllerIndex = inputDev.getControllerNumber() - 1;
break;
}
}
}
// Send LED commands on the out endpoint of each interface. There is one interface
// corresponding to each possible attached controller.
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface iface = device.getInterface(i);
// Skip the non-input interfaces
if (iface.getInterfaceClass() != UsbConstants.USB_CLASS_VENDOR_SPEC ||
iface.getInterfaceSubclass() != XB360W_IFACE_SUBCLASS ||
iface.getInterfaceProtocol() != XB360W_IFACE_PROTOCOL) {
continue;
}
sendLedCommandToInterface(iface, controllerIndex++);
}
// "Fail" to give control back to the kernel driver
return false;
}
@Override
public void stop() {
// Nothing to do
}
@Override
public void rumble(short lowFreqMotor, short highFreqMotor) {
// Unreachable.
}
@Override
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
// Unreachable.
}
}
@@ -6,6 +6,7 @@ import android.hardware.usb.UsbDeviceConnection;
import com.limelight.LimeLog;
import com.limelight.nvstream.input.ControllerPacket;
import com.limelight.nvstream.jni.MoonBridge;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -54,9 +55,14 @@ public class XboxOneController extends AbstractXboxController {
};
private byte seqNum = 0;
private short lowFreqMotor = 0;
private short highFreqMotor = 0;
private short leftTriggerMotor = 0;
private short rightTriggerMotor = 0;
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
super(device, connection, deviceId, listener);
capabilities |= MoonBridge.LI_CCAP_TRIGGER_RUMBLE;
}
private void processButtons(ByteBuffer buffer) {
@@ -176,12 +182,14 @@ public class XboxOneController extends AbstractXboxController {
return true;
}
@Override
public void rumble(short lowFreqMotor, short highFreqMotor) {
private void sendRumblePacket() {
byte[] data = {
0x09, 0x00, seqNum++, 0x09, 0x00,
0x0F, 0x00, 0x00,
(byte)(lowFreqMotor >> 9), (byte)(highFreqMotor >> 9),
0x0F,
(byte)(leftTriggerMotor >> 9),
(byte)(rightTriggerMotor >> 9),
(byte)(lowFreqMotor >> 9),
(byte)(highFreqMotor >> 9),
(byte)0xFF, 0x00, (byte)0xFF
};
int res = connection.bulkTransfer(outEndpt, data, data.length, 100);
@@ -190,6 +198,20 @@ public class XboxOneController extends AbstractXboxController {
}
}
@Override
public void rumble(short lowFreqMotor, short highFreqMotor) {
this.lowFreqMotor = lowFreqMotor;
this.highFreqMotor = highFreqMotor;
sendRumblePacket();
}
@Override
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
this.leftTriggerMotor = leftTrigger;
this.rightTriggerMotor = rightTrigger;
sendRumblePacket();
}
private static class InitPacket {
final int vendorId;
final int productId;
@@ -9,6 +9,7 @@ public interface EvdevListener {
void mouseMove(int deltaX, int deltaY);
void mouseButtonEvent(int buttonId, boolean down);
void mouseScroll(byte amount);
void mouseVScroll(byte amount);
void mouseHScroll(byte amount);
void keyboardEvent(boolean buttonDown, short keyCode);
}
File diff suppressed because it is too large Load Diff
@@ -14,6 +14,7 @@ import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaCodecInfo.CodecCapabilities;
@@ -31,7 +32,6 @@ public class MediaCodecHelper {
private static final List<String> blacklistedDecoderPrefixes;
private static final List<String> spsFixupBitstreamFixupDecoderPrefixes;
private static final List<String> blacklistedAdaptivePlaybackPrefixes;
private static final List<String> deprioritizedHevcDecoders;
private static final List<String> baselineProfileHackPrefixes;
private static final List<String> directSubmitPrefixes;
private static final List<String> constrainedHighProfilePrefixes;
@@ -43,6 +43,7 @@ public class MediaCodecHelper {
private static final List<String> kirinDecoderPrefixes;
private static final List<String> exynosDecoderPrefixes;
private static final List<String> amlogicDecoderPrefixes;
private static final List<String> knownVendorLowLatencyOptions;
public static final boolean SHOULD_BYPASS_SOFTWARE_BLOCK =
Build.HARDWARE.equals("ranchu") || Build.HARDWARE.equals("cheets") || Build.BRAND.equals("Android-x86");
@@ -71,7 +72,10 @@ public class MediaCodecHelper {
static {
refFrameInvalidationAvcPrefixes = new LinkedList<>();
refFrameInvalidationHevcPrefixes = new LinkedList<>();
refFrameInvalidationHevcPrefixes.add("omx.exynos");
refFrameInvalidationHevcPrefixes.add("c2.exynos");
// Qualcomm and NVIDIA may be added at runtime
}
@@ -173,6 +177,9 @@ public class MediaCodecHelper {
// vendor.low-latency.enable. We will still use HEVC if decoderCanMeetPerformancePointWithHevcAndNotAvc()
// determines it's the only way to meet the performance requirements.
//
// With the Android 12 update, Sabrina now uses HEVC (with RFI) based upon FEATURE_LowLatency
// support, which provides equivalent latency to H.264 now.
//
// FIXME: Should we do this for all Amlogic S905X SoCs?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !Build.DEVICE.equalsIgnoreCase("sabrina")) {
whitelistedHevcDecoders.add("omx.amlogic");
@@ -195,14 +202,6 @@ public class MediaCodecHelper {
// during initialization to avoid SoCs with broken HEVC decoders.
}
static {
deprioritizedHevcDecoders = new LinkedList<>();
// These are decoders that work but aren't used by default for various reasons.
// Qualcomm is currently the only decoders in this group.
}
static {
useFourSlicesPrefixes = new LinkedList<>();
@@ -215,6 +214,15 @@ public class MediaCodecHelper {
// Old Qualcomm decoders are detected at runtime
}
static {
knownVendorLowLatencyOptions = new LinkedList<>();
knownVendorLowLatencyOptions.add("vendor.qti-ext-dec-low-latency.enable");
knownVendorLowLatencyOptions.add("vendor.hisi-ext-low-latency-video-dec.video-scene-for-low-latency-req");
knownVendorLowLatencyOptions.add("vendor.rtc-ext-dec-low-latency.enable");
knownVendorLowLatencyOptions.add("vendor.low-latency.enable");
}
static {
qualcommDecoderPrefixes = new LinkedList<>();
@@ -306,12 +314,33 @@ public class MediaCodecHelper {
// We still have to check Build.MANUFACTURER to catch Amazon Fire tablets.
if (context.getPackageManager().hasSystemFeature("amazon.hardware.fire_tv") ||
Build.MANUFACTURER.equalsIgnoreCase("Amazon")) {
// HEVC and RFI have been confirmed working on Fire TV 2, Fire TV Stick 2, Fire TV 4K Max,
// Fire HD 8 2020, and Fire HD 8 2022 models.
//
// This is probably a good enough sample to conclude that all MediaTek Fire OS devices
// are likely to be okay.
whitelistedHevcDecoders.add("omx.mtk");
refFrameInvalidationHevcPrefixes.add("omx.mtk");
refFrameInvalidationHevcPrefixes.add("c2.mtk");
// This requires setting vdec-lowlatency on the Fire TV 3, otherwise the decoder
// never produces any output frames. See comment above for details on why we only
// do this for Fire TV devices.
whitelistedHevcDecoders.add("omx.amlogic");
// Fire TV 3 seems to produce random artifacts on HEVC streams after packet loss.
// Enabling RFI turns these artifacts into full decoder output hangs, so let's not enable
// that for Fire OS 6 Amlogic devices. We will leave HEVC enabled because that's the only
// way these devices can hit 4K. Hopefully this is just a problem with the BSP used in
// the Fire OS 6 Amlogic devices, so we will leave this enabled for Fire OS 7+.
//
// Apart from a few TV models, the main Amlogic-based Fire TV devices are the Fire TV
// Cubes and Fire TV 3. This check will exclude the Fire TV 3 and Fire TV Cube 1, but
// allow the newer Fire TV Cubes to use HEVC RFI.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
refFrameInvalidationHevcPrefixes.add("omx.amlogic");
refFrameInvalidationHevcPrefixes.add("c2.amlogic");
}
}
ActivityManager activityManager =
@@ -325,19 +354,24 @@ public class MediaCodecHelper {
// Tegra K1 and later can do reference frame invalidation properly
if (configInfo.reqGlEsVersion >= 0x30000) {
LimeLog.info("Added omx.nvidia to AVC reference frame invalidation support list");
LimeLog.info("Added omx.nvidia/c2.nvidia to reference frame invalidation support list");
refFrameInvalidationAvcPrefixes.add("omx.nvidia");
LimeLog.info("Added omx.qcom/c2.qti to AVC reference frame invalidation support list");
refFrameInvalidationAvcPrefixes.add("omx.qcom");
refFrameInvalidationAvcPrefixes.add("c2.qti");
// Prior to M, we were tricking the decoder into using baseline profile, which
// won't support RFI properly.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
LimeLog.info("Added omx.intel to AVC reference frame invalidation support list");
refFrameInvalidationAvcPrefixes.add("omx.intel");
// Exclude HEVC RFI on Pixel C and Tegra devices prior to Android 11. Misbehaving RFI
// on these devices can cause hundreds of milliseconds of latency, so it's not worth
// using it unless we're absolutely sure that it will not cause increased latency.
if (!Build.DEVICE.equalsIgnoreCase("dragon") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
refFrameInvalidationHevcPrefixes.add("omx.nvidia");
}
refFrameInvalidationAvcPrefixes.add("c2.nvidia"); // Unconfirmed
refFrameInvalidationHevcPrefixes.add("c2.nvidia"); // Unconfirmed
LimeLog.info("Added omx.qcom/c2.qti to reference frame invalidation support list");
refFrameInvalidationAvcPrefixes.add("omx.qcom");
refFrameInvalidationHevcPrefixes.add("omx.qcom");
refFrameInvalidationAvcPrefixes.add("c2.qti");
refFrameInvalidationHevcPrefixes.add("c2.qti");
}
// Qualcomm's early HEVC decoders break hard on our HEVC stream. The best check to
@@ -349,13 +383,9 @@ public class MediaCodecHelper {
// (see comment on isGLES31SnapdragonRenderer).
//
if (isGLES31SnapdragonRenderer(glRenderer)) {
// We prefer reference frame invalidation support (which is only doable on AVC on
// older Qualcomm chips) vs. enabling HEVC by default. The user can override using the settings
// to force HEVC on. If HDR or mobile data will be used, we'll override this and use
// HEVC anyway.
LimeLog.info("Added omx.qcom/c2.qti to deprioritized HEVC decoders based on GLES 3.1+ support");
deprioritizedHevcDecoders.add("omx.qcom");
deprioritizedHevcDecoders.add("c2.qti");
LimeLog.info("Added omx.qcom/c2.qti to HEVC decoders based on GLES 3.1+ support");
whitelistedHevcDecoders.add("omx.qcom");
whitelistedHevcDecoders.add("c2.qti");
}
else {
blacklistedDecoderPrefixes.add("OMX.qcom.video.decoder.hevc");
@@ -375,8 +405,9 @@ public class MediaCodecHelper {
// decoder hangs on the newer GE8100, GE8300, and GE8320 GPUs, so we limit it to the
// Series6XT GPUs where we know it works.
if (glRenderer.contains("GX6")) {
LimeLog.info("Added omx.mtk to RFI list for HEVC");
LimeLog.info("Added omx.mtk/c2.mtk to RFI list for HEVC");
refFrameInvalidationHevcPrefixes.add("omx.mtk");
refFrameInvalidationHevcPrefixes.add("c2.mtk");
}
}
}
@@ -417,6 +448,35 @@ public class MediaCodecHelper {
return false;
}
private static boolean decoderSupportsKnownVendorLowLatencyOption(String decoderName) {
// It's only possible to probe vendor parameters on Android 12 and above.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
MediaCodec testCodec = null;
try {
// Unfortunately we have to create an actual codec instance to get supported options.
testCodec = MediaCodec.createByCodecName(decoderName);
// See if any of the vendor parameters match ones we know about
for (String supportedOption : testCodec.getSupportedVendorParameters()) {
for (String knownLowLatencyOption : knownVendorLowLatencyOptions) {
if (supportedOption.equalsIgnoreCase(knownLowLatencyOption)) {
LimeLog.info(decoderName + " supports known low latency option: " + supportedOption);
return true;
}
}
}
} catch (Exception e) {
// Tolerate buggy codecs
e.printStackTrace();
} finally {
if (testCodec != null) {
testCodec.release();
}
}
}
return false;
}
private static boolean decoderSupportsMaxOperatingRate(String decoderName) {
// Operate at maximum rate to lower latency as much as possible on
// some Qualcomm platforms. We could also set KEY_PRIORITY to 0 (realtime)
@@ -469,6 +529,17 @@ public class MediaCodecHelper {
setNewOption = true;
}
if (tryNumber < 3) {
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(decoderInfo.getName())) {
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
setNewOption = true;
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
videoFormat.setInteger(MediaFormat.KEY_PRIORITY, 0);
setNewOption = true;
}
}
// MediaCodec supports vendor-defined format keys using the "vendor.<extension name>.<parameter name>" syntax.
// These allow access to functionality that is not exposed through documented MediaFormat.KEY_* values.
// https://cs.android.com/android/platform/superproject/+/master:hardware/qcom/sdm845/media/mm-video-v4l2/vidc/common/inc/vidc_vendor_extensions.h;l=67
@@ -477,23 +548,25 @@ public class MediaCodecHelper {
// https://cs.android.com/android/_/android/platform/frameworks/av/+/01c10f8cdcd58d1e7025f426a72e6e75ba5d7fc2
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Try vendor-specific low latency options
//
// NOTE: Update knownVendorLowLatencyOptions if you modify this code!
if (isDecoderInList(qualcommDecoderPrefixes, decoderInfo.getName())) {
// Examples of Qualcomm's vendor extensions for Snapdragon 845:
// https://cs.android.com/android/platform/superproject/+/master:hardware/qcom/sdm845/media/mm-video-v4l2/vidc/vdec/src/omx_vdec_extensions.hpp
// https://cs.android.com/android/_/android/platform/hardware/qcom/sm8150/media/+/0621ceb1c1b19564999db8293574a0e12952ff6c
//
// We will first try both, then try vendor.qti-ext-dec-low-latency.enable alone if that fails
if (tryNumber < 3) {
if (tryNumber < 4) {
videoFormat.setInteger("vendor.qti-ext-dec-picture-order.enable", 1);
setNewOption = true;
}
if (tryNumber < 4) {
if (tryNumber < 5) {
videoFormat.setInteger("vendor.qti-ext-dec-low-latency.enable", 1);
setNewOption = true;
}
}
else if (isDecoderInList(kirinDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
if (tryNumber < 4) {
// Kirin low latency options
// https://developer.huawei.com/consumer/cn/forum/topic/0202325564295980115
videoFormat.setInteger("vendor.hisi-ext-low-latency-video-dec.video-scene-for-low-latency-req", 1);
@@ -502,14 +575,14 @@ public class MediaCodecHelper {
}
}
else if (isDecoderInList(exynosDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
if (tryNumber < 4) {
// Exynos low latency option for H.264 decoder
videoFormat.setInteger("vendor.rtc-ext-dec-low-latency.enable", 1);
setNewOption = true;
}
}
else if (isDecoderInList(amlogicDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
if (tryNumber < 4) {
// Amlogic low latency vendor extension
// https://github.com/codewalkerster/android_vendor_amlogic_common_prebuilt_libstagefrighthw/commit/41fefc4e035c476d58491324a5fe7666bfc2989e
videoFormat.setInteger("vendor.low-latency.enable", 1);
@@ -518,11 +591,6 @@ public class MediaCodecHelper {
}
}
// FIXME: We should probably integrate this into the try system
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(decoderInfo.getName())) {
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
}
return setNewOption;
}
@@ -612,11 +680,35 @@ public class MediaCodecHelper {
return isDecoderInList(refFrameInvalidationAvcPrefixes, decoderName);
}
public static boolean decoderSupportsRefFrameInvalidationHevc(String decoderName) {
return isDecoderInList(refFrameInvalidationHevcPrefixes, decoderName);
public static boolean decoderSupportsRefFrameInvalidationHevc(MediaCodecInfo decoderInfo) {
// HEVC decoders seem to universally support RFI, but it can have huge latency penalties
// for some decoders due to the number of references frames being > 1. Old Amlogic
// decoders are known to have this problem.
//
// If the decoder supports FEATURE_LowLatency or any vendor low latency option,
// we will use that as an indication that it can handle HEVC RFI without excessively
// buffering frames.
if (decoderSupportsAndroidRLowLatency(decoderInfo, "video/hevc") ||
decoderSupportsKnownVendorLowLatencyOption(decoderInfo.getName())) {
LimeLog.info("Enabling HEVC RFI based on low latency option support");
return true;
}
return isDecoderInList(refFrameInvalidationHevcPrefixes, decoderInfo.getName());
}
public static boolean decoderIsWhitelistedForHevc(String decoderName, boolean meteredData, PreferenceConfiguration prefs) {
public static boolean decoderSupportsRefFrameInvalidationAv1(MediaCodecInfo decoderInfo) {
// We'll use the same heuristics as HEVC for now
if (decoderSupportsAndroidRLowLatency(decoderInfo, "video/av01") ||
decoderSupportsKnownVendorLowLatencyOption(decoderInfo.getName())) {
LimeLog.info("Enabling AV1 RFI based on low latency option support");
return true;
}
return false;
}
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.
@@ -630,28 +722,64 @@ public class MediaCodecHelper {
// OMX.qcom.video.decoder.hevcswvdec
// OMX.SEC.hevc.sw.dec
//
if (decoderName.contains("sw")) {
if (decoderInfo.getName().contains("sw")) {
LimeLog.info("Disallowing HEVC on software decoder: " + decoderInfo.getName());
return false;
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && (!decoderInfo.isHardwareAccelerated() || decoderInfo.isSoftwareOnly())) {
LimeLog.info("Disallowing HEVC on software decoder: " + decoderInfo.getName());
return false;
}
// Some devices have HEVC decoders that we prefer not to use
// typically because it can't support reference frame invalidation.
// However, we will use it for HDR and for streaming over mobile networks
// since it works fine otherwise. We will also use it for 4K because RFI
// is currently disabled due to issues with video corruption.
if (isDecoderInList(deprioritizedHevcDecoders, decoderName)) {
if (meteredData || (prefs.width == 3840 && prefs.height == 2160)) {
LimeLog.info("Selected deprioritized decoder");
// If this device is media performance class 12 or higher, we will assume any hardware
// HEVC decoder present is fast and modern enough for streaming.
//
// [5.3/H-1-1] MUST NOT drop more than 2 frames in 10 seconds (i.e less than 0.333 percent frame drop) for a 1080p 60 fps video session under load.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
LimeLog.info("Media performance class: " + Build.VERSION.MEDIA_PERFORMANCE_CLASS);
if (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S) {
LimeLog.info("Allowing HEVC based on media performance class");
return true;
}
else {
return false;
}
}
return isDecoderInList(whitelistedHevcDecoders, decoderName);
// If the decoder supports FEATURE_LowLatency, we will assume it is fast and modern enough
// to be preferable for streaming over H.264 decoders.
if (decoderSupportsAndroidRLowLatency(decoderInfo, "video/hevc")) {
LimeLog.info("Allowing HEVC based on FEATURE_LowLatency support");
return true;
}
// Otherwise, we use our list of known working HEVC decoders
return isDecoderInList(whitelistedHevcDecoders, decoderInfo.getName());
}
public static boolean isDecoderWhitelistedForAv1(MediaCodecInfo decoderInfo) {
// Google didn't have official support for AV1 (or more importantly, a CTS test) until
// Android 10, so don't use any decoder before then.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return false;
}
//
// Software decoders are terrible and we never want to use them.
// We want to catch decoders like:
// OMX.qcom.video.decoder.hevcswvdec
// OMX.SEC.hevc.sw.dec
//
if (decoderInfo.getName().contains("sw")) {
LimeLog.info("Disallowing AV1 on software decoder: " + decoderInfo.getName());
return false;
}
else if (!decoderInfo.isHardwareAccelerated() || decoderInfo.isSoftwareOnly()) {
LimeLog.info("Disallowing AV1 on software decoder: " + decoderInfo.getName());
return false;
}
// TODO: Test some AV1 decoders
return false;
}
@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
@@ -853,8 +981,7 @@ public class MediaCodecHelper {
public static String readCpuinfo() throws Exception {
StringBuilder cpuInfo = new StringBuilder();
BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo")));
try {
try (final BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo")))) {
for (;;) {
int ch = br.read();
if (ch == -1)
@@ -863,8 +990,6 @@ public class MediaCodecHelper {
}
return cpuInfo.toString();
} finally {
br.close();
}
}
@@ -11,6 +11,10 @@ class VideoStats {
int totalFramesRendered;
int frameLossEvents;
int framesLost;
char minHostProcessingLatency;
char maxHostProcessingLatency;
int totalHostProcessingLatency;
int framesWithHostProcessingLatency;
long measurementStartTimestamp;
void add(VideoStats other) {
@@ -22,6 +26,15 @@ class VideoStats {
this.frameLossEvents += other.frameLossEvents;
this.framesLost += other.framesLost;
if (this.minHostProcessingLatency == 0) {
this.minHostProcessingLatency = other.minHostProcessingLatency;
} else {
this.minHostProcessingLatency = (char) Math.min(this.minHostProcessingLatency, other.minHostProcessingLatency);
}
this.maxHostProcessingLatency = (char) Math.max(this.maxHostProcessingLatency, other.maxHostProcessingLatency);
this.totalHostProcessingLatency += other.totalHostProcessingLatency;
this.framesWithHostProcessingLatency += other.framesWithHostProcessingLatency;
if (this.measurementStartTimestamp == 0) {
this.measurementStartTimestamp = other.measurementStartTimestamp;
}
@@ -37,6 +50,10 @@ class VideoStats {
this.totalFramesRendered = other.totalFramesRendered;
this.frameLossEvents = other.frameLossEvents;
this.framesLost = other.framesLost;
this.minHostProcessingLatency = other.minHostProcessingLatency;
this.maxHostProcessingLatency = other.maxHostProcessingLatency;
this.totalHostProcessingLatency = other.totalHostProcessingLatency;
this.framesWithHostProcessingLatency = other.framesWithHostProcessingLatency;
this.measurementStartTimestamp = other.measurementStartTimestamp;
}
@@ -48,6 +65,10 @@ class VideoStats {
this.totalFramesRendered = 0;
this.frameLossEvents = 0;
this.framesLost = 0;
this.minHostProcessingLatency = 0;
this.maxHostProcessingLatency = 0;
this.totalHostProcessingLatency = 0;
this.framesWithHostProcessingLatency = 0;
this.measurementStartTimestamp = 0;
}
@@ -9,7 +9,9 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import com.limelight.LimeLog;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvHTTP;
import android.content.ContentValues;
import android.content.Context;
@@ -17,17 +19,28 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import org.json.JSONException;
import org.json.JSONObject;
public class ComputerDatabaseManager {
private static final String COMPUTER_DB_NAME = "computers3.db";
private static final String COMPUTER_DB_NAME = "computers4.db";
private static final String COMPUTER_TABLE_NAME = "Computers";
private static final String COMPUTER_UUID_COLUMN_NAME = "UUID";
private static final String COMPUTER_NAME_COLUMN_NAME = "ComputerName";
private static final String ADDRESSES_COLUMN_NAME = "Addresses";
private interface AddressFields {
String LOCAL = "local";
String REMOTE = "remote";
String MANUAL = "manual";
String IPv6 = "ipv6";
String ADDRESS = "address";
String PORT = "port";
}
private static final String MAC_ADDRESS_COLUMN_NAME = "MacAddress";
private static final String SERVER_CERT_COLUMN_NAME = "ServerCert";
private static final char ADDRESS_DELIMITER = ';';
private SQLiteDatabase computerDb;
public ComputerDatabaseManager(Context c) {
@@ -62,24 +75,54 @@ public class ComputerDatabaseManager {
for (ComputerDetails computer : oldComputers) {
updateComputer(computer);
}
oldComputers = LegacyDatabaseReader3.migrateAllComputers(c);
for (ComputerDetails computer : oldComputers) {
updateComputer(computer);
}
}
public void deleteComputer(ComputerDetails details) {
computerDb.delete(COMPUTER_TABLE_NAME, COMPUTER_UUID_COLUMN_NAME+"=?", new String[]{details.uuid});
}
public static JSONObject tupleToJson(ComputerDetails.AddressTuple tuple) throws JSONException {
if (tuple == null) {
return null;
}
JSONObject json = new JSONObject();
json.put(AddressFields.ADDRESS, tuple.address);
json.put(AddressFields.PORT, tuple.port);
return json;
}
public static ComputerDetails.AddressTuple tupleFromJson(JSONObject json, String name) throws JSONException {
if (!json.has(name)) {
return null;
}
JSONObject address = json.getJSONObject(name);
return new ComputerDetails.AddressTuple(
address.getString(AddressFields.ADDRESS), address.getInt(AddressFields.PORT));
}
public boolean updateComputer(ComputerDetails details) {
ContentValues values = new ContentValues();
values.put(COMPUTER_UUID_COLUMN_NAME, details.uuid);
values.put(COMPUTER_NAME_COLUMN_NAME, details.name);
StringBuilder addresses = new StringBuilder();
addresses.append(details.localAddress != null ? details.localAddress : "");
addresses.append(ADDRESS_DELIMITER).append(details.remoteAddress != null ? details.remoteAddress : "");
addresses.append(ADDRESS_DELIMITER).append(details.manualAddress != null ? details.manualAddress : "");
addresses.append(ADDRESS_DELIMITER).append(details.ipv6Address != null ? details.ipv6Address : "");
try {
JSONObject addresses = new JSONObject();
addresses.put(AddressFields.LOCAL, tupleToJson(details.localAddress));
addresses.put(AddressFields.REMOTE, tupleToJson(details.remoteAddress));
addresses.put(AddressFields.MANUAL, tupleToJson(details.manualAddress));
addresses.put(AddressFields.IPv6, tupleToJson(details.ipv6Address));
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
} catch (JSONException e) {
throw new RuntimeException(e);
}
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
values.put(MAC_ADDRESS_COLUMN_NAME, details.macAddress);
try {
if (details.serverCert != null) {
@@ -95,26 +138,28 @@ public class ComputerDatabaseManager {
return -1 != computerDb.insertWithOnConflict(COMPUTER_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
private static String readNonEmptyString(String input) {
if (input.isEmpty()) {
return null;
}
return input;
}
private ComputerDetails getComputerFromCursor(Cursor c) {
ComputerDetails details = new ComputerDetails();
details.uuid = c.getString(0);
details.name = c.getString(1);
try {
JSONObject addresses = new JSONObject(c.getString(2));
details.localAddress = tupleFromJson(addresses, AddressFields.LOCAL);
details.remoteAddress = tupleFromJson(addresses, AddressFields.REMOTE);
details.manualAddress = tupleFromJson(addresses, AddressFields.MANUAL);
details.ipv6Address = tupleFromJson(addresses, AddressFields.IPv6);
} catch (JSONException e) {
throw new RuntimeException(e);
}
String[] addresses = c.getString(2).split(""+ADDRESS_DELIMITER, -1);
details.localAddress = readNonEmptyString(addresses[0]);
details.remoteAddress = readNonEmptyString(addresses[1]);
details.manualAddress = readNonEmptyString(addresses[2]);
details.ipv6Address = readNonEmptyString(addresses[3]);
// External port is persisted in the remote address field
if (details.remoteAddress != null) {
details.externalPort = details.remoteAddress.port;
}
else {
details.externalPort = NvHTTP.DEFAULT_HTTP_PORT;
}
details.macAddress = c.getString(3);
@@ -136,28 +181,26 @@ public class ComputerDatabaseManager {
}
public List<ComputerDetails> getAllComputers() {
Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null);
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
computerList.add(getComputerFromCursor(c));
try (final Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null)) {
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
computerList.add(getComputerFromCursor(c));
}
return computerList;
}
c.close();
return computerList;
}
public ComputerDetails getComputerByUUID(String uuid) {
Cursor c = computerDb.query(COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?", new String[]{ uuid }, null, null, null);
if (!c.moveToFirst()) {
// No matching computer
c.close();
return null;
try (final Cursor c = computerDb.query(
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
new String[]{ uuid }, null, null, null)
) {
if (!c.moveToFirst()) {
// No matching computer
return null;
}
return getComputerFromCursor(c);
}
ComputerDetails details = getComputerFromCursor(c);
c.close();
return details;
}
}
@@ -64,6 +64,8 @@ public class ComputerManagerService extends Service {
private boolean pollingActive = false;
private final Lock defaultNetworkLock = new ReentrantLock();
private ConnectivityManager.NetworkCallback networkCallback;
private DiscoveryService.DiscoveryBinder discoveryBinder;
private final ServiceConnection discoveryServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder binder) {
@@ -139,7 +141,7 @@ public class ComputerManagerService extends Service {
// then use STUN to populate the external address field if
// it's not set already.
if (details.remoteAddress == null) {
InetAddress addr = InetAddress.getByName(details.activeAddress);
InetAddress addr = InetAddress.getByName(details.activeAddress.address);
if (addr.isSiteLocalAddress()) {
populateExternalAddress(details);
}
@@ -369,7 +371,12 @@ public class ComputerManagerService extends Service {
// Perform the STUN request if we're not on a VPN or if we bound to a network
if (!activeNetworkIsVpn || boundToNetwork) {
details.remoteAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
if (stunResolvedAddress != null) {
// 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.
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
}
}
// Unbind from the network
@@ -396,7 +403,7 @@ public class ComputerManagerService extends Service {
// Populate the computer template with mDNS info
if (computer.getLocalAddress() != null) {
details.localAddress = computer.getLocalAddress().getHostAddress();
details.localAddress = new ComputerDetails.AddressTuple(computer.getLocalAddress().getHostAddress(), computer.getPort());
// Since we're on the same network, we can use STUN to find
// our WAN address, which is also very likely the WAN address
@@ -406,7 +413,7 @@ public class ComputerManagerService extends Service {
}
}
if (computer.getIpv6Address() != null) {
details.ipv6Address = computer.getIpv6Address().getHostAddress();
details.ipv6Address = new ComputerDetails.AddressTuple(computer.getIpv6Address().getHostAddress(), computer.getPort());
}
try {
@@ -424,11 +431,6 @@ public class ComputerManagerService extends Service {
}
}
@Override
public void notifyComputerRemoved(MdnsComputer computer) {
// Nothing to do here
}
@Override
public void notifyDiscoveryFailure(Exception e) {
LimeLog.severe("mDNS discovery failed");
@@ -543,12 +545,21 @@ public class ComputerManagerService extends Service {
}
}
private ComputerDetails tryPollIp(ComputerDetails details, String address) {
private ComputerDetails tryPollIp(ComputerDetails details, ComputerDetails.AddressTuple address) {
try {
NvHTTP http = new NvHTTP(address, idManager.getUniqueId(), details.serverCert,
// If the current address's port number matches the active address's port number, we can also assume
// the HTTPS port will also match. This assumption is currently safe because Sunshine sets all ports
// as offsets from the base HTTP port and doesn't allow custom HttpsPort responses for WAN vs LAN.
boolean portMatchesActiveAddress = details.state == ComputerDetails.State.ONLINE &&
details.activeAddress != null && address.port == details.activeAddress.port;
NvHTTP http = new NvHTTP(address, portMatchesActiveAddress ? details.httpsPort : 0, idManager.getUniqueId(), details.serverCert,
PlatformBinding.getCryptoProvider(ComputerManagerService.this));
ComputerDetails newDetails = http.getComputerDetails();
// If this PC is currently online at this address, extend the timeouts to allow more time for the PC to respond.
boolean isLikelyOnline = details.state == ComputerDetails.State.ONLINE && address.equals(details.activeAddress);
ComputerDetails newDetails = http.getComputerDetails(isLikelyOnline);
// Check if this is the PC we expected
if (newDetails.uuid == null) {
@@ -572,14 +583,14 @@ public class ComputerManagerService extends Service {
}
private static class ParallelPollTuple {
public String address;
public ComputerDetails.AddressTuple address;
public ComputerDetails existingDetails;
public boolean complete;
public Thread pollingThread;
public ComputerDetails returnedDetails;
public ParallelPollTuple(String address, ComputerDetails existingDetails) {
public ParallelPollTuple(ComputerDetails.AddressTuple address, ComputerDetails existingDetails) {
this.address = address;
this.existingDetails = existingDetails;
}
@@ -591,7 +602,7 @@ public class ComputerManagerService extends Service {
}
}
private void startParallelPollThread(ParallelPollTuple tuple, HashSet<String> uniqueAddresses) {
private void startParallelPollThread(ParallelPollTuple tuple, HashSet<ComputerDetails.AddressTuple> uniqueAddresses) {
// Don't bother starting a polling thread for an address that doesn't exist
// or if the address has already been polled with an earlier tuple
if (tuple.address == null || !uniqueAddresses.add(tuple.address)) {
@@ -625,7 +636,7 @@ public class ComputerManagerService extends Service {
// These must be started in order of precedence for the deduplication algorithm
// to result in the correct behavior.
HashSet<String> uniqueAddresses = new HashSet<>();
HashSet<ComputerDetails.AddressTuple> uniqueAddresses = new HashSet<>();
startParallelPollThread(localInfo, uniqueAddresses);
startParallelPollThread(manualInfo, uniqueAddresses);
startParallelPollThread(remoteInfo, uniqueAddresses);
@@ -730,10 +741,49 @@ public class ComputerManagerService extends Service {
}
releaseLocalDatabaseReference();
// Monitor for network changes to invalidate our PC state
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
LimeLog.info("Resetting PC state for new available network");
synchronized (pollingTuples) {
for (PollingTuple tuple : pollingTuples) {
tuple.computer.state = ComputerDetails.State.UNKNOWN;
if (listener != null) {
listener.notifyComputerUpdated(tuple.computer);
}
}
}
}
@Override
public void onLost(Network network) {
LimeLog.info("Offlining PCs due to network loss");
synchronized (pollingTuples) {
for (PollingTuple tuple : pollingTuples) {
tuple.computer.state = ComputerDetails.State.OFFLINE;
if (listener != null) {
listener.notifyComputerUpdated(tuple.computer);
}
}
}
}
};
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
connMgr.registerDefaultNetworkCallback(networkCallback);
}
}
@Override
public void onDestroy() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
connMgr.unregisterNetworkCallback(networkCallback);
}
if (discoveryBinder != null) {
// Unbind from the discovery service
unbindService(discoveryServiceConnection);
@@ -821,7 +871,7 @@ public class ComputerManagerService extends Service {
PollingTuple tuple = getPollingTuple(computer);
try {
NvHTTP http = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer), idManager.getUniqueId(),
NvHTTP http = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer), computer.httpsPort, idManager.getUniqueId(),
computer.serverCert, PlatformBinding.getCryptoProvider(ComputerManagerService.this));
String appList;
@@ -849,18 +899,12 @@ public class ComputerManagerService extends Service {
if (!appList.isEmpty() &&
(!list.isEmpty() || emptyAppListResponses >= EMPTY_LIST_THRESHOLD)) {
// Open the cache file
OutputStream cacheOut = null;
try {
cacheOut = CacheHelper.openCacheFileForOutput(getCacheDir(), "applist", computer.uuid);
try (final OutputStream cacheOut = CacheHelper.openCacheFileForOutput(
getCacheDir(), "applist", computer.uuid)
) {
CacheHelper.writeStringToOutputStream(cacheOut, appList);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (cacheOut != null) {
cacheOut.close();
}
} catch (IOException ignored) {}
}
// Reset empty count if it wasn't empty this time
@@ -33,12 +33,11 @@ public class IdentityManager {
private static String loadUniqueId(Context c) {
// 2 Hex digits per byte
char[] uid = new char[UID_SIZE_IN_BYTES * 2];
InputStreamReader reader = null;
LimeLog.info("Reading UID from disk");
try {
reader = new InputStreamReader(c.openFileInput(UNIQUE_ID_FILE_NAME));
if (reader.read(uid) != UID_SIZE_IN_BYTES * 2)
{
try (final InputStreamReader reader =
new InputStreamReader(c.openFileInput(UNIQUE_ID_FILE_NAME))
) {
if (reader.read(uid) != UID_SIZE_IN_BYTES * 2) {
LimeLog.severe("UID file data is truncated");
return null;
}
@@ -50,12 +49,6 @@ public class IdentityManager {
LimeLog.severe("Error while reading UID file");
e.printStackTrace();
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignored) {}
}
}
}
@@ -64,20 +57,14 @@ public class IdentityManager {
LimeLog.info("Generating new UID");
String uidStr = String.format((Locale)null, "%016x", new Random().nextLong());
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(c.openFileOutput(UNIQUE_ID_FILE_NAME, 0));
try (final OutputStreamWriter writer =
new OutputStreamWriter(c.openFileOutput(UNIQUE_ID_FILE_NAME, 0))
) {
writer.write(uidStr);
LimeLog.info("UID written to disk");
} catch (IOException e) {
LimeLog.severe("Error while writing UID file");
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();
} catch (IOException ignored) {}
}
}
// We can return a UID even if I/O fails
@@ -7,6 +7,7 @@ import android.database.sqlite.SQLiteException;
import com.limelight.LimeLog;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvHTTP;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -30,26 +31,26 @@ public class LegacyDatabaseReader {
// too. To disambiguate, we'll need to prefix them with a string
// greater than the allowable IP address length.
try {
details.localAddress = InetAddress.getByAddress(c.getBlob(2)).getHostAddress();
details.localAddress = new ComputerDetails.AddressTuple(InetAddress.getByAddress(c.getBlob(2)).getHostAddress(), NvHTTP.DEFAULT_HTTP_PORT);
LimeLog.warning("DB: Legacy local address for " + details.name);
} catch (UnknownHostException e) {
// This is probably a hostname/address with the prefix string
String stringData = c.getString(2);
if (stringData.startsWith(ADDRESS_PREFIX)) {
details.localAddress = c.getString(2).substring(ADDRESS_PREFIX.length());
details.localAddress = new ComputerDetails.AddressTuple(c.getString(2).substring(ADDRESS_PREFIX.length()), NvHTTP.DEFAULT_HTTP_PORT);
} else {
LimeLog.severe("DB: Corrupted local address for " + details.name);
}
}
try {
details.remoteAddress = InetAddress.getByAddress(c.getBlob(3)).getHostAddress();
details.remoteAddress = new ComputerDetails.AddressTuple(InetAddress.getByAddress(c.getBlob(3)).getHostAddress(), NvHTTP.DEFAULT_HTTP_PORT);
LimeLog.warning("DB: Legacy remote address for " + details.name);
} catch (UnknownHostException e) {
// This is probably a hostname/address with the prefix string
String stringData = c.getString(3);
if (stringData.startsWith(ADDRESS_PREFIX)) {
details.remoteAddress = c.getString(3).substring(ADDRESS_PREFIX.length());
details.remoteAddress = new ComputerDetails.AddressTuple(c.getString(3).substring(ADDRESS_PREFIX.length()), NvHTTP.DEFAULT_HTTP_PORT);
} else {
LimeLog.severe("DB: Corrupted remote address for " + details.name);
}
@@ -68,37 +69,34 @@ public class LegacyDatabaseReader {
}
private static List<ComputerDetails> getAllComputers(SQLiteDatabase db) {
Cursor c = db.rawQuery("SELECT * FROM " + COMPUTER_TABLE_NAME, null);
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
ComputerDetails details = getComputerFromCursor(c);
try (final Cursor c = db.rawQuery("SELECT * FROM " + COMPUTER_TABLE_NAME, null)) {
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
ComputerDetails details = getComputerFromCursor(c);
// If a critical field is corrupt or missing, skip the database entry
if (details.uuid == null) {
continue;
// If a critical field is corrupt or missing, skip the database entry
if (details.uuid == null) {
continue;
}
computerList.add(details);
}
computerList.add(details);
return computerList;
}
c.close();
return computerList;
}
public static List<ComputerDetails> migrateAllComputers(Context c) {
SQLiteDatabase computerDb = null;
try {
try (final SQLiteDatabase computerDb = SQLiteDatabase.openDatabase(
c.getDatabasePath(COMPUTER_DB_NAME).getPath(),
null, SQLiteDatabase.OPEN_READONLY)
) {
// Open the existing database
computerDb = SQLiteDatabase.openDatabase(c.getDatabasePath(COMPUTER_DB_NAME).getPath(), null, SQLiteDatabase.OPEN_READONLY);
return getAllComputers(computerDb);
} catch (SQLiteException e) {
return new LinkedList<ComputerDetails>();
} finally {
// Close and delete the old DB
if (computerDb != null) {
computerDb.close();
}
c.deleteDatabase(COMPUTER_DB_NAME);
}
}
@@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvHTTP;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
@@ -23,9 +24,9 @@ public class LegacyDatabaseReader2 {
details.uuid = c.getString(0);
details.name = c.getString(1);
details.localAddress = c.getString(2);
details.remoteAddress = c.getString(3);
details.manualAddress = c.getString(4);
details.localAddress = new ComputerDetails.AddressTuple(c.getString(2), NvHTTP.DEFAULT_HTTP_PORT);
details.remoteAddress = new ComputerDetails.AddressTuple(c.getString(3), NvHTTP.DEFAULT_HTTP_PORT);
details.manualAddress = new ComputerDetails.AddressTuple(c.getString(4), NvHTTP.DEFAULT_HTTP_PORT);
details.macAddress = c.getString(5);
// This column wasn't always present in the old schema
@@ -49,37 +50,34 @@ public class LegacyDatabaseReader2 {
}
public static List<ComputerDetails> getAllComputers(SQLiteDatabase computerDb) {
Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null);
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
ComputerDetails details = getComputerFromCursor(c);
try (final Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null)) {
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
ComputerDetails details = getComputerFromCursor(c);
// If a critical field is corrupt or missing, skip the database entry
if (details.uuid == null) {
continue;
// If a critical field is corrupt or missing, skip the database entry
if (details.uuid == null) {
continue;
}
computerList.add(details);
}
computerList.add(details);
return computerList;
}
c.close();
return computerList;
}
public static List<ComputerDetails> migrateAllComputers(Context c) {
SQLiteDatabase computerDb = null;
try {
try (final SQLiteDatabase computerDb = SQLiteDatabase.openDatabase(
c.getDatabasePath(COMPUTER_DB_NAME).getPath(),
null, SQLiteDatabase.OPEN_READONLY)
) {
// Open the existing database
computerDb = SQLiteDatabase.openDatabase(c.getDatabasePath(COMPUTER_DB_NAME).getPath(), null, SQLiteDatabase.OPEN_READONLY);
return getAllComputers(computerDb);
} catch (SQLiteException e) {
return new LinkedList<ComputerDetails>();
} finally {
// Close and delete the old DB
if (computerDb != null) {
computerDb.close();
}
c.deleteDatabase(COMPUTER_DB_NAME);
}
}
@@ -0,0 +1,123 @@
package com.limelight.computers;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvHTTP;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.LinkedList;
import java.util.List;
public class LegacyDatabaseReader3 {
private static final String COMPUTER_DB_NAME = "computers3.db";
private static final String COMPUTER_TABLE_NAME = "Computers";
private static final char ADDRESS_DELIMITER = ';';
private static final char PORT_DELIMITER = '_';
private static String readNonEmptyString(String input) {
if (input.isEmpty()) {
return null;
}
return input;
}
private static ComputerDetails.AddressTuple splitAddressToTuple(String input) {
if (input == null) {
return null;
}
String[] parts = input.split(""+PORT_DELIMITER, -1);
if (parts.length == 1) {
return new ComputerDetails.AddressTuple(parts[0], NvHTTP.DEFAULT_HTTP_PORT);
}
else {
return new ComputerDetails.AddressTuple(parts[0], Integer.parseInt(parts[1]));
}
}
private static String splitTupleToAddress(ComputerDetails.AddressTuple tuple) {
return tuple.address+PORT_DELIMITER+tuple.port;
}
private static ComputerDetails getComputerFromCursor(Cursor c) {
ComputerDetails details = new ComputerDetails();
details.uuid = c.getString(0);
details.name = c.getString(1);
String[] addresses = c.getString(2).split(""+ADDRESS_DELIMITER, -1);
details.localAddress = splitAddressToTuple(readNonEmptyString(addresses[0]));
details.remoteAddress = splitAddressToTuple(readNonEmptyString(addresses[1]));
details.manualAddress = splitAddressToTuple(readNonEmptyString(addresses[2]));
details.ipv6Address = splitAddressToTuple(readNonEmptyString(addresses[3]));
// External port is persisted in the remote address field
if (details.remoteAddress != null) {
details.externalPort = details.remoteAddress.port;
}
else {
details.externalPort = NvHTTP.DEFAULT_HTTP_PORT;
}
details.macAddress = c.getString(3);
try {
byte[] derCertData = c.getBlob(4);
if (derCertData != null) {
details.serverCert = (X509Certificate) CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(derCertData));
}
} catch (CertificateException e) {
e.printStackTrace();
}
// This signifies we don't have dynamic state (like pair state)
details.state = ComputerDetails.State.UNKNOWN;
return details;
}
public static List<ComputerDetails> getAllComputers(SQLiteDatabase computerDb) {
try (final Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null)) {
LinkedList<ComputerDetails> computerList = new LinkedList<>();
while (c.moveToNext()) {
ComputerDetails details = getComputerFromCursor(c);
// If a critical field is corrupt or missing, skip the database entry
if (details.uuid == null) {
continue;
}
computerList.add(details);
}
return computerList;
}
}
public static List<ComputerDetails> migrateAllComputers(Context c) {
try (final SQLiteDatabase computerDb = SQLiteDatabase.openDatabase(
c.getDatabasePath(COMPUTER_DB_NAME).getPath(),
null, SQLiteDatabase.OPEN_READONLY)
) {
// Open the existing database
return getAllComputers(computerDb);
} catch (SQLiteException e) {
return new LinkedList<ComputerDetails>();
} finally {
// Close and delete the old DB
c.deleteDatabase(COMPUTER_DB_NAME);
}
}
}
@@ -3,22 +3,21 @@ package com.limelight.discovery;
import java.util.List;
import com.limelight.nvstream.mdns.MdnsComputer;
import com.limelight.nvstream.mdns.JmDNSDiscoveryAgent;
import com.limelight.nvstream.mdns.MdnsDiscoveryAgent;
import com.limelight.nvstream.mdns.MdnsDiscoveryListener;
import com.limelight.nvstream.mdns.NsdManagerDiscoveryAgent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.MulticastLock;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
public class DiscoveryService extends Service {
private MdnsDiscoveryAgent discoveryAgent;
private MdnsDiscoveryListener boundListener;
private MulticastLock multicastLock;
public class DiscoveryBinder extends Binder {
public void setListener(MdnsDiscoveryListener listener) {
@@ -26,13 +25,11 @@ public class DiscoveryService extends Service {
}
public void startDiscovery(int queryIntervalMs) {
multicastLock.acquire();
discoveryAgent.startDiscovery(queryIntervalMs);
}
public void stopDiscovery() {
discoveryAgent.stopDiscovery();
multicastLock.release();
}
public List<MdnsComputer> getComputerSet() {
@@ -42,11 +39,7 @@ public class DiscoveryService extends Service {
@Override
public void onCreate() {
WifiManager wifiMgr = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
multicastLock = wifiMgr.createMulticastLock("Limelight mDNS");
multicastLock.setReferenceCounted(false);
discoveryAgent = new MdnsDiscoveryAgent(new MdnsDiscoveryListener() {
MdnsDiscoveryListener listener = new MdnsDiscoveryListener() {
@Override
public void notifyComputerAdded(MdnsComputer computer) {
if (boundListener != null) {
@@ -54,20 +47,28 @@ public class DiscoveryService extends Service {
}
}
@Override
public void notifyComputerRemoved(MdnsComputer computer) {
if (boundListener != null) {
boundListener.notifyComputerRemoved(computer);
}
}
@Override
public void notifyDiscoveryFailure(Exception e) {
if (boundListener != null) {
boundListener.notifyDiscoveryFailure(e);
}
}
});
};
// Prior to Android 14, NsdManager doesn't provide all the capabilities needed for parity
// with jmDNS (specifically handling multiple addresses for a single service). There are
// also documented reliability bugs early in the Android 4.x series shortly after it was
// introduced. The benefit of using NsdManager over jmDNS is that it works correctly in
// environments where mDNS proxying is required, like ChromeOS, WSA, and the emulator.
//
// As such, we use the jmDNS-based MdnsDiscoveryAgent prior to Android 14 and NsdManager
// on Android 14 and above.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
discoveryAgent = new JmDNSDiscoveryAgent(getApplicationContext(), listener);
}
else {
discoveryAgent = new NsdManagerDiscoveryAgent(getApplicationContext(), listener);
}
}
private final DiscoveryBinder binder = new DiscoveryBinder();
@@ -81,7 +82,6 @@ public class DiscoveryService extends Service {
public boolean onUnbind(Intent intent) {
// Stop any discovery session
discoveryAgent.stopDiscovery();
multicastLock.release();
// Unbind the listener
boundListener = null;
@@ -154,21 +154,15 @@ public class DiskAssetLoader {
}
public void populateCacheWithStream(CachedAppAssetLoader.LoaderTuple tuple, InputStream input) {
OutputStream out = null;
boolean success = false;
try {
out = CacheHelper.openCacheFileForOutput(cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
try (final OutputStream out = CacheHelper.openCacheFileForOutput(
cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png")
) {
CacheHelper.writeInputStreamToOutputStream(input, out, MAX_ASSET_SIZE);
success = true;
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException ignored) {}
}
if (!success) {
LimeLog.warning("Unable to populate cache with tuple: "+tuple);
CacheHelper.deleteCacheFile(cacheDir, "boxart", tuple.computer.uuid, tuple.app.getAppId() + ".png");
@@ -22,8 +22,9 @@ public class NetworkAssetLoader {
public InputStream getBitmapStream(CachedAppAssetLoader.LoaderTuple tuple) {
InputStream in = null;
try {
NvHTTP http = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(tuple.computer), uniqueId,
tuple.computer.serverCert, PlatformBinding.getCryptoProvider(context));
NvHTTP http = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(tuple.computer),
tuple.computer.httpsPort, uniqueId, tuple.computer.serverCert,
PlatformBinding.getCryptoProvider(context));
in = http.getBoxArt(tuple.app);
} catch (IOException ignored) {}
@@ -1,11 +1,15 @@
package com.limelight.nvstream;
import com.limelight.nvstream.http.ComputerDetails;
import java.security.cert.X509Certificate;
import javax.crypto.SecretKey;
public class ConnectionContext {
public String serverAddress;
public ComputerDetails.AddressTuple serverAddress;
public int httpsPort;
public boolean isNvidiaServerSoftware;
public X509Certificate serverCert;
public StreamConfiguration streamConfig;
public NvConnectionListener connListener;
@@ -15,6 +19,7 @@ public class ConnectionContext {
// This is the version quad from the appversion tag of /serverinfo
public String serverAppVersion;
public String serverGfeVersion;
public int serverCodecModeSupport;
// This is the sessionUrl0 tag from /resume and /launch
public String rtspSessionUrl;
@@ -22,5 +27,8 @@ public class ConnectionContext {
public int negotiatedWidth, negotiatedHeight;
public boolean negotiatedHdr;
public int negotiatedRemoteStreaming;
public int negotiatedPacketSize;
public int videoCapabilities;
}
@@ -1,8 +1,20 @@
package com.limelight.nvstream;
import android.app.ActivityManager;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.IpPrefix;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.RouteInfo;
import android.os.Build;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -19,7 +31,8 @@ import org.xmlpull.v1.XmlPullParserException;
import com.limelight.LimeLog;
import com.limelight.nvstream.av.audio.AudioRenderer;
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.http.GfeHttpResponseException;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.HostHttpResponseException;
import com.limelight.nvstream.http.LimelightCryptoProvider;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
@@ -29,34 +42,28 @@ import com.limelight.nvstream.jni.MoonBridge;
public class NvConnection {
// Context parameters
private String host;
private LimelightCryptoProvider cryptoProvider;
private String uniqueId;
private ConnectionContext context;
private static Semaphore connectionAllowed = new Semaphore(1);
private final boolean isMonkey;
private final boolean batchMouseInput;
private final Context appContext;
private static final int MOUSE_BATCH_PERIOD_MS = 5;
private Timer mouseInputTimer;
private final Object mouseInputLock = new Object();
private short relMouseX, relMouseY, relMouseWidth, relMouseHeight;
private short absMouseX, absMouseY, absMouseWidth, absMouseHeight;
public NvConnection(String host, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert, boolean batchMouseInput)
{
this.host = host;
public NvConnection(Context appContext, ComputerDetails.AddressTuple host, int httpsPort, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert)
{
this.appContext = appContext;
this.cryptoProvider = cryptoProvider;
this.uniqueId = uniqueId;
this.batchMouseInput = batchMouseInput;
this.context = new ConnectionContext();
this.context.serverAddress = host;
this.context.httpsPort = httpsPort;
this.context.streamConfig = config;
this.context.serverCert = serverCert;
// This is unique per connection
this.context.riKey = generateRiAesKey();
context.riKeyId = generateRiKeyId();
this.context.riKeyId = generateRiKeyId();
this.isMonkey = ActivityManager.isUserAMonkey();
}
@@ -80,11 +87,6 @@ public class NvConnection {
}
public void stop() {
// Stop sending additional input
if (mouseInputTimer != null) {
mouseInputTimer.cancel();
}
// Interrupt any pending connection. This is thread-safe.
MoonBridge.interruptConnection();
@@ -99,29 +101,129 @@ public class NvConnection {
connectionAllowed.release();
}
private void flushMousePosition() {
synchronized (mouseInputLock) {
if (relMouseX != 0 || relMouseY != 0) {
if (relMouseWidth != 0 || relMouseHeight != 0) {
MoonBridge.sendMouseMoveAsMousePosition(relMouseX, relMouseY, relMouseWidth, relMouseHeight);
}
else {
MoonBridge.sendMouseMove(relMouseX, relMouseY);
}
relMouseX = relMouseY = relMouseWidth = relMouseHeight = 0;
}
if (absMouseX != 0 || absMouseY != 0 || absMouseWidth != 0 || absMouseHeight != 0) {
MoonBridge.sendMousePosition(absMouseX, absMouseY, absMouseWidth, absMouseHeight);
absMouseX = absMouseY = absMouseWidth = absMouseHeight = 0;
private InetAddress resolveServerAddress() throws IOException {
// Try to find an address that works for this host
InetAddress[] addrs = InetAddress.getAllByName(context.serverAddress.address);
for (InetAddress addr : addrs) {
try (Socket s = new Socket()) {
s.setSoLinger(true, 0);
s.connect(new InetSocketAddress(addr, context.serverAddress.port), 1000);
return addr;
} catch (IOException e) {
e.printStackTrace();
}
}
// If we made it here, we didn't manage to find a working address. If DNS returned any
// address, we'll use the first available address and hope for the best.
if (addrs.length > 0) {
return addrs[0];
}
else {
throw new IOException("No addresses found for "+context.serverAddress);
}
}
private int detectServerConnectionType() {
ConnectivityManager connMgr = (ConnectivityManager) appContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Network activeNetwork = connMgr.getActiveNetwork();
if (activeNetwork != null) {
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(activeNetwork);
if (netCaps != null) {
if (netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
!netCaps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)) {
// VPNs are treated as remote connections
return StreamConfiguration.STREAM_CFG_REMOTE;
}
else if (netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
// Cellular is always treated as remote to avoid any possible
// issues with 464XLAT or similar technologies.
return StreamConfiguration.STREAM_CFG_REMOTE;
}
}
// Check if the server address is on-link
LinkProperties linkProperties = connMgr.getLinkProperties(activeNetwork);
if (linkProperties != null) {
InetAddress serverAddress;
try {
serverAddress = resolveServerAddress();
} catch (IOException e) {
e.printStackTrace();
// We can't decide without being able to resolve the server address
return StreamConfiguration.STREAM_CFG_AUTO;
}
// If the address is in the NAT64 prefix, always treat it as remote
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
IpPrefix nat64Prefix = linkProperties.getNat64Prefix();
if (nat64Prefix != null && nat64Prefix.contains(serverAddress)) {
return StreamConfiguration.STREAM_CFG_REMOTE;
}
}
for (RouteInfo route : linkProperties.getRoutes()) {
// Skip non-unicast routes (which are all we get prior to Android 13)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && route.getType() != RouteInfo.RTN_UNICAST) {
continue;
}
// Find the first route that matches this address
if (route.matches(serverAddress)) {
// If there's no gateway, this is an on-link destination
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// We want to use hasGateway() because getGateway() doesn't adhere
// to documented behavior of returning null for on-link addresses.
if (!route.hasGateway()) {
return StreamConfiguration.STREAM_CFG_LOCAL;
}
}
else {
// getGateway() is documented to return null for on-link destinations,
// but it actually returns the unspecified address (0.0.0.0 or ::).
InetAddress gateway = route.getGateway();
if (gateway == null || gateway.isAnyLocalAddress()) {
return StreamConfiguration.STREAM_CFG_LOCAL;
}
}
// We _should_ stop after the first matching route, but for some reason
// Android doesn't always report IPv6 routes in descending order of
// specificity and metric. To handle that case, we enumerate all matching
// routes, assuming that an on-link route will always be preferred.
}
}
}
}
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
if (activeNetworkInfo != null) {
switch (activeNetworkInfo.getType()) {
case ConnectivityManager.TYPE_VPN:
case ConnectivityManager.TYPE_MOBILE:
case ConnectivityManager.TYPE_MOBILE_DUN:
case ConnectivityManager.TYPE_MOBILE_HIPRI:
case ConnectivityManager.TYPE_MOBILE_MMS:
case ConnectivityManager.TYPE_MOBILE_SUPL:
case ConnectivityManager.TYPE_WIMAX:
// VPNs and cellular connections are always remote connections
return StreamConfiguration.STREAM_CFG_REMOTE;
}
}
}
// If we can't determine the connection type, let moonlight-common-c decide.
return StreamConfiguration.STREAM_CFG_AUTO;
}
private boolean startApp() throws XmlPullParserException, IOException
{
NvHTTP h = new NvHTTP(context.serverAddress, uniqueId, context.serverCert, cryptoProvider);
NvHTTP h = new NvHTTP(context.serverAddress, context.httpsPort, uniqueId, context.serverCert, cryptoProvider);
String serverInfo = h.getServerInfo();
String serverInfo = h.getServerInfo(true);
context.serverAppVersion = h.getServerVersion(serverInfo);
if (context.serverAppVersion == null) {
@@ -129,6 +231,9 @@ public class NvConnection {
return false;
}
ComputerDetails details = h.getComputerDetails(serverInfo);
context.isNvidiaServerSoftware = details.nvidiaServer;
// May be missing for older servers
context.serverGfeVersion = h.getGfeVersion(serverInfo);
@@ -137,9 +242,11 @@ public class NvConnection {
return false;
}
context.negotiatedHdr = context.streamConfig.getEnableHdr();
if ((h.getServerCodecModeSupport(serverInfo) & 0x200) == 0 && context.negotiatedHdr) {
context.connListener.displayTransientMessage("Your GPU does not support streaming HDR. The stream will be SDR.");
context.serverCodecModeSupport = (int)h.getServerCodecModeSupport(serverInfo);
context.negotiatedHdr = (context.streamConfig.getSupportedVideoFormats() & MoonBridge.VIDEO_FORMAT_MASK_10BIT) != 0;
if ((context.serverCodecModeSupport & 0x20200) == 0 && context.negotiatedHdr) {
context.connListener.displayTransientMessage("Your PC GPU does not support streaming HDR. The stream will be SDR.");
context.negotiatedHdr = false;
}
@@ -149,13 +256,13 @@ public class NvConnection {
// Check for a supported stream resolution
if ((context.streamConfig.getWidth() > 4096 || context.streamConfig.getHeight() > 4096) &&
(h.getServerCodecModeSupport(serverInfo) & 0x200) == 0) {
(h.getServerCodecModeSupport(serverInfo) & 0x200) == 0 && context.isNvidiaServerSoftware) {
context.connListener.displayMessage("Your host PC does not support streaming at resolutions above 4K.");
return false;
}
else if ((context.streamConfig.getWidth() > 4096 || context.streamConfig.getHeight() > 4096) &&
!context.streamConfig.getHevcSupported()) {
context.connListener.displayMessage("Your streaming device must support HEVC to stream at resolutions above 4K.");
(context.streamConfig.getSupportedVideoFormats() & ~MoonBridge.VIDEO_FORMAT_MASK_H264) == 0) {
context.connListener.displayMessage("Your streaming device must support HEVC or AV1 to stream at resolutions above 4K.");
return false;
}
else if (context.streamConfig.getHeight() >= 2160 && !h.supports4K(serverInfo)) {
@@ -171,6 +278,18 @@ public class NvConnection {
context.negotiatedWidth = context.streamConfig.getWidth();
context.negotiatedHeight = context.streamConfig.getHeight();
}
// We will perform some connection type detection if the caller asked for it
if (context.streamConfig.getRemote() == StreamConfiguration.STREAM_CFG_AUTO) {
context.negotiatedRemoteStreaming = detectServerConnectionType();
context.negotiatedPacketSize =
context.negotiatedRemoteStreaming == StreamConfiguration.STREAM_CFG_REMOTE ?
1024 : context.streamConfig.getMaxPacketSize();
}
else {
context.negotiatedRemoteStreaming = context.streamConfig.getRemote();
context.negotiatedPacketSize = context.streamConfig.getMaxPacketSize();
}
//
// Video stream format will be decided during the RTSP handshake
@@ -192,14 +311,14 @@ public class NvConnection {
if (h.getCurrentGame(serverInfo) != 0) {
try {
if (h.getCurrentGame(serverInfo) == app.getAppId()) {
if (!h.resumeApp(context)) {
if (!h.launchApp(context, "resume", app.getAppId(), context.negotiatedHdr)) {
context.connListener.displayMessage("Failed to resume existing session");
return false;
}
} else {
return quitAndLaunch(h, context);
}
} catch (GfeHttpResponseException e) {
} catch (HostHttpResponseException e) {
if (e.getErrorCode() == 470) {
// This is the error you get when you try to resume a session that's not yours.
// Because this is fairly common, we'll display a more detailed message.
@@ -232,7 +351,7 @@ public class NvConnection {
context.connListener.displayMessage("Failed to quit previous session! You must quit it manually");
return false;
}
} catch (GfeHttpResponseException e) {
} catch (HostHttpResponseException e) {
if (e.getErrorCode() == 599) {
context.connListener.displayMessage("This session wasn't started by this device," +
" so it cannot be quit. End streaming on the original " +
@@ -250,7 +369,7 @@ public class NvConnection {
private boolean launchNotRunningApp(NvHTTP h, ConnectionContext context)
throws IOException, XmlPullParserException {
// Launch the app since it's not running
if (!h.launchApp(context, context.streamConfig.getApp().getAppId(), context.negotiatedHdr)) {
if (!h.launchApp(context, "launch", context.streamConfig.getApp().getAppId(), context.negotiatedHdr)) {
context.connListener.displayMessage("Failed to launch application");
return false;
}
@@ -269,7 +388,6 @@ public class NvConnection {
String appName = context.streamConfig.getApp().getAppName();
context.serverAddress = host;
context.connListener.stageStarting(appName);
try {
@@ -278,7 +396,7 @@ public class NvConnection {
return;
}
context.connListener.stageComplete(appName);
} catch (GfeHttpResponseException e) {
} catch (HostHttpResponseException e) {
e.printStackTrace();
context.connListener.displayMessage(e.getMessage());
context.connListener.stageFailed(appName, 0, e.getErrorCode());
@@ -307,19 +425,22 @@ public class NvConnection {
// we must not invoke that functionality in parallel.
synchronized (MoonBridge.class) {
MoonBridge.setupBridge(videoDecoderRenderer, audioRenderer, connectionListener);
int ret = MoonBridge.startConnection(context.serverAddress,
int ret = MoonBridge.startConnection(context.serverAddress.address,
context.serverAppVersion, context.serverGfeVersion, context.rtspSessionUrl,
context.serverCodecModeSupport,
context.negotiatedWidth, context.negotiatedHeight,
context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(),
context.streamConfig.getMaxPacketSize(),
context.streamConfig.getRemote(), context.streamConfig.getAudioConfiguration().toInt(),
context.streamConfig.getHevcSupported(),
context.negotiatedHdr,
context.negotiatedPacketSize, context.negotiatedRemoteStreaming,
context.streamConfig.getAudioConfiguration().toInt(),
context.streamConfig.getSupportedVideoFormats(),
context.streamConfig.getHevcBitratePercentageMultiplier(),
context.streamConfig.getAv1BitratePercentageMultiplier(),
context.streamConfig.getClientRefreshRateX100(),
context.streamConfig.getEncryptionFlags(),
context.riKey.getEncoded(), ib.array(),
context.videoCapabilities);
context.videoCapabilities,
context.streamConfig.getColorSpace(),
context.streamConfig.getColorRange());
if (ret != 0) {
// LiStartConnection() failed, so the caller is not expected
// to stop the connection themselves. We need to release their
@@ -327,20 +448,6 @@ public class NvConnection {
connectionAllowed.release();
return;
}
if (batchMouseInput) {
// High polling rate mice can cause GeForce Experience's input queue to get backed up,
// causing massive input latency. We counter this by limiting our mouse events to 200 Hz
// which appears to avoid triggering the issue on all known configurations.
mouseInputTimer = new Timer("MouseInput", true);
mouseInputTimer.schedule(new TimerTask() {
@Override
public void run() {
// Flush the mouse position every 5 ms
flushMousePosition();
}
}, MOUSE_BATCH_PERIOD_MS, MOUSE_BATCH_PERIOD_MS);
}
}
}
}).start();
@@ -349,65 +456,27 @@ public class NvConnection {
public void sendMouseMove(final short deltaX, final short deltaY)
{
if (!isMonkey) {
synchronized (mouseInputLock) {
relMouseX += deltaX;
relMouseY += deltaY;
// Reset these to ensure we don't send this as a position update
relMouseWidth = 0;
relMouseHeight = 0;
}
if (!batchMouseInput) {
flushMousePosition();
}
MoonBridge.sendMouseMove(deltaX, deltaY);
}
}
public void sendMousePosition(short x, short y, short referenceWidth, short referenceHeight)
{
if (!isMonkey) {
synchronized (mouseInputLock) {
absMouseX = x;
absMouseY = y;
absMouseWidth = referenceWidth;
absMouseHeight = referenceHeight;
}
if (!batchMouseInput) {
flushMousePosition();
}
MoonBridge.sendMousePosition(x, y, referenceWidth, referenceHeight);
}
}
public void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight)
{
if (!isMonkey) {
synchronized (mouseInputLock) {
// Only accumulate the delta if the reference size is the same
if (relMouseWidth == referenceWidth && relMouseHeight == referenceHeight) {
relMouseX += deltaX;
relMouseY += deltaY;
}
else {
relMouseX = deltaX;
relMouseY = deltaY;
}
relMouseWidth = referenceWidth;
relMouseHeight = referenceHeight;
}
if (!batchMouseInput) {
flushMousePosition();
}
MoonBridge.sendMouseMoveAsMousePosition(deltaX, deltaY, referenceWidth, referenceHeight);
}
}
public void sendMouseButtonDown(final byte mouseButton)
{
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseButton(MouseButtonPacket.PRESS_EVENT, mouseButton);
}
}
@@ -415,13 +484,12 @@ public class NvConnection {
public void sendMouseButtonUp(final byte mouseButton)
{
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseButton(MouseButtonPacket.RELEASE_EVENT, mouseButton);
}
}
public void sendControllerInput(final short controllerNumber,
final short activeGamepadMask, final short buttonFlags,
final short activeGamepadMask, final int buttonFlags,
final byte leftTrigger, final byte rightTrigger,
final short leftStickX, final short leftStickY,
final short rightStickX, final short rightStickY)
@@ -431,38 +499,89 @@ public class NvConnection {
leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
}
}
public void sendControllerInput(final short buttonFlags,
final byte leftTrigger, final byte rightTrigger,
final short leftStickX, final short leftStickY,
final short rightStickX, final short rightStickY)
{
public void sendKeyboardInput(final short keyMap, final byte keyDirection, final byte modifier, final byte flags) {
if (!isMonkey) {
MoonBridge.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX,
leftStickY, rightStickX, rightStickY);
}
}
public void sendKeyboardInput(final short keyMap, final byte keyDirection, final byte modifier) {
if (!isMonkey) {
MoonBridge.sendKeyboardInput(keyMap, keyDirection, modifier);
MoonBridge.sendKeyboardInput(keyMap, keyDirection, modifier, flags);
}
}
public void sendMouseScroll(final byte scrollClicks) {
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseScroll(scrollClicks);
MoonBridge.sendMouseHighResScroll((short)(scrollClicks * 120)); // WHEEL_DELTA
}
}
public void sendMouseHScroll(final byte scrollClicks) {
if (!isMonkey) {
MoonBridge.sendMouseHighResHScroll((short)(scrollClicks * 120)); // WHEEL_DELTA
}
}
public void sendMouseHighResScroll(final short scrollAmount) {
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseHighResScroll(scrollAmount);
}
}
public void sendMouseHighResHScroll(final short scrollAmount) {
if (!isMonkey) {
MoonBridge.sendMouseHighResHScroll(scrollAmount);
}
}
public int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressureOrDistance,
float contactAreaMajor, float contactAreaMinor, short rotation) {
if (!isMonkey) {
return MoonBridge.sendTouchEvent(eventType, pointerId, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;
}
}
public int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
float pressureOrDistance, float contactAreaMajor, float contactAreaMinor,
short rotation, byte tilt) {
if (!isMonkey) {
return MoonBridge.sendPenEvent(eventType, toolType, penButtons, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation, tilt);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;
}
}
public int sendControllerArrivalEvent(byte controllerNumber, short activeGamepadMask, byte type,
int supportedButtonFlags, short capabilities) {
return MoonBridge.sendControllerArrivalEvent(controllerNumber, activeGamepadMask, type, supportedButtonFlags, capabilities);
}
public int sendControllerTouchEvent(byte controllerNumber, byte eventType, int pointerId,
float x, float y, float pressure) {
if (!isMonkey) {
return MoonBridge.sendControllerTouchEvent(controllerNumber, eventType, pointerId, x, y, pressure);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;
}
}
public int sendControllerMotionEvent(byte controllerNumber, byte motionType,
float x, float y, float z) {
if (!isMonkey) {
return MoonBridge.sendControllerMotionEvent(controllerNumber, motionType, x, y, z);
}
else {
return MoonBridge.LI_ERR_UNSUPPORTED;
}
}
public void sendControllerBatteryEvent(byte controllerNumber, byte batteryState, byte batteryPercentage) {
MoonBridge.sendControllerBatteryEvent(controllerNumber, batteryState, batteryPercentage);
}
public void sendUtf8Text(final String text) {
if (!isMonkey) {
MoonBridge.sendUtf8Text(text);
@@ -13,6 +13,11 @@ public interface NvConnectionListener {
void displayTransientMessage(String message);
void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor);
void rumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger);
void setHdrMode(boolean enabled);
void setHdrMode(boolean enabled, byte[] hdrMetadata);
void setMotionEventState(short controllerNumber, byte motionType, short reportRateHz);
void setControllerLED(short controllerNumber, byte r, byte g, byte b);
}
@@ -22,11 +22,14 @@ public class StreamConfiguration {
private int maxPacketSize;
private int remote;
private MoonBridge.AudioConfiguration audioConfiguration;
private boolean supportsHevc;
private int supportedVideoFormats;
private int hevcBitratePercentageMultiplier;
private boolean enableHdr;
private int av1BitratePercentageMultiplier;
private int attachedGamepadMask;
private int encryptionFlags;
private int colorRange;
private int colorSpace;
private boolean persistGamepadsAfterDisconnect;
public static class Builder {
private StreamConfiguration config = new StreamConfiguration();
@@ -87,8 +90,8 @@ public class StreamConfiguration {
return this;
}
public StreamConfiguration.Builder setEnableHdr(boolean enableHdr) {
config.enableHdr = enableHdr;
public StreamConfiguration.Builder setAv1BitratePercentageMultiplier(int multiplier) {
config.av1BitratePercentageMultiplier = multiplier;
return this;
}
@@ -107,6 +110,11 @@ public class StreamConfiguration {
return this;
}
public StreamConfiguration.Builder setPersistGamepadsAfterDisconnect(boolean value) {
config.persistGamepadsAfterDisconnect = value;
return this;
}
public StreamConfiguration.Builder setClientRefreshRateX100(int refreshRateX100) {
config.clientRefreshRateX100 = refreshRateX100;
return this;
@@ -127,11 +135,21 @@ public class StreamConfiguration {
return this;
}
public StreamConfiguration.Builder setHevcSupported(boolean supportsHevc) {
config.supportsHevc = supportsHevc;
public StreamConfiguration.Builder setSupportedVideoFormats(int supportedVideoFormats) {
config.supportedVideoFormats = supportedVideoFormats;
return this;
}
public StreamConfiguration.Builder setColorRange(int colorRange) {
config.colorRange = colorRange;
return this;
}
public StreamConfiguration.Builder setColorSpace(int colorSpace) {
config.colorSpace = colorSpace;
return this;
}
public StreamConfiguration build() {
return config;
}
@@ -150,8 +168,7 @@ public class StreamConfiguration {
this.sops = true;
this.enableAdaptiveResolution = false;
this.audioConfiguration = MoonBridge.AUDIO_CONFIGURATION_STEREO;
this.supportsHevc = false;
this.enableHdr = false;
this.supportedVideoFormats = MoonBridge.VIDEO_FORMAT_H264;
this.attachedGamepadMask = 0;
}
@@ -203,22 +220,26 @@ public class StreamConfiguration {
return audioConfiguration;
}
public boolean getHevcSupported() {
return supportsHevc;
public int getSupportedVideoFormats() {
return supportedVideoFormats;
}
public int getHevcBitratePercentageMultiplier() {
return hevcBitratePercentageMultiplier;
}
public boolean getEnableHdr() {
return enableHdr;
public int getAv1BitratePercentageMultiplier() {
return av1BitratePercentageMultiplier;
}
public int getAttachedGamepadMask() {
return attachedGamepadMask;
}
public boolean getPersistGamepadsAfterDisconnect() {
return persistGamepadsAfterDisconnect;
}
public int getClientRefreshRateX100() {
return clientRefreshRateX100;
}
@@ -226,4 +247,12 @@ public class StreamConfiguration {
public int getEncryptionFlags() {
return encryptionFlags;
}
public int getColorRange() {
return colorRange;
}
public int getColorSpace() {
return colorSpace;
}
}
@@ -10,11 +10,12 @@ public abstract class VideoDecoderRenderer {
// This is called once for each frame-start NALU. This means it will be called several times
// for an IDR frame which contains several parameter sets and the I-frame data.
public abstract int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
int frameNumber, int frameType, long receiveTimeMs, long enqueueTimeMs);
int frameNumber, int frameType, char frameHostProcessingLatency,
long receiveTimeMs, long enqueueTimeMs);
public abstract void cleanup();
public abstract int getCapabilities();
public abstract void setHdrMode(boolean enabled);
public abstract void setHdrMode(boolean enabled, byte[] hdrMetadata);
}
@@ -1,6 +1,7 @@
package com.limelight.nvstream.http;
import java.security.cert.X509Certificate;
import java.util.Objects;
public class ComputerDetails {
@@ -8,22 +9,73 @@ public class ComputerDetails {
ONLINE, OFFLINE, UNKNOWN
}
public static class AddressTuple {
public String address;
public int port;
public AddressTuple(String address, int port) {
if (address == null) {
throw new IllegalArgumentException("Address cannot be null");
}
if (port <= 0) {
throw new IllegalArgumentException("Invalid port");
}
// If this was an escaped IPv6 address, remove the brackets
if (address.startsWith("[") && address.endsWith("]")) {
address = address.substring(1, address.length() - 1);
}
this.address = address;
this.port = port;
}
@Override
public int hashCode() {
return Objects.hash(address, port);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AddressTuple)) {
return false;
}
AddressTuple that = (AddressTuple) obj;
return address.equals(that.address) && port == that.port;
}
public String toString() {
if (address.contains(":")) {
// IPv6
return "[" + address + "]:" + port;
}
else {
// IPv4 and hostnames
return address + ":" + port;
}
}
}
// Persistent attributes
public String uuid;
public String name;
public String localAddress;
public String remoteAddress;
public String manualAddress;
public String ipv6Address;
public AddressTuple localAddress;
public AddressTuple remoteAddress;
public AddressTuple manualAddress;
public AddressTuple ipv6Address;
public String macAddress;
public X509Certificate serverCert;
// Transient attributes
public State state;
public String activeAddress;
public AddressTuple activeAddress;
public int httpsPort;
public int externalPort;
public PairingManager.PairState pairState;
public int runningGameId;
public String rawAppList;
public boolean nvidiaServer;
public ComputerDetails() {
// Use defaults
@@ -35,6 +87,27 @@ public class ComputerDetails {
update(details);
}
public int guessExternalPort() {
if (externalPort != 0) {
return externalPort;
}
else if (remoteAddress != null) {
return remoteAddress.port;
}
else if (activeAddress != null) {
return activeAddress.port;
}
else if (ipv6Address != null) {
return ipv6Address.port;
}
else if (localAddress != null) {
return localAddress.port;
}
else {
return NvHTTP.DEFAULT_HTTP_PORT;
}
}
public void update(ComputerDetails details) {
this.state = details.state;
this.name = details.name;
@@ -43,12 +116,18 @@ public class ComputerDetails {
this.activeAddress = details.activeAddress;
}
// We can get IPv4 loopback addresses with GS IPv6 Forwarder
if (details.localAddress != null && !details.localAddress.startsWith("127.")) {
if (details.localAddress != null && !details.localAddress.address.startsWith("127.")) {
this.localAddress = details.localAddress;
}
if (details.remoteAddress != null) {
this.remoteAddress = details.remoteAddress;
}
else if (this.remoteAddress != null && details.externalPort != 0) {
// If we have a remote address already (perhaps via STUN) but our updated details
// don't have a new one (because GFE doesn't send one), propagate the external
// port to the current remote address. We may have tried to guess it previously.
this.remoteAddress.port = details.externalPort;
}
if (details.manualAddress != null) {
this.manualAddress = details.manualAddress;
}
@@ -61,8 +140,11 @@ public class ComputerDetails {
if (details.serverCert != null) {
this.serverCert = details.serverCert;
}
this.externalPort = details.externalPort;
this.httpsPort = details.httpsPort;
this.pairState = details.pairState;
this.runningGameId = details.runningGameId;
this.nvidiaServer = details.nvidiaServer;
this.rawAppList = details.rawAppList;
}
@@ -80,6 +162,7 @@ public class ComputerDetails {
str.append("MAC Address: ").append(macAddress).append("\n");
str.append("Pair State: ").append(pairState).append("\n");
str.append("Running Game ID: ").append(runningGameId).append("\n");
str.append("HTTPS Port: ").append(httpsPort).append("\n");
return str.toString();
}
}
@@ -2,13 +2,13 @@ package com.limelight.nvstream.http;
import java.io.IOException;
public class GfeHttpResponseException extends IOException {
public class HostHttpResponseException extends IOException {
private static final long serialVersionUID = 1543508830807804222L;
private int errorCode;
private String errorMsg;
public GfeHttpResponseException(int errorCode, String errorMsg) {
public HostHttpResponseException(int errorCode, String errorMsg) {
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
@@ -23,6 +23,6 @@ public class GfeHttpResponseException extends IOException {
@Override
public String getMessage() {
return "GeForce Experience returned error: "+errorMsg+" (Error code: "+errorCode+")";
return "Host PC returned error: "+errorMsg+" (Error code: "+errorCode+")";
}
}
@@ -8,6 +8,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.Socket;
@@ -62,19 +63,22 @@ public class NvHTTP {
private String uniqueId;
private PairingManager pm;
public static final int HTTPS_PORT = 47984;
public static final int HTTP_PORT = 47989;
public static final int CONNECTION_TIMEOUT = 3000;
public static final int READ_TIMEOUT = 5000;
private static final int DEFAULT_HTTPS_PORT = 47984;
public static final int DEFAULT_HTTP_PORT = 47989;
public static final int SHORT_CONNECTION_TIMEOUT = 3000;
public static final int LONG_CONNECTION_TIMEOUT = 5000;
public static final int READ_TIMEOUT = 7000;
// Print URL and content to logcat on debug builds
private static boolean verbose = BuildConfig.DEBUG;
private HttpUrl baseUrlHttps;
private HttpUrl baseUrlHttp;
private int httpsPort;
private OkHttpClient httpClient;
private OkHttpClient httpClientWithReadTimeout;
private OkHttpClient httpClientLongConnectTimeout;
private OkHttpClient httpClientLongConnectNoReadTimeout;
private OkHttpClient httpClientShortConnectTimeout;
private X509TrustManager defaultTrustManager;
private X509TrustManager trustManager;
@@ -167,20 +171,34 @@ public class NvHTTP {
}
};
httpClient = new OkHttpClient.Builder()
httpClientLongConnectTimeout = new OkHttpClient.Builder()
.connectionPool(new ConnectionPool(0, 1, TimeUnit.MILLISECONDS))
.hostnameVerifier(hv)
.readTimeout(0, TimeUnit.MILLISECONDS)
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(LONG_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.proxy(Proxy.NO_PROXY)
.build();
httpClientWithReadTimeout = httpClient.newBuilder()
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
httpClientShortConnectTimeout = httpClientLongConnectTimeout.newBuilder()
.connectTimeout(SHORT_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.build();
httpClientLongConnectNoReadTimeout = httpClientLongConnectTimeout.newBuilder()
.readTimeout(0, TimeUnit.MILLISECONDS)
.build();
}
public HttpUrl getHttpsUrl(boolean likelyOnline) throws IOException {
if (httpsPort == 0) {
// Fetch the HTTPS port if we don't have it already
httpsPort = getHttpsPort(openHttpConnectionToString(likelyOnline ? httpClientLongConnectTimeout : httpClientShortConnectTimeout,
baseUrlHttp, "serverinfo"));
}
return new HttpUrl.Builder().scheme("https").host(baseUrlHttp.host()).port(httpsPort).build();
}
public NvHTTP(String address, String uniqueId, X509Certificate serverCert, LimelightCryptoProvider cryptoProvider) throws IOException {
public NvHTTP(ComputerDetails.AddressTuple address, int httpsPort, String uniqueId, X509Certificate serverCert, LimelightCryptoProvider cryptoProvider) throws IOException {
// Use the same UID for all Moonlight clients so we can quit games
// started by other Moonlight clients.
this.uniqueId = "0123456789ABCDEF";
@@ -189,17 +207,25 @@ public class NvHTTP {
initializeHttpState(cryptoProvider);
this.httpsPort = httpsPort;
try {
// If this is an IPv4-mapped IPv6 address, OkHTTP will choke on it if it's
// in IPv6 form, because InetAddress.getByName() will return an Inet4Address
// for what OkHTTP thinks is an IPv6 address. Normalize it into IPv4 form
// to avoid triggering this bug.
String addressString = address.address;
if (addressString.contains(":") && addressString.contains(".")) {
InetAddress addr = InetAddress.getByName(addressString);
if (addr instanceof Inet4Address) {
addressString = ((Inet4Address)addr).getHostAddress();
}
}
this.baseUrlHttp = new HttpUrl.Builder()
.scheme("http")
.host(address)
.port(HTTP_PORT)
.build();
this.baseUrlHttps = new HttpUrl.Builder()
.scheme("https")
.host(address)
.port(HTTPS_PORT)
.host(addressString)
.port(address.port)
.build();
} catch (IllegalArgumentException e) {
// Encapsulate IllegalArgumentException into IOException for callers to handle more easily
@@ -253,7 +279,7 @@ public class NvHTTP {
return getXmlString(new StringReader(str), tagname, throwIfMissing);
}
private static void verifyResponseStatus(XmlPullParser xpp) throws GfeHttpResponseException {
private static void verifyResponseStatus(XmlPullParser xpp) throws HostHttpResponseException {
// We use Long.parseLong() because in rare cases GFE can send back a status code of
// 0xFFFFFFFF, which will cause Integer.parseInt() to throw a NumberFormatException due
// to exceeding Integer.MAX_VALUE. We'll get the desired error code of -1 by just casting
@@ -267,12 +293,15 @@ public class NvHTTP {
statusCode = 418;
statusMsg = "Missing audio capture device. Reinstall GeForce Experience.";
}
throw new GfeHttpResponseException(statusCode, statusMsg);
throw new HostHttpResponseException(statusCode, statusMsg);
}
}
public String getServerInfo() throws IOException, XmlPullParserException {
public String getServerInfo(boolean likelyOnline) throws IOException, XmlPullParserException {
String resp;
// If we believe the PC is online, give it a little extra time to respond
OkHttpClient client = likelyOnline ? httpClientLongConnectTimeout : httpClientShortConnectTimeout;
//
// TODO: Shield Hub uses HTTP for this and is able to get an accurate PairStatus with HTTP.
@@ -284,13 +313,13 @@ public class NvHTTP {
if (serverCert != null) {
try {
try {
resp = openHttpConnectionToString(baseUrlHttps, "serverinfo", true);
resp = openHttpConnectionToString(client, getHttpsUrl(likelyOnline), "serverinfo");
} catch (SSLHandshakeException e) {
// Detect if we failed due to a server cert mismatch
if (e.getCause() instanceof CertificateException) {
// Jump to the GfeHttpResponseException exception handler to retry
// over HTTP which will allow us to pair again to update the cert
throw new GfeHttpResponseException(401, "Server certificate mismatch");
throw new HostHttpResponseException(401, "Server certificate mismatch");
}
else {
throw e;
@@ -301,10 +330,10 @@ public class NvHTTP {
// We want this because it will throw us into the HTTP case if the client is unpaired.
getServerVersion(resp);
}
catch (GfeHttpResponseException e) {
catch (HostHttpResponseException e) {
if (e.getErrorCode() == 401) {
// Cert validation error - fall back to HTTP
return openHttpConnectionToString(baseUrlHttp, "serverinfo", true);
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
}
// If it's not a cert validation error, throw it
@@ -315,14 +344,21 @@ public class NvHTTP {
}
else {
// No pinned cert, so use HTTP
return openHttpConnectionToString(baseUrlHttp , "serverinfo", true);
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
}
}
public ComputerDetails getComputerDetails() throws IOException, XmlPullParserException {
private static ComputerDetails.AddressTuple makeTuple(String address, int port) {
if (address == null) {
return null;
}
return new ComputerDetails.AddressTuple(address, port);
}
public ComputerDetails getComputerDetails(String serverInfo) throws IOException, XmlPullParserException {
ComputerDetails details = new ComputerDetails();
String serverInfo = getServerInfo();
details.name = getXmlString(serverInfo, "hostname", false);
if (details.name == null || details.name.isEmpty()) {
details.name = "UNKNOWN";
@@ -331,20 +367,32 @@ public class NvHTTP {
// UUID is mandatory to determine which machine is responding
details.uuid = getXmlString(serverInfo, "uniqueid", true);
details.macAddress = getXmlString(serverInfo, "mac", false);
details.localAddress = getXmlString(serverInfo, "LocalIP", false);
details.httpsPort = getHttpsPort(serverInfo);
// This is missing on on recent GFE versions
details.remoteAddress = getXmlString(serverInfo, "ExternalIP", false);
details.macAddress = getXmlString(serverInfo, "mac", false);
// FIXME: Do we want to use the current port?
details.localAddress = makeTuple(getXmlString(serverInfo, "LocalIP", false), baseUrlHttp.port());
// This is missing on on recent GFE versions, but it's present on Sunshine
details.externalPort = getExternalPort(serverInfo);
details.remoteAddress = makeTuple(getXmlString(serverInfo, "ExternalIP", false), details.externalPort);
details.pairState = getPairState(serverInfo);
details.runningGameId = getCurrentGame(serverInfo);
// The MJOLNIR codename was used by GFE but never by any third-party server
details.nvidiaServer = getXmlString(serverInfo, "state", true).contains("MJOLNIR");
// We could reach it so it's online
details.state = ComputerDetails.State.ONLINE;
return details;
}
public ComputerDetails getComputerDetails(boolean likelyOnline) throws IOException, XmlPullParserException {
return getComputerDetails(getServerInfo(likelyOnline));
}
// This hack is Android-specific but we do it on all platforms
// because it doesn't really matter
@@ -378,25 +426,18 @@ public class NvHTTP {
.build();
}
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
return openHttpConnection(baseUrl, path, null, enableReadTimeout);
private ResponseBody openHttpConnection(OkHttpClient client, HttpUrl baseUrl, String path) throws IOException {
return openHttpConnection(client, baseUrl, path, null);
}
// Read timeout should be enabled for any HTTP query that requires no outside action
// on the GFE server. Examples of queries that DO require outside action are launch, resume, and quit.
// The initial pair query does require outside action (user entering a PIN) but subsequent pairing
// queries do not.
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
private ResponseBody openHttpConnection(OkHttpClient client, HttpUrl baseUrl, String path, String query) throws IOException {
HttpUrl completeUrl = getCompleteUrl(baseUrl, path, query);
Request request = new Request.Builder().url(completeUrl).get().build();
Response response;
if (enableReadTimeout) {
response = performAndroidTlsHack(httpClientWithReadTimeout).newCall(request).execute();
}
else {
response = performAndroidTlsHack(httpClient).newCall(request).execute();
}
Response response = performAndroidTlsHack(client).newCall(request).execute();
ResponseBody body = response.body();
@@ -413,17 +454,17 @@ public class NvHTTP {
throw new FileNotFoundException(completeUrl.toString());
}
else {
throw new GfeHttpResponseException(response.code(), response.message());
throw new HostHttpResponseException(response.code(), response.message());
}
}
private String openHttpConnectionToString(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
return openHttpConnectionToString(baseUrl, path, null, enableReadTimeout);
private String openHttpConnectionToString(OkHttpClient client, HttpUrl baseUrl, String path) throws IOException {
return openHttpConnectionToString(client, baseUrl, path, null);
}
private String openHttpConnectionToString(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
private String openHttpConnectionToString(OkHttpClient client, HttpUrl baseUrl, String path, String query) throws IOException {
try {
ResponseBody resp = openHttpConnection(baseUrl, path, query, enableReadTimeout);
ResponseBody resp = openHttpConnection(client, baseUrl, path, query);
String respString = resp.string();
resp.close();
@@ -448,7 +489,7 @@ public class NvHTTP {
}
public PairingManager.PairState getPairState() throws IOException, XmlPullParserException {
return getPairState(getServerInfo());
return getPairState(getServerInfo(true));
}
public PairingManager.PairState getPairState(String serverInfo) throws IOException, XmlPullParserException {
@@ -527,6 +568,32 @@ public class NvHTTP {
}
}
public int getHttpsPort(String serverInfo) {
try {
return Integer.parseInt(getXmlString(serverInfo, "HttpsPort", true));
} catch (XmlPullParserException e) {
e.printStackTrace();
return DEFAULT_HTTPS_PORT;
} catch (IOException e) {
e.printStackTrace();
return DEFAULT_HTTPS_PORT;
}
}
public int getExternalPort(String serverInfo) {
// This is an extension which is not present in GFE. It is present for Sunshine to be able
// to support dynamic HTTP WAN ports without requiring the user to manually enter the port.
try {
return Integer.parseInt(getXmlString(serverInfo, "ExternalPort", true));
} catch (XmlPullParserException e) {
// Expected on non-Sunshine servers
return baseUrlHttp.port();
} catch (IOException e) {
e.printStackTrace();
return baseUrlHttp.port();
}
}
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
LinkedList<NvApp> appList = getAppList();
for (NvApp appFromList : appList) {
@@ -618,40 +685,37 @@ public class NvHTTP {
}
public String getAppListRaw() throws IOException {
return openHttpConnectionToString(baseUrlHttps, "applist", true);
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true), "applist");
}
public LinkedList<NvApp> getAppList() throws GfeHttpResponseException, IOException, XmlPullParserException {
public LinkedList<NvApp> getAppList() throws HostHttpResponseException, IOException, XmlPullParserException {
if (verbose) {
// Use the raw function so the app list is printed
return getAppListByReader(new StringReader(getAppListRaw()));
}
else {
ResponseBody resp = openHttpConnection(baseUrlHttps, "applist", true);
LinkedList<NvApp> appList = getAppListByReader(new InputStreamReader(resp.byteStream()));
resp.close();
return appList;
try (final ResponseBody resp = openHttpConnection(httpClientLongConnectTimeout, getHttpsUrl(true), "applist")) {
return getAppListByReader(new InputStreamReader(resp.byteStream()));
}
}
}
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws GfeHttpResponseException, IOException {
return openHttpConnectionToString(baseUrlHttp, "pair",
"devicename=roth&updateState=1&" + additionalArguments,
enableReadTimeout);
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws HostHttpResponseException, IOException {
return openHttpConnectionToString(enableReadTimeout ? httpClientLongConnectTimeout : httpClientLongConnectNoReadTimeout,
baseUrlHttp, "pair", "devicename=roth&updateState=1&" + additionalArguments);
}
String executePairingChallenge() throws GfeHttpResponseException, IOException {
return openHttpConnectionToString(baseUrlHttps, "pair",
"devicename=roth&updateState=1&phrase=pairchallenge",
true);
String executePairingChallenge() throws HostHttpResponseException, IOException {
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true),
"pair", "devicename=roth&updateState=1&phrase=pairchallenge");
}
public void unpair() throws IOException {
openHttpConnectionToString(baseUrlHttp, "unpair", true);
openHttpConnectionToString(httpClientLongConnectTimeout, baseUrlHttp, "unpair");
}
public InputStream getBoxArt(NvApp app) throws IOException {
ResponseBody resp = openHttpConnection(baseUrlHttps, "appasset", "appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0", true);
ResponseBody resp = openHttpConnection(httpClientLongConnectTimeout, getHttpsUrl(true), "appasset", "appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0");
return resp.byteStream();
}
@@ -686,27 +750,30 @@ public class NvHTTP {
return new String(hexChars);
}
public boolean launchApp(ConnectionContext context, int appId, boolean enableHdr) throws IOException, XmlPullParserException {
public boolean launchApp(ConnectionContext context, String verb, int appId, boolean enableHdr) throws IOException, XmlPullParserException {
// Using an FPS value over 60 causes SOPS to default to 720p60,
// so force it to 0 to ensure the correct resolution is set. We
// used to use 60 here but that locked the frame rate to 60 FPS
// on GFE 3.20.3.
int fps = context.streamConfig.getLaunchRefreshRate() > 60 ? 0 : context.streamConfig.getLaunchRefreshRate();
int fps = context.isNvidiaServerSoftware && context.streamConfig.getLaunchRefreshRate() > 60 ?
0 : context.streamConfig.getLaunchRefreshRate();
// Using an unsupported resolution (not 720p, 1080p, or 4K) causes
// GFE to force SOPS to 720p60. This is fine for < 720p resolutions like
// 360p or 480p, but it is not ideal for 1440p and other resolutions.
// When we detect an unsupported resolution, disable SOPS unless it's under 720p.
// FIXME: Detect support resolutions using the serverinfo response, not a hardcoded list
boolean enableSops = context.streamConfig.getSops();
if (context.negotiatedWidth * context.negotiatedHeight > 1280 * 720 &&
context.negotiatedWidth * context.negotiatedHeight != 1920 * 1080 &&
context.negotiatedWidth * context.negotiatedHeight != 3840 * 2160) {
LimeLog.info("Disabling SOPS due to non-standard resolution: "+context.negotiatedWidth+"x"+context.negotiatedHeight);
enableSops = false;
if (context.isNvidiaServerSoftware) {
// Using an unsupported resolution (not 720p, 1080p, or 4K) causes
// GFE to force SOPS to 720p60. This is fine for < 720p resolutions like
// 360p or 480p, but it is not ideal for 1440p and other resolutions.
// When we detect an unsupported resolution, disable SOPS unless it's under 720p.
// FIXME: Detect support resolutions using the serverinfo response, not a hardcoded list
if (context.negotiatedWidth * context.negotiatedHeight > 1280 * 720 &&
context.negotiatedWidth * context.negotiatedHeight != 1920 * 1080 &&
context.negotiatedWidth * context.negotiatedHeight != 3840 * 2160) {
LimeLog.info("Disabling SOPS due to non-standard resolution: "+context.negotiatedWidth+"x"+context.negotiatedHeight);
enableSops = false;
}
}
String xmlStr = openHttpConnectionToString(baseUrlHttps, "launch",
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), verb,
"appid=" + appId +
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
@@ -715,26 +782,11 @@ public class NvHTTP {
(!enableHdr ? "" : "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0") +
"&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) +
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""),
false);
if (!getXmlString(xmlStr, "gamesession", true).equals("0")) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
return true;
}
else {
return false;
}
}
public boolean resumeApp(ConnectionContext context) throws IOException, XmlPullParserException {
String xmlStr = openHttpConnectionToString(baseUrlHttps, "resume",
"rikey="+bytesToHex(context.riKey.getEncoded()) +
"&rikeyid="+context.riKeyId +
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo(),
false);
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
"&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() +
"&gcmap=" + context.streamConfig.getAttachedGamepadMask() +
"&gcpersist="+(context.streamConfig.getPersistGamepadsAfterDisconnect() ? 1 : 0));
if ((verb.equals("launch") && !getXmlString(xmlStr, "gamesession", true).equals("0") ||
(verb.equals("resume") && !getXmlString(xmlStr, "resume", true).equals("0")))) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
return true;
@@ -745,17 +797,17 @@ public class NvHTTP {
}
public boolean quitApp() throws IOException, XmlPullParserException {
String xmlStr = openHttpConnectionToString(baseUrlHttps, "cancel", false);
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "cancel");
if (getXmlString(xmlStr, "cancel", true).equals("0")) {
return false;
}
// Newer GFE versions will just return success even if quitting fails
// if we're not the original requestor.
if (getCurrentGame(getServerInfo()) != 0) {
if (getCurrentGame(getServerInfo(true)) != 0) {
// Generate a synthetic GfeResponseException letting the caller know
// that they can't kill someone else's stream.
throw new GfeHttpResponseException(599, "");
throw new HostHttpResponseException(599, "");
}
return true;
@@ -1,19 +1,27 @@
package com.limelight.nvstream.input;
public class ControllerPacket {
public static final short A_FLAG = 0x1000;
public static final short B_FLAG = 0x2000;
public static final short X_FLAG = 0x4000;
public static final short Y_FLAG = (short)0x8000;
public static final short UP_FLAG = 0x0001;
public static final short DOWN_FLAG = 0x0002;
public static final short LEFT_FLAG = 0x0004;
public static final short RIGHT_FLAG = 0x0008;
public static final short LB_FLAG = 0x0100;
public static final short RB_FLAG = 0x0200;
public static final short PLAY_FLAG = 0x0010;
public static final short BACK_FLAG = 0x0020;
public static final short LS_CLK_FLAG = 0x0040;
public static final short RS_CLK_FLAG = 0x0080;
public static final short SPECIAL_BUTTON_FLAG = 0x0400;
public static final int A_FLAG = 0x1000;
public static final int B_FLAG = 0x2000;
public static final int X_FLAG = 0x4000;
public static final int Y_FLAG = 0x8000;
public static final int UP_FLAG = 0x0001;
public static final int DOWN_FLAG = 0x0002;
public static final int LEFT_FLAG = 0x0004;
public static final int RIGHT_FLAG = 0x0008;
public static final int LB_FLAG = 0x0100;
public static final int RB_FLAG = 0x0200;
public static final int PLAY_FLAG = 0x0010;
public static final int BACK_FLAG = 0x0020;
public static final int LS_CLK_FLAG = 0x0040;
public static final int RS_CLK_FLAG = 0x0080;
public static final int SPECIAL_BUTTON_FLAG = 0x0400;
// Extended buttons (Sunshine only)
public static final int PADDLE1_FLAG = 0x010000;
public static final int PADDLE2_FLAG = 0x020000;
public static final int PADDLE3_FLAG = 0x040000;
public static final int PADDLE4_FLAG = 0x080000;
public static final int TOUCHPAD_FLAG = 0x100000; // Touchpad buttons on Sony controllers
public static final int MISC_FLAG = 0x200000; // Share/Mic/Capture/Mute buttons on various controllers
}
@@ -7,4 +7,5 @@ public class KeyboardPacket {
public static final byte MODIFIER_SHIFT = 0x01;
public static final byte MODIFIER_CTRL = 0x02;
public static final byte MODIFIER_ALT = 0x04;
}
public static final byte MODIFIER_META = 0x08;
}
@@ -14,9 +14,13 @@ public class MoonBridge {
public static final int VIDEO_FORMAT_H264 = 0x0001;
public static final int VIDEO_FORMAT_H265 = 0x0100;
public static final int VIDEO_FORMAT_H265_MAIN10 = 0x0200;
public static final int VIDEO_FORMAT_AV1_MAIN8 = 0x1000;
public static final int VIDEO_FORMAT_AV1_MAIN10 = 0x2000;
public static final int VIDEO_FORMAT_MASK_H264 = 0x00FF;
public static final int VIDEO_FORMAT_MASK_H265 = 0xFF00;
public static final int VIDEO_FORMAT_MASK_H264 = 0x000F;
public static final int VIDEO_FORMAT_MASK_H265 = 0x0F00;
public static final int VIDEO_FORMAT_MASK_AV1 = 0xF000;
public static final int VIDEO_FORMAT_MASK_10BIT = 0x2200;
public static final int ENCFLG_NONE = 0;
public static final int ENCFLG_AUDIO = 1;
@@ -30,9 +34,17 @@ public class MoonBridge {
public static final int FRAME_TYPE_PFRAME = 0;
public static final int FRAME_TYPE_IDR = 1;
public static final int COLORSPACE_REC_601 = 0;
public static final int COLORSPACE_REC_709 = 1;
public static final int COLORSPACE_REC_2020 = 2;
public static final int COLOR_RANGE_LIMITED = 0;
public static final int COLOR_RANGE_FULL = 1;
public static final int CAPABILITY_DIRECT_SUBMIT = 1;
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC = 2;
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC = 4;
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_AV1 = 0x40;
public static final int DR_OK = 0;
public static final int DR_NEED_IDR = -1;
@@ -45,6 +57,7 @@ public class MoonBridge {
public static final int ML_ERROR_NO_VIDEO_FRAME = -101;
public static final int ML_ERROR_UNEXPECTED_EARLY_TERMINATION = -102;
public static final int ML_ERROR_PROTECTED_CONTENT = -103;
public static final int ML_ERROR_FRAME_CONVERSION = -104;
public static final int ML_PORT_INDEX_TCP_47984 = 0;
public static final int ML_PORT_INDEX_TCP_47989 = 1;
@@ -65,6 +78,56 @@ public class MoonBridge {
public static final int ML_TEST_RESULT_INCONCLUSIVE = 0xFFFFFFFF;
public static final byte SS_KBE_FLAG_NON_NORMALIZED = 0x01;
public static final int LI_ERR_UNSUPPORTED = -5501;
public static final byte LI_TOUCH_EVENT_HOVER = 0x00;
public static final byte LI_TOUCH_EVENT_DOWN = 0x01;
public static final byte LI_TOUCH_EVENT_UP = 0x02;
public static final byte LI_TOUCH_EVENT_MOVE = 0x03;
public static final byte LI_TOUCH_EVENT_CANCEL = 0x04;
public static final byte LI_TOUCH_EVENT_BUTTON_ONLY = 0x05;
public static final byte LI_TOUCH_EVENT_HOVER_LEAVE = 0x06;
public static final byte LI_TOUCH_EVENT_CANCEL_ALL = 0x07;
public static final byte LI_TOOL_TYPE_UNKNOWN = 0x00;
public static final byte LI_TOOL_TYPE_PEN = 0x01;
public static final byte LI_TOOL_TYPE_ERASER = 0x02;
public static final byte LI_PEN_BUTTON_PRIMARY = 0x01;
public static final byte LI_PEN_BUTTON_SECONDARY = 0x02;
public static final byte LI_PEN_BUTTON_TERTIARY = 0x04;
public static final byte LI_TILT_UNKNOWN = (byte)0xFF;
public static final short LI_ROT_UNKNOWN = (short)0xFFFF;
public static final byte LI_CTYPE_UNKNOWN = 0x00;
public static final byte LI_CTYPE_XBOX = 0x01;
public static final byte LI_CTYPE_PS = 0x02;
public static final byte LI_CTYPE_NINTENDO = 0x03;
public static final short LI_CCAP_ANALOG_TRIGGERS = 0x01;
public static final short LI_CCAP_RUMBLE = 0x02;
public static final short LI_CCAP_TRIGGER_RUMBLE = 0x04;
public static final short LI_CCAP_TOUCHPAD = 0x08;
public static final short LI_CCAP_ACCEL = 0x10;
public static final short LI_CCAP_GYRO = 0x20;
public static final short LI_CCAP_BATTERY_STATE = 0x40;
public static final short LI_CCAP_RGB_LED = 0x80;
public static final byte LI_MOTION_TYPE_ACCEL = 0x01;
public static final byte LI_MOTION_TYPE_GYRO = 0x02;
public static final byte LI_BATTERY_STATE_UNKNOWN = 0x00;
public static final byte LI_BATTERY_STATE_NOT_PRESENT = 0x01;
public static final byte LI_BATTERY_STATE_DISCHARGING = 0x02;
public static final byte LI_BATTERY_STATE_CHARGING = 0x03;
public static final byte LI_BATTERY_STATE_NOT_CHARGING = 0x04; // Connected to power but not charging
public static final byte LI_BATTERY_STATE_FULL = 0x05;
public static final byte LI_BATTERY_PERCENTAGE_UNKNOWN = (byte)0xFF;
private static AudioRenderer audioRenderer;
private static VideoDecoderRenderer videoRenderer;
private static NvConnectionListener connectionListener;
@@ -157,11 +220,11 @@ public class MoonBridge {
}
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
int frameNumber, int frameType,
int frameNumber, int frameType, char frameHostProcessingLatency,
long receiveTimeMs, long enqueueTimeMs) {
if (videoRenderer != null) {
return videoRenderer.submitDecodeUnit(decodeUnitData, decodeUnitLength,
decodeUnitType, frameNumber, frameType, receiveTimeMs, enqueueTimeMs);
decodeUnitType, frameNumber, frameType, frameHostProcessingLatency, receiveTimeMs, enqueueTimeMs);
}
else {
return DR_OK;
@@ -243,9 +306,27 @@ public class MoonBridge {
}
}
public static void bridgeClSetHdrMode(boolean enabled) {
public static void bridgeClSetHdrMode(boolean enabled, byte[] hdrMetadata) {
if (connectionListener != null) {
connectionListener.setHdrMode(enabled);
connectionListener.setHdrMode(enabled, hdrMetadata);
}
}
public static void bridgeClRumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) {
if (connectionListener != null) {
connectionListener.rumbleTriggers(controllerNumber, leftTrigger, rightTrigger);
}
}
public static void bridgeClSetMotionEventState(short controllerNumber, byte eventType, short sampleRateHz) {
if (connectionListener != null) {
connectionListener.setMotionEventState(controllerNumber, eventType, sampleRateHz);
}
}
public static void bridgeClSetControllerLED(short controllerNumber, byte r, byte g, byte b) {
if (connectionListener != null) {
connectionListener.setControllerLED(controllerNumber, r, g, b);
}
}
@@ -262,16 +343,17 @@ public class MoonBridge {
}
public static native int startConnection(String address, String appVersion, String gfeVersion,
String rtspSessionUrl,
String rtspSessionUrl, int serverCodecModeSupport,
int width, int height, int fps,
int bitrate, int packetSize, int streamingRemotely,
int audioConfiguration, boolean supportsHevc,
boolean enableHdr,
int audioConfiguration, int supportedVideoFormats,
int hevcBitratePercentageMultiplier,
int av1BitratePercentageMultiplier,
int clientRefreshRateX100,
int encryptionFlags,
byte[] riAesKey, byte[] riAesIv,
int videoCapabilities);
int videoCapabilities,
int colorSpace, int colorRange);
public static native void stopConnection();
@@ -286,22 +368,32 @@ public class MoonBridge {
public static native void sendMouseButton(byte buttonEvent, byte mouseButton);
public static native void sendMultiControllerInput(short controllerNumber,
short activeGamepadMask, short buttonFlags,
short activeGamepadMask, int buttonFlags,
byte leftTrigger, byte rightTrigger,
short leftStickX, short leftStickY,
short rightStickX, short rightStickY);
public static native void sendControllerInput(short buttonFlags,
byte leftTrigger, byte rightTrigger,
short leftStickX, short leftStickY,
short rightStickX, short rightStickY);
public static native int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressure,
float contactAreaMajor, float contactAreaMinor, short rotation);
public static native void sendKeyboardInput(short keyMap, byte keyDirection, byte modifier);
public static native int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
float pressure, float contactAreaMajor, float contactAreaMinor,
short rotation, byte tilt);
public static native void sendMouseScroll(byte scrollClicks);
public static native int sendControllerArrivalEvent(byte controllerNumber, short activeGamepadMask, byte type, int supportedButtonFlags, short capabilities);
public static native int sendControllerTouchEvent(byte controllerNumber, byte eventType, int pointerId, float x, float y, float pressure);
public static native int sendControllerMotionEvent(byte controllerNumber, byte motionType, float x, float y, float z);
public static native int sendControllerBatteryEvent(byte controllerNumber, byte batteryState, byte batteryPercentage);
public static native void sendKeyboardInput(short keyMap, byte keyDirection, byte modifier, byte flags);
public static native void sendMouseHighResScroll(short scrollAmount);
public static native void sendMouseHighResHScroll(short scrollAmount);
public static native void sendUtf8Text(String text);
public static native String getStageName(int stage);
@@ -323,5 +415,11 @@ public class MoonBridge {
// 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 byte guessControllerType(int vendorId, int productId);
public static native boolean guessControllerHasPaddles(int vendorId, int productId);
public static native boolean guessControllerHasShareButton(int vendorId, int productId);
public static native void init();
}
@@ -0,0 +1,269 @@
package com.limelight.nvstream.mdns;
import android.content.Context;
import android.net.wifi.WifiManager;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.HashSet;
import javax.jmdns.JmmDNS;
import javax.jmdns.NetworkTopologyDiscovery;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.impl.NetworkTopologyDiscoveryImpl;
import com.limelight.LimeLog;
public class JmDNSDiscoveryAgent extends MdnsDiscoveryAgent implements ServiceListener {
private static final String SERVICE_TYPE = "_nvstream._tcp.local.";
private WifiManager.MulticastLock multicastLock;
private Thread discoveryThread;
private HashSet<String> pendingResolution = new HashSet<>();
// The resolver factory's instance member has a static lifetime which
// means our ref count and listener must be static also.
private static int resolverRefCount = 0;
private static HashSet<ServiceListener> listeners = new HashSet<>();
private static ServiceListener nvstreamListener = new ServiceListener() {
@Override
public void serviceAdded(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceAdded(event);
}
}
@Override
public void serviceRemoved(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceRemoved(event);
}
}
@Override
public void serviceResolved(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceResolved(event);
}
}
};
public static class MyNetworkTopologyDiscovery extends NetworkTopologyDiscoveryImpl {
@Override
public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress) {
// This is an copy of jmDNS's implementation, except we omit the multicast check, since
// it seems at least some devices lie about interfaces not supporting multicast when they really do.
try {
if (!networkInterface.isUp()) {
return false;
}
/*
if (!networkInterface.supportsMulticast()) {
return false;
}
*/
if (networkInterface.isLoopback()) {
return false;
}
return true;
} catch (Exception exception) {
return false;
}
}
}
static {
// Override jmDNS's default topology discovery class with ours
NetworkTopologyDiscovery.Factory.setClassDelegate(new NetworkTopologyDiscovery.Factory.ClassDelegate() {
@Override
public NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
return new MyNetworkTopologyDiscovery();
}
});
}
private static JmmDNS referenceResolver() {
synchronized (JmDNSDiscoveryAgent.class) {
JmmDNS instance = JmmDNS.Factory.getInstance();
if (++resolverRefCount == 1) {
// This will cause the listener to be invoked for known hosts immediately.
// JmDNS only supports one listener per service, so we have to do this here
// with a static listener.
instance.addServiceListener(SERVICE_TYPE, nvstreamListener);
}
return instance;
}
}
private static void dereferenceResolver() {
synchronized (JmDNSDiscoveryAgent.class) {
if (--resolverRefCount == 0) {
try {
JmmDNS.Factory.close();
} catch (IOException e) {}
}
}
}
public JmDNSDiscoveryAgent(Context context, MdnsDiscoveryListener listener) {
super(listener);
// Create the multicast lock required to receive mDNS traffic
WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
multicastLock = wifiMgr.createMulticastLock("Limelight mDNS");
multicastLock.setReferenceCounted(false);
}
private void handleResolvedServiceInfo(ServiceInfo info) {
synchronized (pendingResolution) {
pendingResolution.remove(info.getName());
}
try {
handleServiceInfo(info);
} catch (UnsupportedEncodingException e) {
// Invalid DNS response
LimeLog.info("mDNS: Invalid response for machine: "+info.getName());
return;
}
}
private void handleServiceInfo(ServiceInfo info) throws UnsupportedEncodingException {
reportNewComputer(info.getName(), info.getPort(), info.getInet4Addresses(), info.getInet6Addresses());
}
public void startDiscovery(final int discoveryIntervalMs) {
// Kill any existing discovery before starting a new one
stopDiscovery();
// Acquire the multicast lock to start receiving mDNS traffic
multicastLock.acquire();
// Add our listener to the set
synchronized (listeners) {
listeners.add(JmDNSDiscoveryAgent.this);
}
discoveryThread = new Thread() {
@Override
public void run() {
// This may result in listener callbacks so we must register
// our listener first.
JmmDNS resolver = referenceResolver();
try {
while (!Thread.interrupted()) {
// Start an mDNS request
resolver.requestServiceInfo(SERVICE_TYPE, null, discoveryIntervalMs);
// Run service resolution again for pending machines
ArrayList<String> pendingNames;
synchronized (pendingResolution) {
pendingNames = new ArrayList<String>(pendingResolution);
}
for (String name : pendingNames) {
LimeLog.info("mDNS: Retrying service resolution for machine: "+name);
ServiceInfo[] infos = resolver.getServiceInfos(SERVICE_TYPE, name, 500);
if (infos != null && infos.length != 0) {
LimeLog.info("mDNS: Resolved (retry) with "+infos.length+" service entries");
for (ServiceInfo svcinfo : infos) {
handleResolvedServiceInfo(svcinfo);
}
}
}
// Wait for the next polling interval
try {
Thread.sleep(discoveryIntervalMs);
} catch (InterruptedException e) {
break;
}
}
}
finally {
// Dereference the resolver
dereferenceResolver();
}
}
};
discoveryThread.setName("mDNS Discovery Thread");
discoveryThread.start();
}
public void stopDiscovery() {
// Release the multicast lock to stop receiving mDNS traffic
multicastLock.release();
// Remove our listener from the set
synchronized (listeners) {
listeners.remove(JmDNSDiscoveryAgent.this);
}
// If there's already a running thread, interrupt it
if (discoveryThread != null) {
discoveryThread.interrupt();
discoveryThread = null;
}
}
@Override
public void serviceAdded(ServiceEvent event) {
LimeLog.info("mDNS: Machine appeared: "+event.getInfo().getName());
ServiceInfo info = event.getDNS().getServiceInfo(SERVICE_TYPE, event.getInfo().getName(), 500);
if (info == null) {
// This machine is pending resolution
synchronized (pendingResolution) {
pendingResolution.add(event.getInfo().getName());
}
return;
}
LimeLog.info("mDNS: Resolved (blocking)");
handleResolvedServiceInfo(info);
}
@Override
public void serviceRemoved(ServiceEvent event) {
LimeLog.info("mDNS: Machine disappeared: "+event.getInfo().getName());
}
@Override
public void serviceResolved(ServiceEvent event) {
// We handle this synchronously
}
}
@@ -6,12 +6,14 @@ import java.net.InetAddress;
public class MdnsComputer {
private InetAddress localAddr;
private Inet6Address v6Addr;
private int port;
private String name;
public MdnsComputer(String name, InetAddress localAddress, Inet6Address v6Addr) {
public MdnsComputer(String name, InetAddress localAddress, Inet6Address v6Addr, int port) {
this.name = name;
this.localAddr = localAddress;
this.v6Addr = v6Addr;
this.port = port;
}
public String getName() {
@@ -26,6 +28,10 @@ public class MdnsComputer {
return v6Addr;
}
public int getPort() {
return port;
}
@Override
public int hashCode() {
return name.hashCode();
@@ -36,7 +42,7 @@ public class MdnsComputer {
if (o instanceof MdnsComputer) {
MdnsComputer other = (MdnsComputer)o;
if (!other.name.equals(name)) {
if (!other.name.equals(name) || other.port != port) {
return false;
}
@@ -1,166 +1,64 @@
package com.limelight.nvstream.mdns;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import javax.jmdns.JmmDNS;
import javax.jmdns.NetworkTopologyDiscovery;
import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.jmdns.impl.NetworkTopologyDiscoveryImpl;
import com.limelight.LimeLog;
public class MdnsDiscoveryAgent implements ServiceListener {
public static final String SERVICE_TYPE = "_nvstream._tcp.local.";
private MdnsDiscoveryListener listener;
private Thread discoveryThread;
private HashMap<InetAddress, MdnsComputer> computers = new HashMap<InetAddress, MdnsComputer>();
private HashSet<String> pendingResolution = new HashSet<String>();
// The resolver factory's instance member has a static lifetime which
// means our ref count and listener must be static also.
private static int resolverRefCount = 0;
private static HashSet<ServiceListener> listeners = new HashSet<ServiceListener>();
private static ServiceListener nvstreamListener = new ServiceListener() {
@Override
public void serviceAdded(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceAdded(event);
}
}
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@Override
public void serviceRemoved(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceRemoved(event);
}
}
public abstract class MdnsDiscoveryAgent {
protected MdnsDiscoveryListener listener;
@Override
public void serviceResolved(ServiceEvent event) {
HashSet<ServiceListener> localListeners;
// Copy the listener set into a new set so we can invoke
// the callbacks without holding the listeners monitor the
// whole time.
synchronized (listeners) {
localListeners = new HashSet<ServiceListener>(listeners);
}
for (ServiceListener listener : localListeners) {
listener.serviceResolved(event);
}
}
};
public static class MyNetworkTopologyDiscovery extends NetworkTopologyDiscoveryImpl {
@Override
public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress) {
// This is an copy of jmDNS's implementation, except we omit the multicast check, since
// it seems at least some devices lie about interfaces not supporting multicast when they really do.
try {
if (!networkInterface.isUp()) {
return false;
}
/*
if (!networkInterface.supportsMulticast()) {
return false;
}
*/
if (networkInterface.isLoopback()) {
return false;
}
return true;
} catch (Exception exception) {
return false;
}
}
};
static {
// Override jmDNS's default topology discovery class with ours
NetworkTopologyDiscovery.Factory.setClassDelegate(new NetworkTopologyDiscovery.Factory.ClassDelegate() {
@Override
public NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
return new MyNetworkTopologyDiscovery();
}
});
}
private static JmmDNS referenceResolver() {
synchronized (MdnsDiscoveryAgent.class) {
JmmDNS instance = JmmDNS.Factory.getInstance();
if (++resolverRefCount == 1) {
// This will cause the listener to be invoked for known hosts immediately.
// JmDNS only supports one listener per service, so we have to do this here
// with a static listener.
instance.addServiceListener(SERVICE_TYPE, nvstreamListener);
}
return instance;
}
}
private static void dereferenceResolver() {
synchronized (MdnsDiscoveryAgent.class) {
if (--resolverRefCount == 0) {
try {
JmmDNS.Factory.close();
} catch (IOException e) {}
}
}
}
protected HashSet<MdnsComputer> computers = new HashSet<>();
public MdnsDiscoveryAgent(MdnsDiscoveryListener listener) {
this.listener = listener;
}
private void handleResolvedServiceInfo(ServiceInfo info) {
synchronized (pendingResolution) {
pendingResolution.remove(info.getName());
public abstract void startDiscovery(final int discoveryIntervalMs);
public abstract void stopDiscovery();
protected void reportNewComputer(String name, int port, Inet4Address[] v4Addrs, Inet6Address[] v6Addrs) {
LimeLog.info("mDNS: "+name+" has "+v4Addrs.length+" IPv4 addresses");
LimeLog.info("mDNS: "+name+" has "+v6Addrs.length+" IPv6 addresses");
Inet6Address v6GlobalAddr = getBestIpv6Address(v6Addrs);
// Add a computer object for each IPv4 address reported by the PC
for (Inet4Address v4Addr : v4Addrs) {
synchronized (computers) {
MdnsComputer computer = new MdnsComputer(name, v4Addr, v6GlobalAddr, port);
if (computers.add(computer)) {
// This was a new entry
listener.notifyComputerAdded(computer);
}
}
}
try {
handleServiceInfo(info);
} catch (UnsupportedEncodingException e) {
// Invalid DNS response
LimeLog.info("mDNS: Invalid response for machine: "+info.getName());
return;
// If there were no IPv4 addresses, use IPv6 for registration
if (v4Addrs.length == 0) {
Inet6Address v6LocalAddr = getLocalAddress(v6Addrs);
if (v6LocalAddr != null || v6GlobalAddr != null) {
MdnsComputer computer = new MdnsComputer(name, v6LocalAddr, v6GlobalAddr, port);
if (computers.add(computer)) {
// This was a new entry
listener.notifyComputerAdded(computer);
}
}
}
}
private Inet6Address getLocalAddress(Inet6Address[] addresses) {
public List<MdnsComputer> getComputerSet() {
synchronized (computers) {
return new ArrayList<>(computers);
}
}
protected static Inet6Address getLocalAddress(Inet6Address[] addresses) {
for (Inet6Address addr : addresses) {
if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) {
return addr;
@@ -174,7 +72,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
return null;
}
private Inet6Address getLinkLocalAddress(Inet6Address[] addresses) {
protected static Inet6Address getLinkLocalAddress(Inet6Address[] addresses) {
for (Inet6Address addr : addresses) {
if (addr.isLinkLocalAddress()) {
LimeLog.info("Found link-local address: "+addr.getHostAddress());
@@ -185,7 +83,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
return null;
}
private Inet6Address getBestIpv6Address(Inet6Address[] addresses) {
protected static Inet6Address getBestIpv6Address(Inet6Address[] addresses) {
// First try to find a link local address, so we can match the interface identifier
// with a global address (this will work for SLAAC but not DHCPv6).
Inet6Address linkLocalAddr = getLinkLocalAddress(addresses);
@@ -247,162 +145,4 @@ public class MdnsDiscoveryAgent implements ServiceListener {
return null;
}
private void handleServiceInfo(ServiceInfo info) throws UnsupportedEncodingException {
Inet4Address v4Addrs[] = info.getInet4Addresses();
Inet6Address v6Addrs[] = info.getInet6Addresses();
LimeLog.info("mDNS: "+info.getName()+" has "+v4Addrs.length+" IPv4 addresses");
LimeLog.info("mDNS: "+info.getName()+" has "+v6Addrs.length+" IPv6 addresses");
Inet6Address v6GlobalAddr = getBestIpv6Address(v6Addrs);
// Add a computer object for each IPv4 address reported by the PC
for (Inet4Address v4Addr : v4Addrs) {
synchronized (computers) {
MdnsComputer computer = new MdnsComputer(info.getName(), v4Addr, v6GlobalAddr);
if (computers.put(computer.getLocalAddress(), computer) == null) {
// This was a new entry
listener.notifyComputerAdded(computer);
}
}
}
// If there were no IPv4 addresses, use IPv6 for registration
if (v4Addrs.length == 0) {
Inet6Address v6LocalAddr = getLocalAddress(v6Addrs);
if (v6LocalAddr != null || v6GlobalAddr != null) {
MdnsComputer computer = new MdnsComputer(info.getName(), v6LocalAddr, v6GlobalAddr);
if (computers.put(v6LocalAddr != null ?
computer.getLocalAddress() : computer.getIpv6Address(), computer) == null) {
// This was a new entry
listener.notifyComputerAdded(computer);
}
}
}
}
public void startDiscovery(final int discoveryIntervalMs) {
// Kill any existing discovery before starting a new one
stopDiscovery();
// Add our listener to the set
synchronized (listeners) {
listeners.add(MdnsDiscoveryAgent.this);
}
discoveryThread = new Thread() {
@Override
public void run() {
// This may result in listener callbacks so we must register
// our listener first.
JmmDNS resolver = referenceResolver();
try {
while (!Thread.interrupted()) {
// Start an mDNS request
resolver.requestServiceInfo(SERVICE_TYPE, null, discoveryIntervalMs);
// Run service resolution again for pending machines
ArrayList<String> pendingNames;
synchronized (pendingResolution) {
pendingNames = new ArrayList<String>(pendingResolution);
}
for (String name : pendingNames) {
LimeLog.info("mDNS: Retrying service resolution for machine: "+name);
ServiceInfo[] infos = resolver.getServiceInfos(SERVICE_TYPE, name, 500);
if (infos != null && infos.length != 0) {
LimeLog.info("mDNS: Resolved (retry) with "+infos.length+" service entries");
for (ServiceInfo svcinfo : infos) {
handleResolvedServiceInfo(svcinfo);
}
}
}
// Wait for the next polling interval
try {
Thread.sleep(discoveryIntervalMs);
} catch (InterruptedException e) {
break;
}
}
}
finally {
// Dereference the resolver
dereferenceResolver();
}
}
};
discoveryThread.setName("mDNS Discovery Thread");
discoveryThread.start();
}
public void stopDiscovery() {
// Remove our listener from the set
synchronized (listeners) {
listeners.remove(MdnsDiscoveryAgent.this);
}
// If there's already a running thread, interrupt it
if (discoveryThread != null) {
discoveryThread.interrupt();
discoveryThread = null;
}
}
public List<MdnsComputer> getComputerSet() {
synchronized (computers) {
return new ArrayList<MdnsComputer>(computers.values());
}
}
@Override
public void serviceAdded(ServiceEvent event) {
LimeLog.info("mDNS: Machine appeared: "+event.getInfo().getName());
ServiceInfo info = event.getDNS().getServiceInfo(SERVICE_TYPE, event.getInfo().getName(), 500);
if (info == null) {
// This machine is pending resolution
synchronized (pendingResolution) {
pendingResolution.add(event.getInfo().getName());
}
return;
}
LimeLog.info("mDNS: Resolved (blocking)");
handleResolvedServiceInfo(info);
}
@Override
public void serviceRemoved(ServiceEvent event) {
LimeLog.info("mDNS: Machine disappeared: "+event.getInfo().getName());
Inet4Address v4Addrs[] = event.getInfo().getInet4Addresses();
for (Inet4Address addr : v4Addrs) {
synchronized (computers) {
MdnsComputer computer = computers.remove(addr);
if (computer != null) {
listener.notifyComputerRemoved(computer);
break;
}
}
}
Inet6Address v6Addrs[] = event.getInfo().getInet6Addresses();
for (Inet6Address addr : v6Addrs) {
synchronized (computers) {
MdnsComputer computer = computers.remove(addr);
if (computer != null) {
listener.notifyComputerRemoved(computer);
break;
}
}
}
}
@Override
public void serviceResolved(ServiceEvent event) {
// We handle this synchronously
}
}
@@ -2,6 +2,5 @@ package com.limelight.nvstream.mdns;
public interface MdnsDiscoveryListener {
void notifyComputerAdded(MdnsComputer computer);
void notifyComputerRemoved(MdnsComputer computer);
void notifyDiscoveryFailure(Exception e);
}
@@ -0,0 +1,234 @@
package com.limelight.nvstream.mdns;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Build;
import com.limelight.LimeLog;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public class NsdManagerDiscoveryAgent extends MdnsDiscoveryAgent {
private static final String SERVICE_TYPE = "_nvstream._tcp";
private final NsdManager nsdManager;
private final Object listenerLock = new Object();
private NsdManager.DiscoveryListener pendingListener;
private NsdManager.DiscoveryListener activeListener;
private final HashMap<String, NsdManager.ServiceInfoCallback> serviceCallbacks = new HashMap<>();
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
private NsdManager.DiscoveryListener createDiscoveryListener() {
return new NsdManager.DiscoveryListener() {
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
LimeLog.severe("NSD: Service discovery start failed: " + errorCode);
// This listener is no longer pending after this failure
synchronized (listenerLock) {
if (pendingListener != this) {
return;
}
pendingListener = null;
}
listener.notifyDiscoveryFailure(new RuntimeException("onStartDiscoveryFailed(): " + errorCode));
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
LimeLog.severe("NSD: Service discovery stop failed: " + errorCode);
// This listener is no longer active after this failure
synchronized (listenerLock) {
if (activeListener != this) {
return;
}
activeListener = null;
}
}
@Override
public void onDiscoveryStarted(String serviceType) {
LimeLog.info("NSD: Service discovery started");
synchronized (listenerLock) {
if (pendingListener != this) {
// If we registered another discovery listener in the meantime, stop this one
nsdManager.stopServiceDiscovery(this);
return;
}
pendingListener = null;
activeListener = this;
}
}
@Override
public void onDiscoveryStopped(String serviceType) {
LimeLog.info("NSD: Service discovery stopped");
synchronized (listenerLock) {
if (activeListener != this) {
return;
}
activeListener = null;
}
}
@Override
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
// Protect against racing stopDiscovery() call
synchronized (listenerLock) {
// Ignore callbacks if we're not the active listener
if (activeListener != this) {
return;
}
LimeLog.info("NSD: Machine appeared: " + nsdServiceInfo.getServiceName());
NsdManager.ServiceInfoCallback serviceInfoCallback = new NsdManager.ServiceInfoCallback() {
@Override
public void onServiceInfoCallbackRegistrationFailed(int errorCode) {
LimeLog.severe("NSD: Service info callback registration failed: " + errorCode);
listener.notifyDiscoveryFailure(new RuntimeException("onServiceInfoCallbackRegistrationFailed(): " + errorCode));
}
@Override
public void onServiceUpdated(NsdServiceInfo nsdServiceInfo) {
LimeLog.info("NSD: Machine resolved: " + nsdServiceInfo.getServiceName());
reportNewComputer(nsdServiceInfo.getServiceName(), nsdServiceInfo.getPort(),
getV4Addrs(nsdServiceInfo.getHostAddresses()),
getV6Addrs(nsdServiceInfo.getHostAddresses()));
}
@Override
public void onServiceLost() {
}
@Override
public void onServiceInfoCallbackUnregistered() {
}
};
nsdManager.registerServiceInfoCallback(nsdServiceInfo, executor, serviceInfoCallback);
serviceCallbacks.put(nsdServiceInfo.getServiceName(), serviceInfoCallback);
}
}
@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
// Protect against racing stopDiscovery() call
synchronized (listenerLock) {
// Ignore callbacks if we're not the active listener
if (activeListener != this) {
return;
}
LimeLog.info("NSD: Machine lost: " + nsdServiceInfo.getServiceName());
NsdManager.ServiceInfoCallback serviceInfoCallback = serviceCallbacks.remove(nsdServiceInfo.getServiceName());
if (serviceInfoCallback != null) {
nsdManager.unregisterServiceInfoCallback(serviceInfoCallback);
}
}
}
};
}
public NsdManagerDiscoveryAgent(Context context, MdnsDiscoveryListener listener) {
super(listener);
this.nsdManager = context.getSystemService(NsdManager.class);
}
@Override
public void startDiscovery(int discoveryIntervalMs) {
synchronized (listenerLock) {
// Register a new service discovery listener if there's not already one starting or running
if (pendingListener == null && activeListener == null) {
pendingListener = createDiscoveryListener();
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, pendingListener);
}
}
}
@Override
public void stopDiscovery() {
// Protect against racing ServiceInfoCallback and DiscoveryListener callbacks
synchronized (listenerLock) {
// Clear any pending listener to ensure the discoverStarted() callback
// will realize it's gone and stop itself.
pendingListener = null;
// Unregister the service discovery listener
if (activeListener != null) {
nsdManager.stopServiceDiscovery(activeListener);
// Even though listener stoppage is asynchronous, the listener is gone as far as
// we're concerned. We null this right now to ensure pending callbacks know it's
// stopped and startDiscovery() can immediately create a new listener. If we left
// it until onDiscoveryStopped() was called, startDiscovery() would get confused
// and assume a listener was already running, even though it's stopping.
activeListener = null;
}
// Unregister all service info callbacks
for (NsdManager.ServiceInfoCallback callback : serviceCallbacks.values()) {
nsdManager.unregisterServiceInfoCallback(callback);
}
serviceCallbacks.clear();
}
}
private static Inet4Address[] getV4Addrs(List<InetAddress> addrs) {
int matchCount = 0;
for (InetAddress addr : addrs) {
if (addr instanceof Inet4Address) {
matchCount++;
}
}
Inet4Address[] matching = new Inet4Address[matchCount];
int i = 0;
for (InetAddress addr : addrs) {
if (addr instanceof Inet4Address) {
matching[i++] = (Inet4Address) addr;
}
}
return matching;
}
private static Inet6Address[] getV6Addrs(List<InetAddress> addrs) {
int matchCount = 0;
for (InetAddress addr : addrs) {
if (addr instanceof Inet6Address) {
matchCount++;
}
}
Inet6Address[] matching = new Inet6Address[matchCount];
int i = 0;
for (InetAddress addr : addrs) {
if (addr instanceof Inet6Address) {
matching[i++] = (Inet6Address) addr;
}
}
return matching;
}
}
@@ -10,38 +10,87 @@ import com.limelight.LimeLog;
import com.limelight.nvstream.http.ComputerDetails;
public class WakeOnLanSender {
private static final int[] PORTS_TO_TRY = new int[] {
// These ports will always be tried as-is.
private static final int[] STATIC_PORTS_TO_TRY = new int[] {
9, // Standard WOL port (privileged port)
47998, 47999, 48000, 48002, 48010, // Ports opened by GFE
47009, // Port opened by Moonlight Internet Hosting Tool for WoL (non-privileged port)
};
// These ports will be offset by the base port number (47989) to support alternate ports.
private static final int[] DYNAMIC_PORTS_TO_TRY = new int[] {
47998, 47999, 48000, 48002, 48010, // Ports opened by GFE
};
private static void sendPacketsForAddress(InetAddress address, int httpPort, DatagramSocket sock, byte[] payload) throws IOException {
IOException lastException = null;
boolean sentWolPacket = false;
// Try the static ports
for (int port : STATIC_PORTS_TO_TRY) {
try {
DatagramPacket dp = new DatagramPacket(payload, payload.length);
dp.setAddress(address);
dp.setPort(port);
sock.send(dp);
sentWolPacket = true;
} catch (IOException e) {
e.printStackTrace();
lastException = e;
}
}
// Try the dynamic ports
for (int port : DYNAMIC_PORTS_TO_TRY) {
try {
DatagramPacket dp = new DatagramPacket(payload, payload.length);
dp.setAddress(address);
dp.setPort((port - 47989) + httpPort);
sock.send(dp);
sentWolPacket = true;
} catch (IOException e) {
e.printStackTrace();
lastException = e;
}
}
if (!sentWolPacket) {
throw lastException;
}
}
public static void sendWolPacket(ComputerDetails computer) throws IOException {
DatagramSocket sock = new DatagramSocket(0);
byte[] payload = createWolPayload(computer);
IOException lastException = null;
boolean sentWolPacket = false;
try {
// Try all resolved remote and local addresses and IPv4 broadcast address.
try (final DatagramSocket sock = new DatagramSocket(0)) {
// Try all resolved remote and local addresses and broadcast addresses.
// The broadcast address is required to avoid stale ARP cache entries
// making the sleeping machine unreachable.
for (String unresolvedAddress : new String[] {
computer.localAddress, computer.remoteAddress, computer.manualAddress, computer.ipv6Address, "255.255.255.255"
for (ComputerDetails.AddressTuple address : new ComputerDetails.AddressTuple[] {
computer.localAddress, computer.remoteAddress,
computer.manualAddress, computer.ipv6Address,
}) {
if (unresolvedAddress == null) {
if (address == null) {
continue;
}
try {
for (InetAddress resolvedAddress : InetAddress.getAllByName(unresolvedAddress)) {
// Try all the ports for each resolved address
for (int port : PORTS_TO_TRY) {
DatagramPacket dp = new DatagramPacket(payload, payload.length);
dp.setAddress(resolvedAddress);
dp.setPort(port);
sock.send(dp);
sendPacketsForAddress(InetAddress.getByName("255.255.255.255"), address.port, sock, payload);
sentWolPacket = true;
} catch (IOException e) {
e.printStackTrace();
lastException = e;
}
try {
for (InetAddress resolvedAddress : InetAddress.getAllByName(address.address)) {
try {
sendPacketsForAddress(resolvedAddress, address.port, sock, payload);
sentWolPacket = true;
} catch (IOException e) {
e.printStackTrace();
lastException = e;
}
}
} catch (IOException e) {
@@ -52,8 +101,6 @@ public class WakeOnLanSender {
lastException = e;
}
}
} finally {
sock.close();
}
// Propagate the DNS resolution exception if we didn't
@@ -65,18 +112,20 @@ public class WakeOnLanSender {
private static byte[] macStringToBytes(String macAddress) {
byte[] macBytes = new byte[6];
@SuppressWarnings("resource")
Scanner scan = new Scanner(macAddress).useDelimiter(":");
for (int i = 0; i < macBytes.length && scan.hasNext(); i++) {
try {
macBytes[i] = (byte) Integer.parseInt(scan.next(), 16);
} catch (NumberFormatException e) {
LimeLog.warning("Malformed MAC address: "+macAddress+" (index: "+i+")");
break;
try (@SuppressWarnings("resource")
final Scanner scan = new Scanner(macAddress).useDelimiter(":")
) {
for (int i = 0; i < macBytes.length && scan.hasNext(); i++) {
try {
macBytes[i] = (byte) Integer.parseInt(scan.next(), 16);
} catch (NumberFormatException e) {
LimeLog.warning("Malformed MAC address: " + macAddress + " (index: " + i + ")");
break;
}
}
return macBytes;
}
scan.close();
return macBytes;
}
private static byte[] createWolPayload(ComputerDetails computer) {
@@ -6,6 +6,8 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.concurrent.LinkedBlockingQueue;
@@ -96,8 +98,31 @@ public class AddComputerManually extends Activity {
}
}
private void doAddPc(String host) throws InterruptedException {
private URI parseRawUserInputToUri(String rawUserInput) {
try {
// Try adding a scheme and parsing the remaining input.
// This handles input like 127.0.0.1:47989, [::1], [::1]:47989, and 127.0.0.1.
URI uri = new URI("moonlight://" + rawUserInput);
if (uri.getHost() != null && !uri.getHost().isEmpty()) {
return uri;
}
} catch (URISyntaxException ignored) {}
try {
// Attempt to escape the input as an IPv6 literal.
// This handles input like ::1.
URI uri = new URI("moonlight://[" + rawUserInput + "]");
if (uri.getHost() != null && !uri.getHost().isEmpty()) {
return uri;
}
} catch (URISyntaxException ignored) {}
return null;
}
private void doAddPc(String rawUserInput) throws InterruptedException {
boolean wrongSiteLocal = false;
boolean invalidInput = false;
boolean success;
int portTestResult;
@@ -106,8 +131,28 @@ public class AddComputerManually extends Activity {
try {
ComputerDetails details = new ComputerDetails();
details.manualAddress = host;
success = managerBinder.addComputerBlocking(details);
// Check if we parsed a host address successfully
URI uri = parseRawUserInputToUri(rawUserInput);
if (uri != null && uri.getHost() != null && !uri.getHost().isEmpty()) {
String host = uri.getHost();
int port = uri.getPort();
// If a port was not specified, use the default
if (port == -1) {
port = NvHTTP.DEFAULT_HTTP_PORT;
}
details.manualAddress = new ComputerDetails.AddressTuple(host, port);
success = managerBinder.addComputerBlocking(details);
if (!success){
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
}
} else {
// Invalid user input
success = false;
invalidInput = true;
}
} catch (InterruptedException e) {
// Propagate the InterruptedException to the caller for proper handling
dialog.dismiss();
@@ -117,13 +162,11 @@ public class AddComputerManually extends Activity {
// https://github.com/square/okhttp/blob/okhttp_27/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java#L705
e.printStackTrace();
success = false;
invalidInput = true;
}
// Keep the SpinnerDialog open while testing connectivity
if (!success){
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
}
if (!success && !wrongSiteLocal) {
if (!success && !wrongSiteLocal && !invalidInput) {
// Run the test before dismissing the spinner because it can take a few seconds.
portTestResult = MoonBridge.testClientConnectivity(ServerHelper.CONNECTION_TEST_SERVER, 443,
MoonBridge.ML_PORT_FLAG_TCP_47984 | MoonBridge.ML_PORT_FLAG_TCP_47989);
@@ -134,7 +177,10 @@ public class AddComputerManually extends Activity {
dialog.dismiss();
if (wrongSiteLocal) {
if (invalidInput) {
Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title), getResources().getString(R.string.addpc_unknown_host), false);
}
else if (wrongSiteLocal) {
Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title), getResources().getString(R.string.addpc_wrong_sitelocal), false);
}
else if (!success) {
@@ -10,6 +10,13 @@ import android.view.Display;
import com.limelight.nvstream.jni.MoonBridge;
public class PreferenceConfiguration {
public enum FormatOption {
AUTO,
FORCE_AV1,
FORCE_HEVC,
FORCE_H264,
};
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";
@@ -48,6 +55,10 @@ public class PreferenceConfiguration {
private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode";
private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx";
private static final String REDUCE_REFRESH_RATE_PREF_STRING = "checkbox_reduce_refresh_rate";
private static final String FULL_RANGE_PREF_STRING = "checkbox_full_range";
private static final String GAMEPAD_TOUCHPAD_AS_MOUSE_PREF_STRING = "checkbox_gamepad_touchpad_as_mouse";
private static final String GAMEPAD_MOTION_SENSORS_PREF_STRING = "checkbox_gamepad_motion_sensors";
private static final String GAMEPAD_MOTION_FALLBACK_PREF_STRING = "checkbox_gamepad_motion_fallback";
static final String DEFAULT_RESOLUTION = "1280x720";
static final String DEFAULT_FPS = "60";
@@ -61,6 +72,7 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_MULTI_CONTROLLER = true;
private static final boolean DEFAULT_USB_DRIVER = true;
private static final String DEFAULT_VIDEO_FORMAT = "auto";
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
private static final boolean ONLY_L3_R3_DEFAULT = false;
private static final boolean DEFAULT_ENABLE_HDR = false;
@@ -80,10 +92,10 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_ABSOLUTE_MOUSE_MODE = false;
private static final boolean DEFAULT_ENABLE_AUDIO_FX = false;
private static final boolean DEFAULT_REDUCE_REFRESH_RATE = false;
public static final int FORCE_H265_ON = -1;
public static final int AUTOSELECT_H265 = 0;
public static final int FORCE_H265_OFF = 1;
private static final boolean DEFAULT_FULL_RANGE = false;
private static final boolean DEFAULT_GAMEPAD_TOUCHPAD_AS_MOUSE = false;
private static final boolean DEFAULT_GAMEPAD_MOTION_SENSORS = true;
private static final boolean DEFAULT_GAMEPAD_MOTION_FALLBACK = false;
public static final int FRAME_PACING_MIN_LATENCY = 0;
public static final int FRAME_PACING_BALANCED = 1;
@@ -100,7 +112,7 @@ public class PreferenceConfiguration {
public int width, height, fps;
public int bitrate;
public int videoFormat;
public FormatOption videoFormat;
public int deadzonePercentage;
public int oscOpacity;
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
@@ -124,6 +136,10 @@ public class PreferenceConfiguration {
public boolean absoluteMouseMode;
public boolean enableAudioFx;
public boolean reduceRefreshRate;
public boolean fullRange;
public boolean gamepadMotionSensors;
public boolean gamepadTouchpadAsMouse;
public boolean gamepadMotionSensorsFallbackToDevice;
public static boolean isNativeResolution(int width, int height) {
// It's not a native resolution if it matches an existing resolution option
@@ -230,33 +246,62 @@ public class PreferenceConfiguration {
int height = getHeightFromResolutionString(resString);
int fps = Integer.parseInt(fpsString);
// This table prefers 16:10 resolutions because they are
// only slightly more pixels than the 16:9 equivalents, so
// we don't want to bump those 16:10 resolutions up to the
// next 16:9 slot.
//
// This logic is shamelessly stolen from Moonlight Qt:
// https://github.com/moonlight-stream/moonlight-qt/blob/master/app/settings/streamingpreferences.cpp
if (width * height <= 640 * 360) {
return (int)(1000 * (fps / 30.0));
}
else if (width * height <= 854 * 480) {
return (int)(1500 * (fps / 30.0));
}
// This covers 1280x720 and 1280x800 too
else if (width * height <= 1366 * 768) {
return (int)(5000 * (fps / 30.0));
}
else if (width * height <= 1920 * 1200) {
return (int)(10000 * (fps / 30.0));
}
else if (width * height <= 2560 * 1600) {
return (int)(20000 * (fps / 30.0));
}
else /* if (width * height <= 3840 * 2160) */ {
return (int)(40000 * (fps / 30.0));
// Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear
// bitrate increase for frame rate once we get to values that high.
double frameRateFactor = (fps <= 60 ? fps : (Math.sqrt(fps / 60.f) * 60.f)) / 30.f;
// TODO: Collect some empirical data to see if these defaults make sense.
// We're just using the values that the Shield used, as we have for years.
int[] pixelVals = {
640 * 360,
854 * 480,
1280 * 720,
1920 * 1080,
2560 * 1440,
3840 * 2160,
-1,
};
int[] factorVals = {
1,
2,
5,
10,
20,
40,
-1
};
// Calculate the resolution factor by linear interpolation of the resolution table
float resolutionFactor;
int pixels = width * height;
for (int i = 0; ; i++) {
if (pixels == pixelVals[i]) {
// We can bail immediately for exact matches
resolutionFactor = factorVals[i];
break;
}
else if (pixels < pixelVals[i]) {
if (i == 0) {
// Never go below the lowest resolution entry
resolutionFactor = factorVals[i];
}
else {
// Interpolate between the entry greater than the chosen resolution (i) and the entry less than the chosen resolution (i-1)
resolutionFactor = ((float)(pixels - pixelVals[i-1]) / (pixelVals[i] - pixelVals[i-1])) * (factorVals[i] - factorVals[i-1]) + factorVals[i-1];
}
break;
}
else if (pixelVals[i] == -1) {
// Never go above the highest resolution entry
resolutionFactor = factorVals[i-1];
break;
}
}
return (int)Math.round(resolutionFactor * frameRateFactor) * 1000;
}
public static boolean getDefaultSmallMode(Context context) {
@@ -286,22 +331,25 @@ public class PreferenceConfiguration {
prefs.getString(FPS_PREF_STRING, DEFAULT_FPS));
}
private static int getVideoFormatValue(Context context) {
private static FormatOption getVideoFormatValue(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String str = prefs.getString(VIDEO_FORMAT_PREF_STRING, DEFAULT_VIDEO_FORMAT);
if (str.equals("auto")) {
return AUTOSELECT_H265;
return FormatOption.AUTO;
}
else if (str.equals("forceav1")) {
return FormatOption.FORCE_AV1;
}
else if (str.equals("forceh265")) {
return FORCE_H265_ON;
return FormatOption.FORCE_HEVC;
}
else if (str.equals("neverh265")) {
return FORCE_H265_OFF;
return FormatOption.FORCE_H264;
}
else {
// Should never get here
return AUTOSELECT_H265;
return FormatOption.AUTO;
}
}
@@ -348,6 +396,7 @@ public class PreferenceConfiguration {
.remove(VIDEO_FORMAT_PREF_STRING)
.remove(ENABLE_HDR_PREF_STRING)
.remove(UNLOCK_FPS_STRING)
.remove(FULL_RANGE_PREF_STRING)
.apply();
}
@@ -454,6 +503,15 @@ public class PreferenceConfiguration {
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
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, prefs.getInt(BITRATE_PREF_OLD_STRING, 0) * 1000);
if (config.bitrate == 0) {
@@ -505,6 +563,10 @@ public class PreferenceConfiguration {
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
config.reduceRefreshRate = prefs.getBoolean(REDUCE_REFRESH_RATE_PREF_STRING, DEFAULT_REDUCE_REFRESH_RATE);
config.fullRange = prefs.getBoolean(FULL_RANGE_PREF_STRING, DEFAULT_FULL_RANGE);
config.gamepadTouchpadAsMouse = prefs.getBoolean(GAMEPAD_TOUCHPAD_AS_MOUSE_PREF_STRING, DEFAULT_GAMEPAD_TOUCHPAD_AS_MOUSE);
config.gamepadMotionSensors = prefs.getBoolean(GAMEPAD_MOTION_SENSORS_PREF_STRING, DEFAULT_GAMEPAD_MOTION_SENSORS);
config.gamepadMotionSensorsFallbackToDevice = prefs.getBoolean(GAMEPAD_MOTION_FALLBACK_PREF_STRING, DEFAULT_GAMEPAD_MOTION_FALLBACK);
return config;
}
@@ -123,6 +123,7 @@ public class StreamSettings extends Activity {
public static class SettingsFragment extends PreferenceFragment {
private int nativeResolutionStartIndex = Integer.MAX_VALUE;
private boolean nativeFramerateShown = false;
private void setValue(String preferenceKey, String value) {
ListPreference pref = (ListPreference) findPreference(preferenceKey);
@@ -130,6 +131,18 @@ public class StreamSettings extends Activity {
pref.setValue(value);
}
private void appendPreferenceEntry(ListPreference pref, String newEntryName, String newEntryValue) {
CharSequence[] newEntries = Arrays.copyOf(pref.getEntries(), pref.getEntries().length + 1);
CharSequence[] newValues = Arrays.copyOf(pref.getEntryValues(), pref.getEntryValues().length + 1);
// Add the new option
newEntries[newEntries.length - 1] = newEntryName;
newValues[newValues.length - 1] = newEntryValue;
pref.setEntries(newEntries);
pref.setEntryValues(newValues);
}
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved, boolean portrait) {
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
@@ -155,29 +168,18 @@ public class StreamSettings extends Activity {
String newValue = nativeWidth+"x"+nativeHeight;
CharSequence[] values = pref.getEntryValues();
// Check if the native resolution is already present
for (CharSequence value : values) {
for (CharSequence value : pref.getEntryValues()) {
if (newValue.equals(value.toString())) {
// It is present in the default list, so don't add it again
return;
}
}
CharSequence[] newEntries = Arrays.copyOf(pref.getEntries(), pref.getEntries().length + 1);
CharSequence[] newValues = Arrays.copyOf(values, values.length + 1);
// Add the new native option
newEntries[newEntries.length - 1] = newName;
newValues[newValues.length - 1] = newValue;
pref.setEntries(newEntries);
pref.setEntryValues(newValues);
if (newValues.length - 1 < nativeResolutionStartIndex) {
nativeResolutionStartIndex = newValues.length - 1;
if (pref.getEntryValues().length < nativeResolutionStartIndex) {
nativeResolutionStartIndex = pref.getEntryValues().length;
}
appendPreferenceEntry(pref, newName, newValue);
}
private void addNativeResolutionEntries(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
@@ -187,6 +189,30 @@ public class StreamSettings extends Activity {
addNativeResolutionEntry(nativeWidth, nativeHeight, insetsRemoved, false);
}
private void addNativeFrameRateEntry(float framerate) {
int frameRateRounded = Math.round(framerate);
if (frameRateRounded == 0) {
return;
}
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.FPS_PREF_STRING);
String fpsValue = Integer.toString(frameRateRounded);
String fpsName = getResources().getString(R.string.resolution_prefix_native) +
" (" + fpsValue + " " + getResources().getString(R.string.fps_suffix_fps) + ")";
// Check if the native frame rate is already present
for (CharSequence value : pref.getEntryValues()) {
if (fpsValue.equals(value.toString())) {
// It is present in the default list, so don't add it again
nativeFramerateShown = false;
return;
}
}
appendPreferenceEntry(pref, fpsName, fpsValue);
nativeFramerateShown = true;
}
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
int matchingCount = 0;
@@ -252,19 +278,10 @@ public class StreamSettings extends Activity {
PreferenceScreen screen = getPreferenceScreen();
// hide on-screen controls category on non touch screen devices
if (!getActivity().getPackageManager().
hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
{
PreferenceCategory category =
(PreferenceCategory) findPreference("category_onscreen_controls");
screen.removePreference(category);
}
{
PreferenceCategory category =
(PreferenceCategory) findPreference("category_input_settings");
category.removePreference(findPreference("checkbox_touchscreen_trackpad"));
}
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_onscreen_controls");
screen.removePreference(category);
}
// Hide remote desktop mouse mode on pre-Oreo (which doesn't have pointer capture)
@@ -276,6 +293,30 @@ public class StreamSettings extends Activity {
category.removePreference(findPreference("checkbox_absolute_mouse_mode"));
}
// Hide gamepad motion sensor option when running on OSes before Android 12.
// Support for motion, LED, battery, and other extensions were introduced in S.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_gamepad_settings");
category.removePreference(findPreference("checkbox_gamepad_motion_sensors"));
}
// Hide gamepad motion sensor fallback option if the device has no gyro or accelerometer
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER) &&
!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE)) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_gamepad_settings");
category.removePreference(findPreference("checkbox_gamepad_motion_fallback"));
}
// Hide USB driver options on devices without USB host support
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_gamepad_settings");
category.removePreference(findPreference("checkbox_usb_bind_all"));
category.removePreference(findPreference("checkbox_usb_driver"));
}
// Remove PiP mode on devices pre-Oreo, where the feature is not available (some low RAM devices),
// and on Fire OS where it violates the Amazon App Store guidelines for some reason.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
@@ -296,7 +337,7 @@ public class StreamSettings extends Activity {
// Remove the vibration options if the device can't vibrate
if (!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_input_settings");
(PreferenceCategory) findPreference("category_gamepad_settings");
category.removePreference(findPreference("checkbox_vibrate_fallback"));
// The entire OSC category may have already been removed by the touchscreen check above
@@ -306,12 +347,11 @@ public class StreamSettings extends Activity {
}
}
int maxSupportedFps = 0;
Display display = getActivity().getWindowManager().getDefaultDisplay();
float maxSupportedFps = display.getRefreshRate();
// Hide non-supported resolution/FPS combinations
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Display display = getActivity().getWindowManager().getDefaultDisplay();
int maxSupportedResW = 0;
// Add a native resolution with any insets included for users that don't want content
@@ -379,7 +419,7 @@ public class StreamSettings extends Activity {
}
if (candidate.getRefreshRate() > maxSupportedFps) {
maxSupportedFps = (int)candidate.getRefreshRate();
maxSupportedFps = candidate.getRefreshRate();
}
}
@@ -472,7 +512,7 @@ public class StreamSettings extends Activity {
// getRealMetrics() function (unlike the lies that getWidth() and getHeight()
// tell to us).
DisplayMetrics metrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
display.getRealMetrics(metrics);
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
addNativeResolutionEntries(width, height, false);
@@ -480,7 +520,6 @@ public class StreamSettings extends Activity {
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");
@@ -517,6 +556,7 @@ public class StreamSettings extends Activity {
}
// Never remove 30 FPS or 60 FPS
}
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.
@@ -570,7 +610,6 @@ public class StreamSettings extends Activity {
category.removePreference(findPreference("checkbox_enable_hdr"));
}
else {
Display display = getActivity().getWindowManager().getDefaultDisplay();
Display.HdrCapabilities hdrCaps = display.getHdrCapabilities();
// We must now ensure our display is compatible with HDR10
@@ -641,6 +680,15 @@ public class StreamSettings extends Activity {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
String valueStr = (String) newValue;
// If this is native frame rate, show the warning dialog
CharSequence[] values = ((ListPreference)preference).getEntryValues();
if (nativeFramerateShown && values[values.length - 1].toString().equals(newValue.toString())) {
Dialog.displayDialog(getActivity(),
getResources().getString(R.string.title_native_fps_dialog),
getResources().getString(R.string.text_native_res_dialog),
false);
}
// Write the new bitrate value
resetBitrateToDefault(prefs, null, valueStr);
@@ -44,4 +44,8 @@ public class HelpLauncher {
public static void launchTroubleshooting(Context context) {
launchUrl(context, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
}
public static void launchGameStreamEolFaq(Context context) {
launchUrl(context, "https://github.com/moonlight-stream/moonlight-docs/wiki/NVIDIA-GameStream-End-Of-Service-Announcement-FAQ");
}
}
@@ -6,13 +6,12 @@ import android.widget.Toast;
import com.limelight.AppView;
import com.limelight.Game;
import com.limelight.PcView;
import com.limelight.R;
import com.limelight.ShortcutTrampoline;
import com.limelight.binding.PlatformBinding;
import com.limelight.computers.ComputerManagerService;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.GfeHttpResponseException;
import com.limelight.nvstream.http.HostHttpResponseException;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.NvHTTP;
import com.limelight.nvstream.jni.MoonBridge;
@@ -27,7 +26,7 @@ import java.security.cert.CertificateEncodingException;
public class ServerHelper {
public static final String CONNECTION_TEST_SERVER = "android.conntest.moonlight-stream.org";
public static String getCurrentAddressFromComputer(ComputerDetails computer) throws IOException {
public static ComputerDetails.AddressTuple getCurrentAddressFromComputer(ComputerDetails computer) throws IOException {
if (computer.activeAddress == null) {
throw new IOException("No active address for "+computer.name);
}
@@ -56,7 +55,9 @@ public class ServerHelper {
public static Intent createStartIntent(Activity parent, NvApp app, ComputerDetails computer,
ComputerManagerService.ComputerManagerBinder managerBinder) {
Intent intent = new Intent(parent, Game.class);
intent.putExtra(Game.EXTRA_HOST, computer.activeAddress);
intent.putExtra(Game.EXTRA_HOST, computer.activeAddress.address);
intent.putExtra(Game.EXTRA_PORT, computer.activeAddress.port);
intent.putExtra(Game.EXTRA_HTTPS_PORT, computer.httpsPort);
intent.putExtra(Game.EXTRA_APP_NAME, app.getAppName());
intent.putExtra(Game.EXTRA_APP_ID, app.getAppId());
intent.putExtra(Game.EXTRA_APP_HDR, app.isHdrSupported());
@@ -126,14 +127,14 @@ public class ServerHelper {
NvHTTP httpConn;
String message;
try {
httpConn = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer),
httpConn = new NvHTTP(ServerHelper.getCurrentAddressFromComputer(computer), computer.httpsPort,
managerBinder.getUniqueId(), computer.serverCert, PlatformBinding.getCryptoProvider(parent));
if (httpConn.quitApp()) {
message = parent.getResources().getString(R.string.applist_quit_success) + " " + app.getAppName();
} else {
message = parent.getResources().getString(R.string.applist_quit_fail) + " " + app.getAppName();
}
} catch (GfeHttpResponseException e) {
} catch (HostHttpResponseException e) {
if (e.getErrorCode() == 599) {
message = "This session wasn't started by this device," +
" so it cannot be quit. End streaming on the original " +
@@ -29,37 +29,37 @@ public class UiHelper {
private static final int TV_VERTICAL_PADDING_DP = 15;
private static final int TV_HORIZONTAL_PADDING_DP = 15;
private static void setGameModeStatus(Context context, boolean streaming, boolean loading, boolean interruptible) {
private static void setGameModeStatus(Context context, boolean streaming, boolean interruptible) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
GameManager gameManager = context.getSystemService(GameManager.class);
if (streaming) {
gameManager.setGameState(new GameState(loading, interruptible ? GameState.MODE_GAMEPLAY_INTERRUPTIBLE : GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE));
gameManager.setGameState(new GameState(false, interruptible ? GameState.MODE_GAMEPLAY_INTERRUPTIBLE : GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE));
}
else {
gameManager.setGameState(new GameState(loading, GameState.MODE_NONE));
gameManager.setGameState(new GameState(false, GameState.MODE_NONE));
}
}
}
public static void notifyStreamConnecting(Context context) {
setGameModeStatus(context, true, true, true);
setGameModeStatus(context, true, true);
}
public static void notifyStreamConnected(Context context) {
setGameModeStatus(context, true, false, false);
setGameModeStatus(context, true, false);
}
public static void notifyStreamEnteringPiP(Context context) {
setGameModeStatus(context, true, false, true);
setGameModeStatus(context, true, true);
}
public static void notifyStreamExitingPiP(Context context) {
setGameModeStatus(context, true, false, false);
setGameModeStatus(context, true, false);
}
public static void notifyStreamEnded(Context context) {
setGameModeStatus(context, false, false, false);
setGameModeStatus(context, false, false);
}
public static void setLocale(Activity activity)
@@ -115,7 +115,7 @@ public class UiHelper {
UiModeManager modeMgr = (UiModeManager) activity.getSystemService(Context.UI_MODE_SERVICE);
// Set GameState.MODE_NONE initially for all activities
setGameModeStatus(activity, false, false, false);
setGameModeStatus(activity, false, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Allow this non-streaming activity to layout under notches.
@@ -40,6 +40,7 @@ LOCAL_SRC_FILES := moonlight-common-c/src/AudioStream.c \
moonlight-common-c/enet/win32.c \
simplejni.c \
callbacks.c \
minisdl.c \
LOCAL_C_INCLUDES := $(LOCAL_PATH)/moonlight-common-c/enet/include \
+67 -11
View File
@@ -33,6 +33,9 @@ static jmethodID BridgeClConnectionTerminatedMethod;
static jmethodID BridgeClRumbleMethod;
static jmethodID BridgeClConnectionStatusUpdateMethod;
static jmethodID BridgeClSetHdrModeMethod;
static jmethodID BridgeClRumbleTriggersMethod;
static jmethodID BridgeClSetMotionEventStateMethod;
static jmethodID BridgeClSetControllerLEDMethod;
static jbyteArray DecodedFrameBuffer;
static jshortArray DecodedAudioBuffer;
@@ -80,7 +83,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
BridgeDrStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStart", "()V");
BridgeDrStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStop", "()V");
BridgeDrCleanupMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrCleanup", "()V");
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIIJJ)I");
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIICJJ)I");
BridgeArInitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArInit", "(III)I");
BridgeArStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStart", "()V");
BridgeArStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStop", "()V");
@@ -93,7 +96,10 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
BridgeClConnectionTerminatedMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionTerminated", "(I)V");
BridgeClRumbleMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClRumble", "(SSS)V");
BridgeClConnectionStatusUpdateMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionStatusUpdate", "(I)V");
BridgeClSetHdrModeMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetHdrMode", "(Z)V");
BridgeClSetHdrModeMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetHdrMode", "(Z[B)V");
BridgeClRumbleTriggersMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClRumbleTriggers", "(SSS)V");
BridgeClSetMotionEventStateMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetMotionEventState", "(SBS)V");
BridgeClSetControllerLEDMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetControllerLED", "(SBBB)V");
}
int BridgeDrSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
@@ -159,7 +165,7 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, currentEntry->length, currentEntry->bufferType,
decodeUnit->frameNumber, decodeUnit->frameType,
decodeUnit->frameNumber, decodeUnit->frameType, (jchar)decodeUnit->frameHostProcessingLatency,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
@@ -180,7 +186,7 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, offset, BUFFER_TYPE_PICDATA,
decodeUnit->frameNumber, decodeUnit->frameType,
decodeUnit->frameNumber, decodeUnit->frameType, (jchar)decodeUnit->frameHostProcessingLatency,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
@@ -331,7 +337,50 @@ void BridgeClConnectionStatusUpdate(int connectionStatus) {
void BridgeClSetHdrMode(bool enabled) {
JNIEnv* env = GetThreadEnv();
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetHdrModeMethod, enabled);
jbyteArray hdrMetadataByteArray = NULL;
SS_HDR_METADATA hdrMetadata;
// Check if HDR metadata was provided
if (enabled && LiGetHdrMetadata(&hdrMetadata)) {
hdrMetadataByteArray = (*env)->NewByteArray(env, sizeof(SS_HDR_METADATA));
(*env)->SetByteArrayRegion(env, hdrMetadataByteArray, 0, sizeof(SS_HDR_METADATA), (jbyte*)&hdrMetadata);
}
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetHdrModeMethod, enabled, hdrMetadataByteArray);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
}
}
void BridgeClRumbleTriggers(unsigned short controllerNumber, unsigned short leftTrigger, unsigned short rightTrigger) {
JNIEnv* env = GetThreadEnv();
// The seemingly redundant short casts are required in order to convert the unsigned short to a signed short.
// If we leave it as an unsigned short, CheckJNI will fail when the value exceeds 32767. The cast itself is
// fine because the Java code treats the value as unsigned even though it's stored in a signed type.
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClRumbleTriggersMethod, controllerNumber, (short)leftTrigger, (short)rightTrigger);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
}
}
void BridgeClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) {
JNIEnv* env = GetThreadEnv();
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetMotionEventStateMethod, controllerNumber, motionType, reportRateHz);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
}
}
void BridgeClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b) {
JNIEnv* env = GetThreadEnv();
// These jbyte casts are necessary to satisfy CheckJNI
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetControllerLEDMethod, controllerNumber, (jbyte)r, (jbyte)g, (jbyte)b);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
@@ -372,26 +421,31 @@ static CONNECTION_LISTENER_CALLBACKS BridgeConnListenerCallbacks = {
.rumble = BridgeClRumble,
.connectionStatusUpdate = BridgeClConnectionStatusUpdate,
.setHdrMode = BridgeClSetHdrMode,
.rumbleTriggers = BridgeClRumbleTriggers,
.setMotionEventState = BridgeClSetMotionEventState,
.setControllerLED = BridgeClSetControllerLED,
};
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass clazz,
jstring address, jstring appVersion, jstring gfeVersion,
jstring rtspSessionUrl,
jstring rtspSessionUrl, jint serverCodecModeSupport,
jint width, jint height, jint fps,
jint bitrate, jint packetSize, jint streamingRemotely,
jint audioConfiguration, jboolean supportsHevc,
jboolean enableHdr,
jint audioConfiguration, jint supportedVideoFormats,
jint hevcBitratePercentageMultiplier,
jint av1BitratePercentageMultiplier,
jint clientRefreshRateX100,
jint encryptionFlags,
jbyteArray riAesKey, jbyteArray riAesIv,
jint videoCapabilities) {
jint videoCapabilities,
jint colorSpace, jint colorRange) {
SERVER_INFORMATION serverInfo = {
.address = (*env)->GetStringUTFChars(env, address, 0),
.serverInfoAppVersion = (*env)->GetStringUTFChars(env, appVersion, 0),
.serverInfoGfeVersion = gfeVersion ? (*env)->GetStringUTFChars(env, gfeVersion, 0) : NULL,
.rtspSessionUrl = rtspSessionUrl ? (*env)->GetStringUTFChars(env, rtspSessionUrl, 0) : NULL,
.serverCodecModeSupport = serverCodecModeSupport,
};
STREAM_CONFIGURATION streamConfig = {
.width = width,
@@ -401,11 +455,13 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
.packetSize = packetSize,
.streamingRemotely = streamingRemotely,
.audioConfiguration = audioConfiguration,
.supportsHevc = supportsHevc,
.enableHdr = enableHdr,
.supportedVideoFormats = supportedVideoFormats,
.hevcBitratePercentageMultiplier = hevcBitratePercentageMultiplier,
.av1BitratePercentageMultiplier = av1BitratePercentageMultiplier,
.clientRefreshRateX100 = clientRefreshRateX100,
.encryptionFlags = encryptionFlags,
.colorSpace = colorSpace,
.colorRange = colorRange
};
jbyte* riAesKeyBuf = (*env)->GetByteArrayElements(env, riAesKey, NULL);
@@ -0,0 +1,592 @@
/*
Copyright (C) Valve Corporation
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#define MAKE_CONTROLLER_ID( nVID, nPID ) (unsigned int)( (unsigned int)nVID << 16 | (unsigned int)nPID )
static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x0079, 0x181a ), k_eControllerType_PS3Controller, NULL }, // Venom Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0079, 0x1844 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x044f, 0xb315 ), k_eControllerType_PS3Controller, NULL }, // Firestorm Dual Analog 3
{ MAKE_CONTROLLER_ID( 0x044f, 0xd007 ), k_eControllerType_PS3Controller, NULL }, // Thrustmaster wireless 3-1
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc24f ), k_eControllerType_PS3Controller, NULL }, // Logitech G29 (PS3)
{ MAKE_CONTROLLER_ID( 0x054c, 0x0268 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x200f ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x056e, 0x2013 ), k_eControllerType_PS3Controller, NULL }, // JC-U4113SBK
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1004 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1006 ), k_eControllerType_PS3Controller, NULL }, // JC-U3412SBK
{ MAKE_CONTROLLER_ID( 0x06a3, 0xf622 ), k_eControllerType_PS3Controller, NULL }, // Cyborg V3
{ MAKE_CONTROLLER_ID( 0x0738, 0x3180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS3 mode
{ MAKE_CONTROLLER_ID( 0x0738, 0x3250 ), k_eControllerType_PS3Controller, NULL }, // madcats fightpad pro ps3
{ MAKE_CONTROLLER_ID( 0x0738, 0x3481 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz FightStick TE 2+ PS3
{ MAKE_CONTROLLER_ID( 0x0738, 0x8180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS4 mode (no touchpad on device)
{ MAKE_CONTROLLER_ID( 0x0738, 0x8838 ), k_eControllerType_PS3Controller, NULL }, // Madcatz Fightstick Pro
{ MAKE_CONTROLLER_ID( 0x0810, 0x0001 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
{ MAKE_CONTROLLER_ID( 0x0810, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
{ MAKE_CONTROLLER_ID( 0x0925, 0x0005 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x0925, 0x8866 ), k_eControllerType_PS3Controller, NULL }, // PS2 maybe break out later
{ MAKE_CONTROLLER_ID( 0x0925, 0x8888 ), k_eControllerType_PS3Controller, NULL }, // Actually ps2 -maybe break out later Lakeview Research WiseGroup Ltd, MP-8866 Dual Joypad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0109 ), k_eControllerType_PS3Controller, NULL }, // PDP Versus Fighting Pad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011e ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS4
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0128 ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS3
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0214 ), k_eControllerType_PS3Controller, NULL }, // afterglow ps3
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1314 ), k_eControllerType_PS3Controller, NULL }, // PDP Afterglow Wireless PS3 controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x6302 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x0008 ), k_eControllerType_PS3Controller, NULL }, // Green Asia
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x3075 ), k_eControllerType_PS3Controller, NULL }, // SpeedLink Strike FX
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x310d ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0009 ), k_eControllerType_PS3Controller, NULL }, // HORI BDA GP1
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x004d ), k_eControllerType_PS3Controller, NULL }, // Horipad 3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005f ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander 4 PS3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006a ), k_eControllerType_PS3Controller, NULL }, // Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006e ), k_eControllerType_PS3Controller, NULL }, // HORI horipad4 ps3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0085 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PS3
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0086 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PC (Uses the Xbox 360 protocol, but has PS3 buttons)
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0088 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Stick mini 4
{ MAKE_CONTROLLER_ID( 0x0f30, 0x1100 ), k_eControllerType_PS3Controller, NULL }, // Qanba Q1 fight stick
{ MAKE_CONTROLLER_ID( 0x11ff, 0x3331 ), k_eControllerType_PS3Controller, NULL }, // SRXJ-PH2400
{ MAKE_CONTROLLER_ID( 0x1345, 0x1000 ), k_eControllerType_PS3Controller, NULL }, // PS2 ACME GA-D5
{ MAKE_CONTROLLER_ID( 0x1345, 0x6005 ), k_eControllerType_PS3Controller, NULL }, // ps2 maybe break out later
{ MAKE_CONTROLLER_ID( 0x146b, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x1a34, 0x0836 ), k_eControllerType_PS3Controller, NULL }, // Afterglow PS3
{ MAKE_CONTROLLER_ID( 0x20bc, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // ShanWan PS3
{ MAKE_CONTROLLER_ID( 0x20d6, 0x576d ), k_eControllerType_PS3Controller, NULL }, // Power A PS3
{ MAKE_CONTROLLER_ID( 0x20d6, 0xca6d ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x2563, 0x0523 ), k_eControllerType_PS3Controller, NULL }, // Digiflip GP006
{ MAKE_CONTROLLER_ID( 0x2563, 0x0575 ), k_eControllerType_PS3Controller, NULL }, // From SDL
{ MAKE_CONTROLLER_ID( 0x25f0, 0x83c3 ), k_eControllerType_PS3Controller, NULL }, // gioteck vx2
{ MAKE_CONTROLLER_ID( 0x25f0, 0xc121 ), k_eControllerType_PS3Controller, NULL }, //
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2003 ), k_eControllerType_PS3Controller, NULL }, // Qanba Drone
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2302 ), k_eControllerType_PS3Controller, NULL }, // Qanba Obsidian
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2502 ), k_eControllerType_PS3Controller, NULL }, // Qanba Dragon
{ MAKE_CONTROLLER_ID( 0x8380, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // BTP 2163
{ MAKE_CONTROLLER_ID( 0x8888, 0x0308 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x181b ), k_eControllerType_PS4Controller, NULL }, // Venom Arcade Stick - XXX:this may not work and may need to be called a ps3 controller
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc260 ), k_eControllerType_PS4Controller, NULL }, // Logitech G29 (PS4)
{ MAKE_CONTROLLER_ID( 0x044f, 0xd00e ), k_eControllerType_PS4Controller, NULL }, // Thrustmaster Eswap Pro - No gyro and lightbar doesn't change color. Works otherwise
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c4 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c5 ), k_eControllerType_PS4Controller, NULL }, // STRIKEPAD PS4 Grip Add-on
{ MAKE_CONTROLLER_ID( 0x054c, 0x09cc ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Slim Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ba0 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller (Wireless dongle)
{ MAKE_CONTROLLER_ID( 0x0738, 0x8250 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightPad Pro PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8384 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE S+ PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8480 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2 PS4
{ MAKE_CONTROLLER_ID( 0x0738, 0x8481 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2+ PS4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e10 ), k_eControllerType_PS4Controller, NULL }, // Armor Armor 3 Pad PS4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e13 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e15 ), k_eControllerType_PS4Controller, NULL }, // Game:Pad 4
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e20 ), k_eControllerType_PS4Controller, NULL }, // Brook Mars Controller - needs FW update to show up as Ps4 controller on PC. Has Gyro but touchpad is a single button.
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0055 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005e ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander 4 PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0066 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS Plus
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0084 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander PS4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0087 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Stick mini 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008a ), k_eControllerType_PS4Controller, NULL }, // HORI Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x009c ), k_eControllerType_PS4Controller, NULL }, // HORI TAC PRO mousething
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a0 ), k_eControllerType_PS4Controller, NULL }, // HORI TAC4 mousething
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ed ), k_eControllerType_XInputPS4Controller, NULL }, // Hori Fighting Stick mini 4 kai - becomes an Xbox 360 controller on PC
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ee ), k_eControllerType_PS4Controller, NULL }, // Hori mini wired https://www.playstation.com/en-us/explore/accessories/gaming-controllers/mini-wired-gamepad/
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011c ), k_eControllerType_PS4Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0123 ), k_eControllerType_PS4Controller, NULL }, // HORI Wireless Controller Light (Japan only) - only over bt- over usb is xbox and pid 0x0124
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0162 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0164 ), k_eControllerType_XInputPS4Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x11c0, 0x4001 ), k_eControllerType_PS4Controller, NULL }, // "PS4 Fun Controller" added from user log
{ MAKE_CONTROLLER_ID( 0x146b, 0x0603 ), k_eControllerType_XInputPS4Controller, NULL }, // Nacon PS4 Compact Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0604 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Daija Arcade Stick
{ MAKE_CONTROLLER_ID( 0x146b, 0x0605 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON PS4 controller in Xbox mode - might also be other bigben brand xbox controllers
{ MAKE_CONTROLLER_ID( 0x146b, 0x0606 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Unknown Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0609 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Wireless Controller for PS4
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d01 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d02 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller v2 - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d06 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymetrical Controller Wireless Dongle -- show up as ps4 until you connect controller to it then it reboots into Xbox controller with different vvid/pid
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d08 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited Wireless Dongle
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d09 ), k_eControllerType_PS4Controller, NULL }, // NACON Daija Fight Stick - touchpad but no gyro/rumble
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Infinite - has gyro
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d13 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Pro Controller 3
{ MAKE_CONTROLLER_ID( 0x146b, 0x1103 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymetrical Controller -- on windows this doesn't enumerate
{ MAKE_CONTROLLER_ID( 0x1532, 0X0401 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera PS4 Controller
{ MAKE_CONTROLLER_ID( 0x1532, 0x1000 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju PS4 Controller
{ MAKE_CONTROLLER_ID( 0x1532, 0x1004 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate USB
{ MAKE_CONTROLLER_ID( 0x1532, 0x1007 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition USB
{ MAKE_CONTROLLER_ID( 0x1532, 0x1008 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera Evo Fightstick
{ MAKE_CONTROLLER_ID( 0x1532, 0x1009 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate BT
{ MAKE_CONTROLLER_ID( 0x1532, 0x100A ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition BT
{ MAKE_CONTROLLER_ID( 0x1532, 0x1100 ), k_eControllerType_PS4Controller, NULL }, // Razer RAION Fightpad - Trackpad, no gyro, lightbar hardcoded to green
{ MAKE_CONTROLLER_ID( 0x20d6, 0x792a ), k_eControllerType_PS4Controller, NULL }, // PowerA Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2000 ), k_eControllerType_PS4Controller, NULL }, // Qanba Drone
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2300 ), k_eControllerType_PS4Controller, NULL }, // Qanba Obsidian
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2303 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Obsidian Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2500 ), k_eControllerType_PS4Controller, NULL }, // Qanba Dragon
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2503 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Dragon Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x7545, 0x0104 ), k_eControllerType_PS4Controller, NULL }, // Armor 3 or Level Up Cobra - At least one variant has gyro
{ MAKE_CONTROLLER_ID (0x9886, 0x0024 ), k_eControllerType_XInputPS4Controller, NULL }, // Astro C40 in Xbox 360 mode
{ MAKE_CONTROLLER_ID( 0x9886, 0x0025 ), k_eControllerType_PS4Controller, NULL }, // Astro C40
// Removing the Giotek because there were a bunch of help tickets from users w/ issues including from non-PS4 controller users. This VID/PID is probably used in different FW's
// { MAKE_CONTROLLER_ID( 0x7545, 0x1122 ), k_eControllerType_PS4Controller, NULL }, // Giotek VX4 - trackpad/gyro don't work. Had to not filter on interface info. Light bar is flaky, but works.
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ce6 ), k_eControllerType_PS5Controller, NULL }, // Sony DualSense Controller
{ MAKE_CONTROLLER_ID( 0x054c, 0x0df2 ), k_eControllerType_PS5Controller, NULL }, // Sony DualSense Edge Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0163 ), k_eControllerType_PS5Controller, NULL }, // HORI Fighting Commander OCTA
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0184 ), k_eControllerType_PS5Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x1532, 0x100b ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wired)
{ MAKE_CONTROLLER_ID( 0x1532, 0x100c ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wireless)
{ MAKE_CONTROLLER_ID( 0x358a, 0x0104 ), k_eControllerType_PS5Controller, NULL }, // Backbone One PlayStation Edition for iOS
{ MAKE_CONTROLLER_ID( 0x0079, 0x0006 ), k_eControllerType_UnknownNonSteamController, NULL }, // DragonRise Generic USB PCB, sometimes configured as a PC Twin Shock Controller - looks like a DS3 but the face buttons are 1-4 instead of symbols
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d4 ), k_eControllerType_XBox360Controller, NULL }, // GPD Win 2 X-Box Controller
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff02 ), k_eControllerType_XBox360Controller, NULL }, // Wooting Two
{ MAKE_CONTROLLER_ID( 0x044f, 0xb326 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Gamepad GP XID
{ MAKE_CONTROLLER_ID( 0x045e, 0x028e ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft X-Box 360 pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x028f ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft X-Box 360 pad v2
{ MAKE_CONTROLLER_ID( 0x045e, 0x0291 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver (XBOX)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft X-Box 360 Big Button IR
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a1 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft X-Box 360 Wireless Controller with XUSB driver on Windows
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a9 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver (third party knockoff)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0719 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Xbox 360 Wireless Receiver
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21d ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F310
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21e ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F510
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21f ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F710
{ MAKE_CONTROLLER_ID( 0x046d, 0xc242 ), k_eControllerType_XBox360Controller, NULL }, // Logitech Chillstream Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x2004 ), k_eControllerType_XBox360Controller, NULL }, // Elecom JC-U3613M
// This isn't actually an Xbox 360 controller, it just looks like one
// { MAKE_CONTROLLER_ID( 0x06a3, 0xf51a ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3600
{ MAKE_CONTROLLER_ID( 0x0738, 0x4716 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x0738, 0x4718 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightStick SE
{ MAKE_CONTROLLER_ID( 0x0738, 0x4726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x0738, 0x4728 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightPad
{ MAKE_CONTROLLER_ID( 0x0738, 0x4736 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon Gamepad
{ MAKE_CONTROLLER_ID( 0x0738, 0x4738 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller (SFIV)
{ MAKE_CONTROLLER_ID( 0x0738, 0x4740 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Beat Pad
{ MAKE_CONTROLLER_ID( 0x0738, 0xb726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox controller - MW2
{ MAKE_CONTROLLER_ID( 0x0738, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz JOYTECH NEO SE Advanced GamePad
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb02 ), k_eControllerType_XBox360Controller, NULL }, // Saitek Cyborg Rumble Pad - PC/Xbox 360
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb03 ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3200 Rumble Pad - PC/Xbox 360
{ MAKE_CONTROLLER_ID( 0x0738, 0xf738 ), k_eControllerType_XBox360Controller, NULL }, // Super SFIV FightStick TE S
{ MAKE_CONTROLLER_ID( 0x0955, 0x7210 ), k_eControllerType_XBox360Controller, NULL }, // Nvidia Shield local controller
{ MAKE_CONTROLLER_ID( 0x0955, 0xb400 ), k_eControllerType_XBox360Controller, NULL }, // NVIDIA Shield streaming controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0105 ), k_eControllerType_XBox360Controller, NULL }, // HSM3 Xbox360 dancepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0113 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0125 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightStick" }, // PDP INJUSTICE FightStick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0127 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightPad" }, // PDP INJUSTICE FightPad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0131 ), k_eControllerType_XBox360Controller, "PDP EA Soccer Controller" }, // PDP EA Soccer Gamepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0133 ), k_eControllerType_XBox360Controller, "PDP Battlefield 4 Controller" }, // PDP Battlefield 4 Gamepad
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0143 ), k_eControllerType_XBox360Controller, "PDP MK X Fight Stick" }, // PDP MK X Fight Stick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0147 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Marvel Controller" }, // PDP Marvel Controller for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0201 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0213 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x021f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0301 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0313 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0314 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0401 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0413 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0501 ), k_eControllerType_XBox360Controller, NULL }, // PDP Xbox 360 Controller (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000a ), k_eControllerType_XBox360Controller, NULL }, // Hori Co. DOA4 FightStick
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000c ), k_eControllerType_XBox360Controller, NULL }, // Hori PadEX Turbo
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000d ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0016 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x001b ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008c ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro 4
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00db ), k_eControllerType_XBox360Controller, "HORI Slime Controller" }, // Hori Dragon Quest Slime Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011e ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick α
{ MAKE_CONTROLLER_ID( 0x1038, 0x1430 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
{ MAKE_CONTROLLER_ID( 0x1038, 0x1431 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
{ MAKE_CONTROLLER_ID( 0x1038, 0xb360 ), k_eControllerType_XBox360Controller, NULL }, // SteelSeries Nimbus/Stratus XL
{ MAKE_CONTROLLER_ID( 0x11c9, 0x55f0 ), k_eControllerType_XBox360Controller, NULL }, // Nacon GC-100XF
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0004 ), k_eControllerType_XBox360Controller, NULL }, // Honey Bee Xbox360 dancepad
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // PDP AFTERGLOW AX.1
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0303 ), k_eControllerType_XBox360Controller, NULL }, // Mortal Kombat Klassic FightStick
{ MAKE_CONTROLLER_ID( 0x1430, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller Adapter
{ MAKE_CONTROLLER_ID( 0x1430, 0x4748 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Guitar Hero X-plorer
{ MAKE_CONTROLLER_ID( 0x1430, 0xf801 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0601 ), k_eControllerType_XBox360Controller, NULL }, // BigBen Interactive XBOX 360 Controller
// { MAKE_CONTROLLER_ID( 0x1532, 0x0037 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f00 ), k_eControllerType_XBox360Controller, NULL }, // Power A Mini Pro Elite
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f0a ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f10 ), k_eControllerType_XBox360Controller, NULL }, // Batarang Xbox 360 controller
{ MAKE_CONTROLLER_ID( 0x162e, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Joytech Neo-Se Take2
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Tournament Edition
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Classic Edition
{ MAKE_CONTROLLER_ID( 0x1689, 0xfe00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x1949, 0x041a ), k_eControllerType_XBox360Controller, "Amazon Luna Controller" }, // Amazon Luna Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Guitar
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0003 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Drumkit
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf016 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf018 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV SE Fighting Stick
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf019 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Brawlstick for Xbox 360
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf021 ), k_eControllerType_XBox360Controller, NULL }, // Mad Cats Ghost Recon FS GamePad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf023 ), k_eControllerType_XBox360Controller, NULL }, // MLG Pro Circuit Controller (Xbox)
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf025 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Call Of Duty
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf027 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FPS Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf028 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightPad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf02e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Fightpad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf036 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon GamePad Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf038 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightStick TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf039 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MvC2 TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03a ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz SFxT Fightstick Pro
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03d ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV Arcade Stick TE - Chun Li
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MLG FightStick TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03f ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick SoulCaliber
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf042 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TES+
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf080 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TE2
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf501 ), k_eControllerType_XBox360Controller, NULL }, // HoriPad EX2 Turbo
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.VX SA
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf504 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro. EX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf505 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2B
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf506 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX Premium VLX
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf901 ), k_eControllerType_XBox360Controller, NULL }, // Gamestop Xbox 360 Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf902 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Gamepad2
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf903 ), k_eControllerType_XBox360Controller, NULL }, // Tron Xbox 360 controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf904 ), k_eControllerType_XBox360Controller, NULL }, // PDP Versus Fighting Pad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf906 ), k_eControllerType_XBox360Controller, NULL }, // MortalKombat FightStick
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfa01 ), k_eControllerType_XBox360Controller, NULL }, // MadCatz GamePad
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza TE
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5000 ), k_eControllerType_XBox360Controller, NULL }, // Razer Atrox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5300 ), k_eControllerType_XBox360Controller, NULL }, // PowerA MINI PROEX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5303 ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x530a ), k_eControllerType_XBox360Controller, NULL }, // Xbox 360 Pro EX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x531a ), k_eControllerType_XBox360Controller, NULL }, // PowerA Pro Ex
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5397 ), k_eControllerType_XBox360Controller, NULL }, // FUS1ON Tournament Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5500 ), k_eControllerType_XBox360Controller, NULL }, // Hori XBOX 360 EX 2 with Turbo
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5501 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX-SA
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX Alt
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Edge
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5506 ), k_eControllerType_XBox360Controller, NULL }, // Hori SOULCALIBUR V Stick
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550d ), k_eControllerType_XBox360Controller, NULL }, // Hori GEM Xbox controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550e ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro V Kai 360
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5508 ), k_eControllerType_XBox360Controller, NULL }, // Hori PAD A
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5510 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Commander ONE
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b00 ), k_eControllerType_XBox360Controller, NULL }, // ThrustMaster Ferrari Italia 458 Racing Wheel
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b02 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster, Inc. GPX Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b03 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Ferrari 458 Racing Wheel
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5d04 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafa ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafb ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafc ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 1
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 3
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL }, // Rock Candy Gamepad for Xbox 360
{ MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL }, // ThrustMaster eSwap PRO Controller Xbox
{ MAKE_CONTROLLER_ID( 0x045e, 0x02d1 ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft X-Box One pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02dd ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft X-Box One pad (Firmware 2015)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e0 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e3 ), k_eControllerType_XBoxOneController, "Xbox One Elite Controller" }, // Microsoft X-Box One Elite pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ea ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x02fd ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ff ), k_eControllerType_XBoxOneController, NULL }, // Microsoft X-Box One controller with XBOXGIP driver on Windows
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b00 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad
// { MAKE_CONTROLLER_ID( 0x045e, 0x0b02 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // The virtual keyboard generated by XboxGip drivers for Xbox One Controllers (see https://github.com/libsdl-org/SDL/pull/5121 for details)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b05 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0a ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0c ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad (Bluetooth)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b12 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft X-Box Series X pad
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b13 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft X-Box Series X pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b20 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft X-Box One S pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b21 ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft X-Box Adaptive pad (BLE)
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b22 ), k_eControllerType_XBoxOneController, "Xbox One Elite 2 Controller" }, // Microsoft X-Box One Elite Series 2 pad (BLE)
{ MAKE_CONTROLLER_ID( 0x0738, 0x4a01 ), k_eControllerType_XBoxOneController, NULL }, // Mad Catz FightStick TE 2
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0139 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013B ), k_eControllerType_XBoxOneController, "PDP Xbox One Face-Off Controller" }, // PDP Face-Off Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013a ), k_eControllerType_XBoxOneController, NULL }, // PDP Xbox One Controller (unlisted)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0145 ), k_eControllerType_XBoxOneController, "PDP MK X Fight Pad" }, // PDP MK X Fight Pad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0146 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015b ), k_eControllerType_XBoxOneController, "PDP Fallout 4 Vault Boy Controller" }, // PDP Fallout 4 Vault Boy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015c ), k_eControllerType_XBoxOneController, "PDP Xbox One @Play Controller" }, // PDP @Play Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015d ), k_eControllerType_XBoxOneController, "PDP Mirror's Edge Controller" }, // PDP Mirror's Edge Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015f ), k_eControllerType_XBoxOneController, "PDP Metallic Controller" }, // PDP Metallic Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0160 ), k_eControllerType_XBoxOneController, "PDP NFL Face-Off Controller" }, // PDP NFL Official Face-Off Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0161 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0162 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0163 ), k_eControllerType_XBoxOneController, "PDP Deliverer of Truth" }, // PDP Legendary Collection: Deliverer of Truth
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0164 ), k_eControllerType_XBoxOneController, "PDP Battlefield 1 Controller" }, // PDP Battlefield 1 Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0165 ), k_eControllerType_XBoxOneController, "PDP Titanfall 2 Controller" }, // PDP Titanfall 2 Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0166 ), k_eControllerType_XBoxOneController, "PDP Mass Effect: Andromeda Controller" }, // PDP Mass Effect: Andromeda Official Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0167 ), k_eControllerType_XBoxOneController, "PDP Halo Wars 2 Face-Off Controller" }, // PDP Halo Wars 2 Official Face-Off Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0205 ), k_eControllerType_XBoxOneController, "PDP Victrix Pro Fight Stick" }, // PDP Victrix Pro Fight Stick
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0206 ), k_eControllerType_XBoxOneController, "PDP Mortal Kombat Controller" }, // PDP Mortal Kombat 25 Anniversary Edition Stick (Xbox One)
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0246 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0261 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0262 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a8 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02aa ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ab ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ac ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Wired Controller for Xbox One - Ember Orange
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ad ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ae ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02af ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Prismatic Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b5 ), k_eControllerType_XBoxOneController, "PDP Xbox One GAMEware Controller" }, // PDP GAMEware Wired Controller Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b6 ), k_eControllerType_XBoxOneController, NULL }, // PDP One-Handed Joystick Adaptive Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bd ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Wired Controller for Xbox One - Royal Purple
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02be ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Deluxe Wired Controller for Xbox One - Raven Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bf ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Deluxe Wired Controller for Xbox One - Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantom Black
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Ghost White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Revenant Blue
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Deluxe Wired Controller for Xbox One - Verdant Green
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Deluxe Wired Controller for Xbox One - Ember Orange
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Deluxe Wired Controller for Xbox One - Royal Purple
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Deluxe Wired Controller for Xbox One - Crimson Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Deluxe Wired Controller for Xbox One - Arctic White
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c8 ), k_eControllerType_XBoxOneController, "PDP Kingdom Hearts Controller" }, // PDP Kingdom Hearts Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantasm Red" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantasm Red
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ca ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Specter Violet
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cb ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Wired Controller for Xbox One - Stealth Series | Specter Violet
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cd ), k_eControllerType_XBoxOneController, "PDP Xbox One Blu-merang" }, // PDP Rock Candy Wired Controller for Xbox One - Blu-merang
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ce ), k_eControllerType_XBoxOneController, "PDP Xbox One Cranblast" }, // PDP Rock Candy Wired Controller for Xbox One - Cranblast
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cf ), k_eControllerType_XBoxOneController, "PDP Xbox One Aqualime" }, // PDP Rock Candy Wired Controller for Xbox One - Aqualime
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Red Camo" }, // PDP Wired Controller for Xbox One - Red Camo
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0346 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0446 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02da ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Afterglow" }, // PDP Xbox Series X Afterglow
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d6 ), k_eControllerType_XBoxOneController, "Victrix Gambit Tournament Controller" }, // Victrix Gambit Tournament Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d9 ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Midnight Blue" }, // PDP Xbox Series X Midnight Blue
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0063 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro Hayabusa (USA) Xbox One
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0067 ), k_eControllerType_XBoxOneController, NULL }, // HORIPAD ONE
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0078 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro V Kai Xbox One
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c5 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0150 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander OCTA for Xbox Series X
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7009 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach Recon Controller
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7013 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach REACT-R
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a00 ), k_eControllerType_XBoxOneController, NULL }, // Razer Atrox Arcade Stick
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a03 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wildcat
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a14 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Ultimate
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a15 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Tournament Edition
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2001 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Black Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2002 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Gray/White Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2003 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Green Inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2004 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Pink inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2005 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - Black
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2006 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - White
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2009 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Red inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Blue inline
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200b ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Red
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200c ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Blue
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200d ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Seafoam Fade
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200e ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Midnight Blue
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200f ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Soldier Green
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2011 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired - Metallic Ice
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2012 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Cuphead EnWired Controller - Mugman
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2015 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Blue Hint
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2016 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Green Hint
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2017 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Cntroller - Arctic Camo
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2018 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Arc Lightning
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2019 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Royal Purple
{ MAKE_CONTROLLER_ID( 0x20d6, 0x201a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Nebula
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4001 ), k_eControllerType_XBoxOneController, "PowerA Fusion Pro 2 Controller" }, // PowerA Fusion Pro 2 Wired Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4002 ), k_eControllerType_XBoxOneController, "PowerA Spectra Infinity Controller" }, // PowerA Spectra Infinity Wired Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x20d6, 0x890b ), k_eControllerType_XBoxOneController, NULL }, // PowerA MOGA XP-Ultra Controller (Xbox Series X style)
{ MAKE_CONTROLLER_ID( 0x24c6, 0x541a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Xbox One Mini Wired Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x542a ), k_eControllerType_XBoxOneController, NULL }, // Xbox ONE spectra
{ MAKE_CONTROLLER_ID( 0x24c6, 0x543a ), k_eControllerType_XBoxOneController, "PowerA Xbox One Controller" }, // PowerA Xbox ONE liquid metal controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x551a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x561a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x581a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Classic Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x591a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x592a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Spectra Pro
{ MAKE_CONTROLLER_ID( 0x24c6, 0x791a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x2002 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller for Xbox
{ MAKE_CONTROLLER_ID( 0x2e24, 0x0652 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1618 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1688 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin X91
{ MAKE_CONTROLLER_ID( 0x146b, 0x0611 ), k_eControllerType_XBoxOneController, NULL }, // Xbox Controller Mode for NACON Revolution 3
// These have been added via Minidump for unrecognized Xinput controller assert
{ MAKE_CONTROLLER_ID( 0x0000, 0x0000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller - Microsoft VID
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1414 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0159 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfaff ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006d ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a4 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1832 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x187f ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1883 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff01 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef8 ), k_eControllerType_XBox360Controller, NULL }, // Homemade fightstick based on brook pcb (with XInput driver??)
{ MAKE_CONTROLLER_ID( 0x046d, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1345, 0x6006 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x056e, 0x2012 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x146b, 0x0602 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ae ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x046d, 0x0401 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0xcaa3 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0xc261 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x046d, 0x0291 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d3 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00b1 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0001, 0x0001 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x188e ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x187c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x189c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x0079, 0x1874 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x0050 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x2e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x91 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x719 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xed ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xc0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x152 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1007 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
/* Added from Minidumps 10-9-19 */
{ MAKE_CONTROLLER_ID( 0x0, 0x6686 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x11ff, 0x511 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x12ab, 0x304 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x291 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x2a9 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1430, 0x70b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x28e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x1bad, 0x5500 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x20ab, 0x55ef ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5509 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2516, 0x69 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x25b1, 0x360 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2203 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x11 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x53 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0xb7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1004 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0x1008 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x46d, 0xf301 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0x7263 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xb738 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xcb29 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x738, 0xf401 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18c2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18c8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x79, 0x18cf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe17 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe1c ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe22 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xc12, 0xe30 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd2d2, 0xd2d2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe00, 0xe00 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x12a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2a5 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bd ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2bf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2c6 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0x97 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xba ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xf0d, 0xd8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xfff, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x45e, 0x867 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
// Added 12-17-2020
{ MAKE_CONTROLLER_ID( 0x16d0, 0xf3f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x2f24, 0x8f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0xe6f, 0xf501 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
//{ MAKE_CONTROLLER_ID( 0x1949, 0x0402 ), /*android*/, NULL }, // Unknown Controller
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0001 ), k_eControllerType_AppleController, NULL }, // MFI Extended Gamepad (generic entry for iOS/tvOS)
{ MAKE_CONTROLLER_ID( 0x05ac, 0x0002 ), k_eControllerType_AppleController, NULL }, // MFI Standard Gamepad (generic entry for iOS/tvOS)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
// This same controller ID is spoofed by many 3rd-party Switch controllers.
// The ones we currently know of are:
// * Any 8bitdo controller with Switch support
// * ORTZ Gaming Wireless Pro Controller
// * ZhiXu Gamepad Wireless
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c1 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORIPAD for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0092 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Pokken Tournament DX Pro Pad
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00f6 ), k_eControllerType_SwitchProController, NULL }, // HORI Wireless Switch Pad
// The HORIPAD S, which comes in multiple styles:
// - NSW-108, classic GameCube controller
// - NSW-244, Fighting Commander arcade pad
// - NSW-278, Hori Pad Mini gamepad
// - NSW-326, HORIPAD FPS for Nintendo Switch
//
// The first two, at least, shouldn't have their buttons remapped, and since we
// can't tell which model we're actually using, we won't do any button remapping
// for any of them.
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00dc ), k_eControllerType_XInputSwitchController, NULL }, // HORIPAD S - Looks like a Switch controller but uses the Xbox 360 controller protocol
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0180 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Pro Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0181 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Deluxe Wired Pro Controller for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0184 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Deluxe+ Audio Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0185 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Wired Fight Pad Pro for Nintendo Switch
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL }, // PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0187 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Rockcandy Wired Controller
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wired Deluxe+ Audio Controller
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Real Arcade Pro V Hayabusa in Switch Mode
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Wired Controller Plus/PowerA Wired Controller Nintendo GameCube Style
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa712 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Fight Pad
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa713 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Super Mario Controller
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa714 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Spectra Controller
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device
// Valve products
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls
{ MAKE_CONTROLLER_ID( 0x28de, 0x1101 ), k_eControllerType_SteamController, NULL }, // Valve Legacy Steam Controller (CHELL)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1102 ), k_eControllerType_SteamController, NULL }, // Valve wired Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1105 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1106 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1142 ), k_eControllerType_SteamController, NULL }, // Valve wireless Steam Controller
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
};
@@ -0,0 +1,77 @@
/*
Copyright (C) Valve Corporation
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef CONTROLLER_TYPE_H
#define CONTROLLER_TYPE_H
#ifdef _WIN32
#pragma once
#endif
//-----------------------------------------------------------------------------
// Purpose: Steam Controller models
// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN A DATABASE
//-----------------------------------------------------------------------------
typedef enum
{
k_eControllerType_None = -1,
k_eControllerType_Unknown = 0,
// Steam Controllers
k_eControllerType_UnknownSteamController = 1,
k_eControllerType_SteamController = 2,
k_eControllerType_SteamControllerV2 = 3,
// Other Controllers
k_eControllerType_UnknownNonSteamController = 30,
k_eControllerType_XBox360Controller = 31,
k_eControllerType_XBoxOneController = 32,
k_eControllerType_PS3Controller = 33,
k_eControllerType_PS4Controller = 34,
k_eControllerType_WiiController = 35,
k_eControllerType_AppleController = 36,
k_eControllerType_AndroidController = 37,
k_eControllerType_SwitchProController = 38,
k_eControllerType_SwitchJoyConLeft = 39,
k_eControllerType_SwitchJoyConRight = 40,
k_eControllerType_SwitchJoyConPair = 41,
k_eControllerType_SwitchInputOnlyController = 42,
k_eControllerType_MobileTouch = 43,
k_eControllerType_XInputSwitchController = 44, // Client-side only, used to mark Nintendo Switch style controllers as using XInput instead of the Nintendo Switch protocol
k_eControllerType_PS5Controller = 45,
k_eControllerType_XInputPS4Controller = 46, // Client-side only, used to mark DualShock 4 style controllers using XInput instead of the DualShock 4 controller protocol
k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value
// Keyboards and Mice
k_eControllertype_GenericKeyboard = 400,
k_eControllertype_GenericMouse = 800,
} EControllerType;
typedef struct
{
unsigned int m_unDeviceID;
EControllerType m_eControllerType;
const char *m_pszName;
} ControllerDescription_t;
extern EControllerType GuessControllerType( int nVID, int nPID );
extern const char *GuessControllerName( int nVID, int nPID );
#endif // CONTROLLER_TYPE_H
+107
View File
@@ -0,0 +1,107 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// This file includes a few functions standalone from SDL_joystick.c useful for joystick typing
#include "minisdl.h"
#include "usb_ids.h"
SDL_bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH ||
product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
SDL_bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_MICROSOFT) {
if (product_id == USB_PRODUCT_XBOX_SERIES_X ||
product_id == USB_PRODUCT_XBOX_SERIES_X_BLE) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_PDP) {
if (product_id == USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT ||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE ||
product_id == USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_POWERA_ALT) {
if ((product_id >= 0x2001 && product_id <= 0x201a) ||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 ||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA ||
product_id == USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_HORI) {
if (product_id == USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X ||
product_id == USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_RAZER) {
if (product_id == USB_PRODUCT_RAZER_WOLVERINE_V2 ||
product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_CHROMA) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_THRUSTMASTER) {
if (product_id == USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_TURTLE_BEACH) {
if (product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R ||
product_id == USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_8BITDO) {
if (product_id == USB_PRODUCT_8BITDO_XBOX_CONTROLLER) {
return SDL_TRUE;
}
}
if (vendor_id == USB_VENDOR_GAMESIR) {
if (product_id == USB_PRODUCT_GAMESIR_G7) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
SDL_bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
{
if (vendor_id == USB_VENDOR_SONY) {
if (product_id == USB_PRODUCT_SONY_DS5_EDGE) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
typedef int SDL_bool;
#define SDL_TRUE 1
#define SDL_FALSE 0
typedef unsigned short Uint16;
SDL_bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id);
SDL_bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id);
SDL_bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id);
+108 -14
View File
@@ -6,6 +6,10 @@
#include <arpa/inet.h>
#include <string.h>
#include "minisdl.h"
#include "controller_type.h"
#include "controller_list.h"
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMouseMove(JNIEnv *env, jclass clazz, jshort deltaX, jshort deltaY) {
LiSendMouseMoveEvent(deltaX, deltaY);
@@ -30,7 +34,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_sendMouseButton(JNIEnv *env, jclass c
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMultiControllerInput(JNIEnv *env, jclass clazz, jshort controllerNumber,
jshort activeGamepadMask, jshort buttonFlags,
jshort activeGamepadMask, jint buttonFlags,
jbyte leftTrigger, jbyte rightTrigger,
jshort leftStickX, jshort leftStickY,
jshort rightStickX, jshort rightStickY) {
@@ -38,22 +42,64 @@ Java_com_limelight_nvstream_jni_MoonBridge_sendMultiControllerInput(JNIEnv *env,
leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendControllerInput(JNIEnv *env, jclass clazz, jshort buttonFlags,
jbyte leftTrigger, jbyte rightTrigger,
jshort leftStickX, jshort leftStickY,
jshort rightStickX, jshort rightStickY) {
LiSendControllerEvent(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendTouchEvent(JNIEnv *env, jclass clazz,
jbyte eventType, jint pointerId,
jfloat x, jfloat y, jfloat pressureOrDistance,
jfloat contactAreaMajor, jfloat contactAreaMinor,
jshort rotation) {
return LiSendTouchEvent(eventType, pointerId, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendPenEvent(JNIEnv *env, jclass clazz, jbyte eventType,
jbyte toolType, jbyte penButtons,
jfloat x, jfloat y, jfloat pressureOrDistance,
jfloat contactAreaMajor, jfloat contactAreaMinor,
jshort rotation, jbyte tilt) {
return LiSendPenEvent(eventType, toolType, penButtons, x, y, pressureOrDistance,
contactAreaMajor, contactAreaMinor, rotation, tilt);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendControllerArrivalEvent(JNIEnv *env, jclass clazz,
jbyte controllerNumber,
jshort activeGamepadMask,
jbyte type,
jint supportedButtonFlags,
jshort capabilities) {
return LiSendControllerArrivalEvent(controllerNumber, activeGamepadMask, type, supportedButtonFlags, capabilities);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendControllerTouchEvent(JNIEnv *env, jclass clazz,
jbyte controllerNumber,
jbyte eventType,
jint pointerId, jfloat x,
jfloat y, jfloat pressure) {
return LiSendControllerTouchEvent(controllerNumber, eventType, pointerId, x, y, pressure);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendControllerMotionEvent(JNIEnv *env, jclass clazz,
jbyte controllerNumber,
jbyte motionType, jfloat x,
jfloat y, jfloat z) {
return LiSendControllerMotionEvent(controllerNumber, motionType, x, y, z);
}
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendControllerBatteryEvent(JNIEnv *env, jclass clazz,
jbyte controllerNumber,
jbyte batteryState,
jbyte batteryPercentage) {
return LiSendControllerBatteryEvent(controllerNumber, batteryState, batteryPercentage);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendKeyboardInput(JNIEnv *env, jclass clazz, jshort keyCode, jbyte keyAction, jbyte modifiers) {
LiSendKeyboardEvent(keyCode, keyAction, modifiers);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMouseScroll(JNIEnv *env, jclass clazz, jbyte scrollClicks) {
LiSendScrollEvent(scrollClicks);
Java_com_limelight_nvstream_jni_MoonBridge_sendKeyboardInput(JNIEnv *env, jclass clazz, jshort keyCode, jbyte keyAction, jbyte modifiers, jbyte flags) {
LiSendKeyboardEvent2(keyCode, keyAction, modifiers, flags);
}
JNIEXPORT void JNICALL
@@ -61,6 +107,11 @@ Java_com_limelight_nvstream_jni_MoonBridge_sendMouseHighResScroll(JNIEnv *env, j
LiSendHighResScrollEvent(scrollAmount);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMouseHighResHScroll(JNIEnv *env, jclass clazz, jshort scrollAmount) {
LiSendHighResHScrollEvent(scrollAmount);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendUtf8Text(JNIEnv *env, jclass clazz, jstring text) {
const char* utf8Text = (*env)->GetStringUTFChars(env, text, NULL);
@@ -159,4 +210,47 @@ Java_com_limelight_nvstream_jni_MoonBridge_getEstimatedRttInfo(JNIEnv *env, jcla
}
return ((uint64_t)rtt << 32U) | variance;
}
JNIEXPORT jbyte JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_guessControllerType(JNIEnv *env, jclass clazz, jint vendorId, jint productId) {
unsigned int unDeviceID = MAKE_CONTROLLER_ID(vendorId, productId);
for (int i = 0; i < sizeof(arrControllers) / sizeof(arrControllers[0]); i++) {
if (unDeviceID == arrControllers[i].m_unDeviceID) {
switch (arrControllers[i].m_eControllerType) {
case k_eControllerType_XBox360Controller:
case k_eControllerType_XBoxOneController:
return LI_CTYPE_XBOX;
case k_eControllerType_PS3Controller:
case k_eControllerType_PS4Controller:
case k_eControllerType_PS5Controller:
return LI_CTYPE_PS;
case k_eControllerType_WiiController:
case k_eControllerType_SwitchProController:
case k_eControllerType_SwitchJoyConLeft:
case k_eControllerType_SwitchJoyConRight:
case k_eControllerType_SwitchJoyConPair:
case k_eControllerType_SwitchInputOnlyController:
return LI_CTYPE_NINTENDO;
default:
return LI_CTYPE_UNKNOWN;
}
}
}
return LI_CTYPE_UNKNOWN;
}
JNIEXPORT jboolean JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_guessControllerHasPaddles(JNIEnv *env, jclass clazz, jint vendorId, jint productId) {
// Xbox Elite and DualSense Edge controllers have paddles
return SDL_IsJoystickXboxOneElite(vendorId, productId) || SDL_IsJoystickDualSenseEdge(vendorId, productId);
}
JNIEXPORT jboolean JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_guessControllerHasShareButton(JNIEnv *env, jclass clazz, jint vendorId, jint productId) {
// Xbox Elite and DualSense Edge controllers have paddles
return SDL_IsJoystickXboxSeriesX(vendorId, productId);
}
+167
View File
@@ -0,0 +1,167 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef usb_ids_h_
#define usb_ids_h_
/* Definitions of useful USB VID/PID values */
#define USB_VENDOR_8BITDO 0x2dc8
#define USB_VENDOR_AMAZON 0x1949
#define USB_VENDOR_APPLE 0x05ac
#define USB_VENDOR_ASTRO 0x9886
#define USB_VENDOR_BACKBONE 0x358a
#define USB_VENDOR_GAMESIR 0x3537
#define USB_VENDOR_DRAGONRISE 0x0079
#define USB_VENDOR_GOOGLE 0x18d1
#define USB_VENDOR_HORI 0x0f0d
#define USB_VENDOR_HYPERKIN 0x2e24
#define USB_VENDOR_LOGITECH 0x046d
#define USB_VENDOR_MADCATZ 0x0738
#define USB_VENDOR_MICROSOFT 0x045e
#define USB_VENDOR_NACON 0x146b
#define USB_VENDOR_NINTENDO 0x057e
#define USB_VENDOR_NVIDIA 0x0955
#define USB_VENDOR_PDP 0x0e6f
#define USB_VENDOR_POWERA 0x24c6
#define USB_VENDOR_POWERA_ALT 0x20d6
#define USB_VENDOR_QANBA 0x2c22
#define USB_VENDOR_RAZER 0x1532
#define USB_VENDOR_SAITEK 0x06a3
#define USB_VENDOR_SHANWAN 0x2563
#define USB_VENDOR_SHANWAN_ALT 0x20bc
#define USB_VENDOR_SONY 0x054c
#define USB_VENDOR_THRUSTMASTER 0x044f
#define USB_VENDOR_TURTLE_BEACH 0x10f5
#define USB_VENDOR_VALVE 0x28de
#define USB_VENDOR_ZEROPLUS 0x0c12
#define USB_PRODUCT_8BITDO_XBOX_CONTROLLER 0x2002
#define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419
#define USB_PRODUCT_ASTRO_C40_XBOX360 0x0024
#define USB_PRODUCT_BACKBONE_ONE_IOS 0x0103
#define USB_PRODUCT_BACKBONE_ONE_IOS_PS5 0x0104
#define USB_PRODUCT_GAMESIR_G7 0x1001
#define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400
#define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER 0x1846
#define USB_PRODUCT_HORI_FIGHTING_COMMANDER_OCTA_SERIES_X 0x0150
#define USB_PRODUCT_HORI_HORIPAD_PRO_SERIES_X 0x014f
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4 0x011c
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
#define USB_PRODUCT_LOGITECH_F310 0xc216
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e
#define USB_PRODUCT_NINTENDO_SNES_CONTROLLER 0x2017
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_GRIP 0x200e
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_LEFT 0x2006
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_PAIR 0x2008 /* Used by joycond */
#define USB_PRODUCT_NINTENDO_SWITCH_JOYCON_RIGHT 0x2007
#define USB_PRODUCT_NINTENDO_SWITCH_PRO 0x2009
#define USB_PRODUCT_NINTENDO_WII_REMOTE 0x0306
#define USB_PRODUCT_NINTENDO_WII_REMOTE2 0x0330
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V103 0x7210
#define USB_PRODUCT_NVIDIA_SHIELD_CONTROLLER_V104 0x7214
#define USB_PRODUCT_RAZER_ATROX 0x0a00
#define USB_PRODUCT_RAZER_PANTHERA 0x0401
#define USB_PRODUCT_RAZER_PANTHERA_EVO 0x1008
#define USB_PRODUCT_RAZER_RAIJU 0x1000
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_USB 0x1007
#define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH 0x100a
#define USB_PRODUCT_RAZER_ULTIMATE_EDITION_USB 0x1004
#define USB_PRODUCT_RAZER_ULTIMATE_EDITION_BLUETOOTH 0x1009
#define USB_PRODUCT_RAZER_WOLVERINE_V2 0x0a29
#define USB_PRODUCT_RAZER_WOLVERINE_V2_CHROMA 0x0a2e
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED 0x100b
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS 0x100c
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRED 0x1010
#define USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_XBOX_WIRELESS 0x1011
#define USB_PRODUCT_SAITEK_CYBORG_V3 0xf622
#define USB_PRODUCT_SHANWAN_DS3 0x0523
#define USB_PRODUCT_SONY_DS3 0x0268
#define USB_PRODUCT_SONY_DS4 0x05c4
#define USB_PRODUCT_SONY_DS4_DONGLE 0x0ba0
#define USB_PRODUCT_SONY_DS4_SLIM 0x09cc
#define USB_PRODUCT_SONY_DS4_STRIKEPAD 0x05c5
#define USB_PRODUCT_SONY_DS5 0x0ce6
#define USB_PRODUCT_SONY_DS5_EDGE 0x0df2
#define USB_PRODUCT_THRUSTMASTER_ESWAPX_PRO 0xd012
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_REACT_R 0x7013
#define USB_PRODUCT_TURTLE_BEACH_SERIES_X_RECON 0x7009
#define USB_PRODUCT_VICTRIX_FS_PRO 0x0203
#define USB_PRODUCT_VICTRIX_FS_PRO_V2 0x0207
#define USB_PRODUCT_XBOX360_XUSB_CONTROLLER 0x02a1 /* XUSB driver software PID */
#define USB_PRODUCT_XBOX360_WIRED_CONTROLLER 0x028e
#define USB_PRODUCT_XBOX360_WIRELESS_RECEIVER 0x0719
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE 0x0b0a
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLUETOOTH 0x0b0c
#define USB_PRODUCT_XBOX_ONE_ADAPTIVE_BLE 0x0b21
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 0x02e3
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 0x0b00
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH 0x0b05
#define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLE 0x0b22
#define USB_PRODUCT_XBOX_ONE_S 0x02ea
#define USB_PRODUCT_XBOX_ONE_S_REV1_BLUETOOTH 0x02e0
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLUETOOTH 0x02fd
#define USB_PRODUCT_XBOX_ONE_S_REV2_BLE 0x0b20
#define USB_PRODUCT_XBOX_SERIES_X 0x0b12
#define USB_PRODUCT_XBOX_SERIES_X_BLE 0x0b13
#define USB_PRODUCT_XBOX_SERIES_X_VICTRIX_GAMBIT 0x02d6
#define USB_PRODUCT_XBOX_SERIES_X_PDP_BLUE 0x02d9
#define USB_PRODUCT_XBOX_SERIES_X_PDP_AFTERGLOW 0x02da
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_FUSION_PRO2 0x4001
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_MOGA_XP_ULTRA 0x890b
#define USB_PRODUCT_XBOX_SERIES_X_POWERA_SPECTRA 0x4002
#define USB_PRODUCT_XBOX_ONE_XBOXGIP_CONTROLLER 0x02ff /* XBOXGIP driver software PID */
#define USB_PRODUCT_XBOX_ONE_XINPUT_CONTROLLER 0x02fe /* Made up product ID for XInput */
#define USB_PRODUCT_STEAM_VIRTUAL_GAMEPAD 0x11ff
/* USB usage pages */
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
#define USB_USAGEPAGE_BUTTON 0x0009
/* USB usages for USAGE_PAGE_GENERIC_DESKTOP */
#define USB_USAGE_GENERIC_POINTER 0x0001
#define USB_USAGE_GENERIC_MOUSE 0x0002
#define USB_USAGE_GENERIC_JOYSTICK 0x0004
#define USB_USAGE_GENERIC_GAMEPAD 0x0005
#define USB_USAGE_GENERIC_KEYBOARD 0x0006
#define USB_USAGE_GENERIC_KEYPAD 0x0007
#define USB_USAGE_GENERIC_MULTIAXISCONTROLLER 0x0008
#define USB_USAGE_GENERIC_X 0x0030
#define USB_USAGE_GENERIC_Y 0x0031
#define USB_USAGE_GENERIC_Z 0x0032
#define USB_USAGE_GENERIC_RX 0x0033
#define USB_USAGE_GENERIC_RY 0x0034
#define USB_USAGE_GENERIC_RZ 0x0035
#define USB_USAGE_GENERIC_SLIDER 0x0036
#define USB_USAGE_GENERIC_DIAL 0x0037
#define USB_USAGE_GENERIC_WHEEL 0x0038
#define USB_USAGE_GENERIC_HAT 0x0039
/* Bluetooth SIG assigned Company Identifiers
https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers/ */
#define BLUETOOTH_VENDOR_AMAZON 0x0171
#define BLUETOOTH_PRODUCT_LUNA_CONTROLLER 0x0419
#endif /* usb_ids_h_ */
+7 -1
View File
@@ -14,7 +14,13 @@
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
android:layout_gravity="center"
android:focusable="true"
android:focusableInTouchMode="true"
android:focusedByDefault="true"
android:defaultFocusHighlightEnabled="false">
<requestFocus />
</com.limelight.ui.StreamView>
<TextView
android:id="@+id/performanceOverlay"
+143
View File
@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pair_incorrect_pin">Неправилен ПИН</string>
<string name="no_video_received_error">Няма получено видео от хоста.</string>
<string name="pacing_latency">Предпочитане на най-ниската латентност</string>
<string name="pacing_balanced_alt">Балансирано с FPS лимит</string>
<string name="pacing_smoothness">Предпочитане на най-плавно видео (може значително да увеличи латентността)</string>
<string name="conn_metered">Предупреждение: Вашата активна мрежова връзка се измерва!</string>
<string name="conn_client_latency_hw">латентност на хардуерния декодер:</string>
<string name="conn_hardware_latency">Средна латентност на хардуерно декодиране:</string>
<string name="ip_hint">IP адрес на GeForce PC</string>
<string name="pcview_menu_send_wol">Изпращане на Wake-On-LAN заявка</string>
<string name="pcview_menu_delete_pc">Изтрий компютъра</string>
<string name="pcview_menu_test_network">Тестване на мрежовата връзка</string>
<string name="pcview_menu_details">Детайли</string>
<string name="nettest_title_waiting">Тестване на мрежовата връзка</string>
<string name="nettest_title_done">Тестът на мрежата е завършен</string>
<string name="pairing">Сдвояване…</string>
<string name="pair_pc_offline">Компютърът е офлайн</string>
<string name="pair_pc_ingame">Компютърът в момента е в игра. Трябва да затворите играта преди сдвояване.</string>
<string name="pair_pairing_title">Сдвояване</string>
<string name="wol_waking_pc">Събуждащ се компютъра…</string>
<string name="unpair_fail">Неуспешно раздвояване</string>
<string name="unpair_error">Устройството не беше сдвоено</string>
<string name="error_pc_offline">Компютърът е офлайн</string>
<string name="title_decoding_error">Видеодекодерът крашна</string>
<string name="no_frame_received_error">Мрежовата ви връзка не работи добре. Намалете настройката си за битрейт на видео или опитайте с по-бърза връзка.</string>
<string name="conn_client_latency">Средна латентност при декодиране на кадър:</string>
<string name="conn_starting">Стартиране</string>
<string name="conn_terminated_title">Връзката е прекратена</string>
<string name="yes">Да</string>
<string name="applist_menu_hide_app">Скриване на приложението</string>
<string name="applist_refresh_title">Списък с приложения</string>
<string name="summary_resolution_list">Увеличете, за да подобрите яснотата на изображението. Намалете за по-добра производителност на устройства от по-нисък клас и по-бавни мрежи.</string>
<string name="title_fps_list">Кадрова честота на видео</string>
<string name="scut_deleted_pc">Компютърът е изтрит</string>
<string name="scut_not_paired">Компютърът не е сдвоен</string>
<string name="scut_pc_not_found">Компютърът не е намерен</string>
<string name="scut_invalid_uuid">Предоставеният компютър не е валиден</string>
<string name="scut_invalid_app_id">Предоставеното приложение не е валидно</string>
<string name="help_loading_msg">Помощната страница се зарежда…</string>
<string name="help_loading_title">Помощ</string>
<string name="pcview_menu_header_online">Онлайн</string>
<string name="pcview_menu_header_unknown">Презареждане</string>
<string name="pcview_menu_pair_pc">Сдвояване с компютър</string>
<string name="pcview_menu_header_offline">Извън линия</string>
<string name="pcview_menu_app_list">Вижте Всички Приложения</string>
<string name="pcview_menu_unpair_pc">Раздвояване</string>
<string name="nettest_text_waiting">Moonlight тества вашата мрежова връзка, за да определи дали NVIDIA GameStream е блокиран.
\n
\nТова може да отнеме няколко секунди…</string>
<string name="nettest_text_success">Вашата мрежа изглежда не блокира Moonlight. Ако все още имате проблеми със свързването, проверете настройките на защитната стена на вашия компютър.
\n
\nАко се опитвате да стриймвате през интернет, инсталирайте Moonlight Internet Hosting Tool на вашия компютър и стартирайте включения тестер за интернет стрийминг, за да проверите интернет връзката на вашия компютър.</string>
<string name="nettest_text_inconclusive">Мрежовият тест не можа да бъде извършен, защото нито един от сървърите за тестване на връзката на Moonlight не е достъпен. Проверете връзката си с интернет или опитайте отново по-късно.</string>
<string name="nettest_text_failure">Текущата мрежова връзка на вашето устройство изглежда блокира Moonlight. Стриймването през интернет може да не работи, докато сте свързани към тази мрежа.
\n
\nСледните мрежови портове са блокирани:
\n</string>
<string name="nettest_text_blocked">Текущата мрежова връзка на вашето устройство блокира Moonlight. Стриймването през интернет може да не работи, докато сте свързани към тази мрежа.</string>
<string name="pair_pairing_msg">Моля, въведете следния ПИН на избрания компютър:</string>
<string name="pair_fail">Неуспешно сдвояване</string>
<string name="pair_already_in_progress">Сдвояването вече е в ход</string>
<string name="wol_pc_online">Компютърът е онлайн</string>
<string name="wol_no_mac">Компютърът не може да бъде събуден, защото GFE не изпрати MAC адрес</string>
<string name="wol_fail">Неуспешно изпращане на Wake-On-LAN пакети</string>
<string name="wol_waking_msg">Може да отнеме няколко секунди, докато вашият компютър се събуди. Ако не стане, уверете се, че е конфигуриран правилно за Wake-On-LAN.</string>
<string name="unpairing">Раздвояване…</string>
<string name="unpair_success">Раздвояването бе успешно</string>
<string name="video_decoder_init_failed">Видео декодерът не успя да се инициализира. Вашето устройство може да не поддържа избраната резолюция или честота.</string>
<string name="error_manager_not_running">Услугата ComputerManager не работи. Моля, изчакайте няколко секунди или рестартирайте приложението.</string>
<string name="error_404">GFE върна грешка HTTP 404. Уверете се, че вашият компютър има поддръжана видео карта. Използването на софтуер за отдалечен работен плот също може да причини тази грешка. Опитайте да рестартирате машината си или да преинсталирате GFE.</string>
<string name="message_decoding_error">Moonlight претърпя срив поради несъвместимост с видеодекодера на това устройство. Уверете се, че GeForce Experience е актуализиран до най-новата версия на вашия компютър. Опитайте да коригирате настройките за стриймване, ако сривовете продължат.</string>
<string name="title_decoding_reset">Нулиране на видео настройките</string>
<string name="message_decoding_reset">Видео декодерът на вашето устройство продължава да се срива при избраните от вас настройки за стриймване. Настройките са нулирани по подразбиране.</string>
<string name="audioconf_stereo">Стерео</string>
<string name="applist_refresh_msg">Приложенията се опресняват…</string>
<string name="error_usb_prohibited">USB достъпът е забранен от администратора на вашето устройство. Проверете настройките на Knox или MDM.</string>
<string name="audioconf_71surround">7.1 съраунд звук</string>
<string name="audioconf_51surround">5.1 съраунд звук</string>
<string name="videoformat_auto">Автоматично</string>
<string name="videoformat_hevcalways">Винаги използване на HEVC (може да крашне)</string>
<string name="summary_frame_pacing">Посочете как да се балансира забавянето и плавността на видеото</string>
<string name="title_frame_pacing">Стъпка на видео кадрите</string>
<string name="pacing_balanced">Балансирано</string>
<string name="check_ports_msg">Проверете вашата защитна стена и правилата за препращане на портове за порт(ове):</string>
<string name="conn_establishing_title">Установяване на връзка</string>
<string name="conn_establishing_msg">Стартиране на връзка</string>
<string name="conn_error_msg">Неуспешно стартиране</string>
<string name="conn_terminated_msg">Връзката беше прекратена</string>
<string name="conn_error_title">Грешка при свързване</string>
<string name="no">Не</string>
<string name="help">Помощ</string>
<string name="lost_connection">Загубена връзка с компютър</string>
<string name="title_details">Подробности</string>
<string name="delete_pc_msg">Сигурни ли сте, че искате да изтриете този компютър\?</string>
<string name="poor_connection_msg">Лоша връзка с компютъра</string>
<string name="perf_overlay_streamdetails">Видео поток: %1$s %2$.2f FPS</string>
<string name="perf_overlay_decoder">Декодер: %1$s</string>
<string name="perf_overlay_netdrops">Кадри, пропуснати от вашата мрежова връзка: %1$.2f%%</string>
<string name="perf_overlay_incomingfps">Входяща честота на кадрите от мрежата: %1$.2f FPS</string>
<string name="perf_overlay_netlatency">Средно забавяне на мрежата: %1$d ms (variance: %2$d ms)</string>
<string name="applist_connect_msg">Свързване с компютъра…</string>
<string name="perf_overlay_renderingfps">Кадрова честота на изобразяване: %1$.2f FPS</string>
<string name="perf_overlay_dectime">Средно време за декодиране: %1$.2f ms</string>
<string name="applist_menu_quit">Прекратяване на сесията</string>
<string name="msg_add_pc">Свързване към компютъра…</string>
<string name="applist_menu_resume">Възобновяване на сесията</string>
<string name="applist_menu_quit_and_start">Изключване на текущата игра и стартиране</string>
<string name="applist_menu_cancel">Отказ</string>
<string name="applist_menu_details">Виж детайлите</string>
<string name="applist_menu_scut">Създаване на пряк път</string>
<string name="applist_refresh_error_title">Грешка</string>
<string name="applist_menu_tv_channel">Добавяне към канал</string>
<string name="applist_refresh_error_msg">Неуспешно получаване на списък с приложения</string>
<string name="applist_quit_success">Успешно изключване</string>
<string name="applist_quit_app">Изключване</string>
<string name="applist_quit_fail">Неуспешно изключване</string>
<string name="applist_details_id">ID на приложението:</string>
<string name="applist_quit_confirmation">Сигурни ли сте, че искате да затворите работещото приложение\? Всички незапазени данни ще бъдат загубени.</string>
<string name="title_add_pc">Ръчно добавяне на компютър</string>
<string name="addpc_fail">Неуспешна връзка с посочения компютър. Уверете се, че необходимите портове са разрешени през защитната стена.</string>
<string name="category_basic_settings">Основни настройки</string>
<string name="addpc_success">Успешно добавен компютър</string>
<string name="addpc_enter_ip">Трябва да въведете IP адрес</string>
<string name="addpc_wrong_sitelocal">Този адрес не изглежда правилен. Трябва да използвате публичния IP адрес на вашия рутер за стриймване през интернет.</string>
<string name="title_resolution_list">Видео резолюция</string>
<string name="summary_fps_list">Увеличете за по-плавен видео поток. Намалете за по-добра производителност на устройства от по-нисък клас.</string>
<string name="title_seekbar_bitrate">Видео битрейт</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="title_audio_config_list">Конфигурация на съраунд звук</string>
<string name="summary_audio_config_list">Активиране на 5.1 или 7.1 съраунд звук за системи за домашно кино</string>
<string name="summary_seekbar_bitrate">Увеличете за по-добро качество на изображението. Намалете, за да подобрите производителността при по-бавни връзки.</string>
<string name="resolution_prefix_native_portrait">(Портрет)</string>
<string name="title_checkbox_enable_audiofx">Активиране на поддръжката на системния еквалайзер</string>
<string name="title_checkbox_stretch_video">Разтегляне на видеото на цял екран</string>
<string name="resolution_prefix_native_landscape">(Пейзаж)</string>
<string name="category_audio_settings">Аудио настройки</string>
<string name="category_input_settings">Настройки за въвеждане</string>
<string name="title_checkbox_touchscreen_trackpad">Използване на сензорния екран като тракпад</string>
<string name="title_checkbox_multi_controller">Автоматично откриване на наличен контролер</string>
<string name="summary_checkbox_multi_controller">Премахването на отметката от тази опция принуждава контролер винаги да присъства</string>
</resources>
+249 -1
View File
@@ -1,2 +1,250 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
<resources>
<string name="conn_establishing_title">Připojování</string>
<string name="conn_metered">Varování: Vaše aktivní připojení je měřené!</string>
<string name="conn_error_msg">Spouštění se nezdařilo</string>
<string name="conn_client_latency_hw">zpoždění hardwarového dekodéru:</string>
<string name="conn_terminated_title">Spojení ukončeno</string>
<string name="resolution_prefix_native_fullscreen">Nativní celá obrazovka</string>
<string name="summary_checkbox_enable_audiofx">Umožňuje fungování zvukových efektů během streamování, ale může zvýšit zpoždění zvuku</string>
<string name="early_termination_error">Na hostitelském PC se něco pokazilo při spouštění streamu.
\n
\nUjistěte se, že na hostitelském počítači neběží žádný obsah chráněný DRM. Můžete také zkusit restartovat hostitelský PC.
\n
\nPokud problém přetrvává, zkuste přeinstalovat ovladače GPU a GeForce Experience.</string>
<string name="wol_waking_pc">Probouzení PC…</string>
<string name="nettest_text_success">Vypadá to, že vaše síť Moonlight neblokuje. Pokud máte i tak potíže s připojením, zkontrolujte nastavení firewallu vašeho PC.
\n
\nPokud se pokoušíte streamovat po internetu, nainstalujte si na svůj počítač Moonlight Internet Hosting Tool a spusťte přiložený program Internet Streaming Tester pro kontrolu vašeho připojení k Internetu.</string>
<string name="error_unknown_host">Nezdařilo se zjistit hostitele</string>
<string name="nettest_text_waiting">Moonlight testuje vaše síťové připojení, aby zjistil, jestli je NVIDIA GameStream zablokován.
\n
\nTo může chvilku zabrat…</string>
<string name="nettest_title_waiting">Testování připojení k síti</string>
<string name="pairing">Párování…</string>
<string name="pair_pc_offline">Počítač je offline</string>
<string name="unpairing">Rušení párování…</string>
<string name="unpair_success">Párování úspěšně zrušeno</string>
<string name="unpair_error">Zařízení nebylo spárováno</string>
<string name="error_manager_not_running">Služba ComputerManager neběží. Vyčkejte prosím chvíli nebo restartujte aplikaci.</string>
<string name="error_pc_offline">Počítač je offline</string>
<string name="unpair_fail">Zrušení párování se nezdařilo</string>
<string name="error_404">GFE vrátilo HTTP chybu 404. Ujistěte se, že vaše PC má podporované GPU. Tato chyba může být způsobena i použitím softwaru pro vzdálenou plochu. Zkuste restartovat počítač, nebo přeinstalujte GFE.</string>
<string name="title_decoding_error">Dekodér videa spadnul</string>
<string name="error_usb_prohibited">Správce zařízení neumožňuje přístup k USB. Zkontrolujte nastavení Knoxu nebo MDM.</string>
<string name="message_decoding_error">Moonlight spadnul kvůli nekompatibilnímu video dekodéru na tomto zařízení. Ujistěte se, že je GeForce Experience na vašem PC aktualizováno na nejnovější verzi. Zkuste upravit nastavení streamování, pokud aplikace padá opakovaně.</string>
<string name="message_decoding_reset">Video dekodér vašeho zařízení při současných nastaveních streamování padá. Vaše nastavení streamování byla resetována na výchozí.</string>
<string name="video_decoder_init_failed">Nezdařilo se spustit video dekodér. Vaše zařízení nemusí podporovat zvolené rozlišení nebo snímkovou frekvenci.</string>
<string name="no_video_received_error">Od hostitele nebylo přijato žádné video.</string>
<string name="no_frame_received_error">Vaše připojení k síti není dost rychlé. Zkuste snížit datový tok videa nebo použijte rychlejší připojení.</string>
<string name="applist_menu_hide_app">Skrýt aplikaci</string>
<string name="title_add_pc">Přidat PC ručně</string>
<string name="title_audio_config_list">Konfigurace prostorového zvuku</string>
<string name="searching_pc">Hledání PC, na kterých běží GameStream...
\n
\nUjistěte se, že je GameStream povolen v záložce SHIELD v nastavení GeForce Experience.</string>
<string name="applist_menu_quit">Ukončit</string>
<string name="applist_menu_quit_and_start">Ukončit současnou hru a spustit</string>
<string name="applist_menu_cancel">Zrušit</string>
<string name="applist_menu_tv_channel">Přidat do kanálu</string>
<string name="applist_refresh_title">Seznam aplikací</string>
<string name="applist_menu_resume">Pokračovat</string>
<string name="applist_menu_details">Zobrazit detaily</string>
<string name="applist_menu_scut">Vytvořit zkratku</string>
<string name="addpc_success">Počítač přidán úspěšně</string>
<string name="applist_details_id">ID aplikace:</string>
<string name="addpc_fail">K zadanému počítači se nepodařilo připojit. Ujistěte se, že jsou ve firewallu povoleny nezbytné porty.</string>
<string name="addpc_enter_ip">Musíte zadat IP adresu</string>
<string name="title_native_res_dialog">Varování pro nativní rozlišení</string>
<string name="title_checkbox_vibrate_fallback">Emulovat podporu vibrací</string>
<string name="title_seekbar_deadzone">Upravit deadzone analogových páček</string>
<string name="check_ports_msg">Zkontrolujte svůj firewall a pravidla přesměrování pro tyto porty:</string>
<string name="conn_terminated_msg">Spojení bylo ukončeno</string>
<string name="ip_hint">IP adresa GeForce PC</string>
<string name="conn_hardware_latency">Průměrné zpoždění hardwarového dekodéru:</string>
<string name="conn_client_latency">Průměrné zpoždění při dekódování snímků:</string>
<string name="perf_overlay_netlatency">Průměrné zpoždění sítě: %1$d ms (odchylka: %2$d ms)</string>
<string name="perf_overlay_dectime">Průměrný čas pro dekódování: %1$.2f ms</string>
<string name="applist_connect_msg">Připojování k PC…</string>
<string name="title_checkbox_touchscreen_trackpad">Použít dotykový displej jako trackpad</string>
<string name="title_checkbox_multi_controller">Automatická detekce připojení herního ovladače</string>
<string name="summary_checkbox_multi_controller">Odškrtnutí této možnosti vynutí, aby byl herní ovladač vždy připojen</string>
<string name="summary_checkbox_xb1_driver">Povolí zabudovaný USB ovladač pro zařízení bez nativní podpory pro Xbox ovladač</string>
<string name="summary_checkbox_vibrate_fallback">Rozvibruje vaše zařízení pro emulaci vibrací ovladače, pokud je váš herní ovladač nepodporuje</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="summary_seekbar_deadzone">Poznámka: Některé hry mohou vynutit větší deadzone, než jaká je nastavena v Moonlightu.</string>
<string name="title_checkbox_xb1_driver">Xbox 360/One USB gamepad ovladač</string>
<string name="title_checkbox_usb_bind_all">Vynutit nativní podporu herního ovladače Xbox</string>
<string name="summary_checkbox_mouse_emulation">Dlouhým podržením tlačítka Start přepnete herní ovladač do režimu myši</string>
<string name="summary_checkbox_usb_bind_all">Použít USB ovladač Moonlightu pro všechny podporované gamepady, i když existuje nativní podpora pro Xbox ovladač</string>
<string name="title_checkbox_mouse_emulation">Emulace myši pomocí herního ovladače</string>
<string name="title_checkbox_flip_face_buttons">Přehodit tlačítka A/B, X/Y</string>
<string name="title_checkbox_absolute_mouse_mode">Režim myši pro vzdálenou plochu</string>
<string name="summary_checkbox_absolute_mouse_mode">Tímto zapnete přirozenější zrychlování myši pro použití ve vzdálené ploše, ale možnost je nekompatibilní se spoustou her.</string>
<string name="summary_osc_opacity">Zmenšete či zvětšete průhlednost ovladače na obrazovce</string>
<string name="summary_only_l3r3">Skryje veškerá virtuální tlačítka kromě L3 a R3</string>
<string name="category_ui_settings">Nastavení zobrazení</string>
<string name="suffix_osc_opacity">%</string>
<string name="title_setup_guide">Průvodce nastavením</string>
<string name="title_checkbox_disable_warnings">Zakázat varovací zprávy</string>
<string name="category_help">Nápověda</string>
<string name="summary_checkbox_disable_warnings">Zakáže varování o pomalém připojení během streamování</string>
<string name="title_disable_frame_drop">Nezahazovat snímky</string>
<string name="title_enable_perf_overlay">Zobrazit během streamování informace o výkonu</string>
<string name="summary_enable_perf_overlay">Zobrazit realtime informace o výkonu streamu během streamování</string>
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="title_troubleshooting">Průvodce řešením problémů</string>
<string name="summary_troubleshooting">Zobrazit tipy pro diagnózu a opravu běžných problémů se streamováním</string>
<string name="resolution_720p">720p</string>
<string name="resolution_1080p">1080p</string>
<string name="resolution_1440p">1440p</string>
<string name="videoformat_auto">Automaticky</string>
<string name="audioconf_71surround">7.1 prostorový zvuk</string>
<string name="pacing_balanced">Vyvážené</string>
<string name="pacing_smoothness">Preferovat plynulejší video (může výrazně zvýšit zpoždění)</string>
<string name="resolution_prefix_native_landscape">(na šířku)</string>
<string name="resolution_prefix_native_portrait">(na výšku)</string>
<string name="category_audio_settings">Nastavení zvuku</string>
<string name="title_checkbox_enable_audiofx">Povolit podporu systémového ekvalizéru</string>
<string name="category_input_settings">Nastavení vstupu</string>
<string name="summary_setup_guide">Zobrazit instrukce k nastavení vašeho herního PC pro streamování</string>
<string name="dialog_title_osc_opacity">Změnit průhlednost</string>
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="fps_120">120 FPS</string>
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">5.1 prostorový zvuk</string>
<string name="help_loading_msg">Načítání stránky s nápovědou…</string>
<string name="pcview_menu_header_online">Online</string>
<string name="pcview_menu_header_offline">Offline</string>
<string name="pcview_menu_header_unknown">Obnovování</string>
<string name="pcview_menu_app_list">Zobrazit všechny aplikace</string>
<string name="pcview_menu_pair_pc">Spárovat s PC</string>
<string name="pcview_menu_unpair_pc">Zrušit párování</string>
<string name="pcview_menu_send_wol">Poslat Wake-On-LAN požadavek</string>
<string name="pcview_menu_delete_pc">Smazat PC</string>
<string name="pcview_menu_test_network">Otestovat připojení k síti</string>
<string name="pcview_menu_details">Zobrazit detaily</string>
<string name="nettest_title_done">Test sítě dokončen</string>
<string name="nettest_text_inconclusive">Test sítě nemohl být proveden, protože se nezdařilo připoojení k žádným z testovacíh serverů Moonlight. Zkontrolujte své připojení k Internetu, nebo to zkuste znovu později.</string>
<string name="nettest_text_failure">Současná síť vašeho počítače nejspíš blokuje Moonlight. Streamování přes Internet nemusí během připojení k této síti fungovat.
\n
\nNásledující porty byly zablokovány:
\n</string>
<string name="nettest_text_blocked">Vaše současné připojení k síti blokuje Moonlight. Streamování přes Internet nemusí fungovat, dokud jste připojeni k této síti.</string>
<string name="pair_pc_ingame">Na počítači momentálně běží hra. Před párováním musíte hru zavřít.</string>
<string name="pair_pairing_title">Párování</string>
<string name="pair_pairing_msg">Vložte prosím následující PIN na cílovém PC:</string>
<string name="pair_incorrect_pin">Nesprávný PIN</string>
<string name="pair_fail">Párování selhalo</string>
<string name="pair_already_in_progress">Párování již probíhá</string>
<string name="wol_pc_online">Počítač je online</string>
<string name="wol_no_mac">Nezdařilo se probudit PC, protože GFE nezaslalo MAC adresu</string>
<string name="title_decoding_reset">Reset nastavení videa</string>
<string name="unable_to_pin_shortcut">Váš současný launcher neumožňuje vytváření zástupců.</string>
<string name="conn_establishing_msg">Připojování</string>
<string name="conn_starting">Spouštění</string>
<string name="conn_error_title">Chyba připojení</string>
<string name="frame_conversion_error">Hostitelský počítač hlásí fatální chybu enkódování videa.
\n
\nZkuste vypnout HDR, změňte rozlišení streamu nebo rozlišení displeje hostitelského PC.</string>
<string name="yes">Ano</string>
<string name="no">Ne</string>
<string name="lost_connection">Připojení k PC bylo ztraceno</string>
<string name="title_details">Detaily</string>
<string name="perf_overlay_renderingfps">Vykreslovací snímková frekvence: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Snímky zahozeny vašim připojením: %1$.2f%%</string>
<string name="applist_refresh_msg">Obnovování aplikací…</string>
<string name="applist_refresh_error_title">Chyba</string>
<string name="applist_refresh_error_msg">Nezdařilo se získat seznam aplikací</string>
<string name="applist_quit_app">Ukončování</string>
<string name="applist_quit_success">Úspěšně ukončeno</string>
<string name="applist_quit_fail">Ukončení se nezdařilo</string>
<string name="applist_quit_confirmation">Určitě chcete ukončit běžící aplikaci\? Neuložená data budou ztracena.</string>
<string name="msg_add_pc">Připojování k PC…</string>
<string name="addpc_unknown_host">Nezdařilo se připojit k adrese PC. Ujistěte se, že v adrese není překlep.</string>
<string name="addpc_wrong_sitelocal">Tahle adresa nevypadá správně. Musíte zadat veřejnou IP vašeho routeru, pokud chcete streamovat přes Internet.</string>
<string name="category_basic_settings">Základní nastavení</string>
<string name="title_resolution_list">Rozlišení videa</string>
<string name="summary_resolution_list">Zvyšte přo zlepšení ostrosti obrazu. Snižte pro lepší výkon na levnějších zařízeních nebo pomalejších sítích.</string>
<string name="summary_audio_config_list">Povolit 5.1 nebo 7.1 prostorový zvuk pro systémy domácího kina</string>
<string name="summary_checkbox_touchscreen_trackpad">Pokud je povoleno, dotykový displej funguje jako trackpad. Pokud je zakázáno, dotykový displej ovládá kurzor myši přímo.</string>
<string name="title_reset_osc">Vymazat uložené rozložení ovladače na obrazovce</string>
<string name="summary_reset_osc">Resetuje všechna nastavení ovladače na obrazovce na jejich výchozí velikost a pozici</string>
<string name="title_osc_opacity">Změnit průhlednost ovladače na obrazovce</string>
<string name="category_advanced_settings">Pokročilá nastavení</string>
<string name="title_unlock_fps">Odemknout všechny možné snímkové frekvence</string>
<string name="title_checkbox_reduce_refresh_rate">Povolit snížení obnovovací frekvence</string>
<string name="summary_checkbox_reduce_refresh_rate">Menší obnovovací frekvence displeje může šetřit energii výměnou za zvýšení zpoždění videa</string>
<string name="title_checkbox_mouse_nav_buttons">Povolit tlačítka myši zpět a vpřed</string>
<string name="summary_checkbox_mouse_nav_buttons">Povolení této možnosti může na některých pochybných zařízeních rozbít klikání pravým tlačítkem</string>
<string name="summary_checkbox_flip_face_buttons">Přehodí tlačítka A/B a X/Y na herním ovladači a instrukcích na obrazovce</string>
<string name="toast_reset_osc_success">Ovladač na obrazovce resetován</string>
<string name="dialog_title_reset_osc">Reset rozložení</string>
<string name="dialog_text_reset_osc">Jste si jisti, že chcete smazat vaše uložené rozložení ovladače\?</string>
<string name="title_checkbox_enable_pip">Povolit sledovací rezim obraz-v-obraze</string>
<string name="summary_checkbox_enable_sops">Povolit GFE měnit herní nastavení pro optimální streamování</string>
<string name="title_checkbox_host_audio">Přehrávat zvuk na PC</string>
<string name="summary_checkbox_host_audio">Přehraje zvuk z počítače a tohoto zařízení</string>
<string name="summary_unlock_fps">Streamování v 90 nebo 120 FPS může snížit zpoždění na dražších zařízeních, ale může způsobit zasekávání nebo nestabilitu na zařízeních, které je nepodporují</string>
<string name="title_enable_post_stream_toast">Zobrazit informace o zpoždění po streamování</string>
<string name="summary_enable_post_stream_toast">Zobrazit informace o zpoždění po skončení streamování</string>
<string name="title_privacy_policy">Zásady ochrany osobních údajů</string>
<string name="summary_privacy_policy">Zobrazit zásady ochrany osobních údajů Moonlightu</string>
<string name="resolution_360p">360p</string>
<string name="resolution_480p">480p</string>
<string name="pacing_balanced_alt">Vyvážené s limitem FPS</string>
<string name="scut_deleted_pc">PC smazán</string>
<string name="scut_not_paired">PC nespárován</string>
<string name="scut_pc_not_found">PC nenalezen</string>
<string name="scut_invalid_uuid">Zadaný počítač není platný</string>
<string name="scut_invalid_app_id">Zadaná aplikace není platná</string>
<string name="help_loading_title">Zobrazení nápovědy</string>
<string name="wol_waking_msg">Může trvat pár sekund, než se váš počítač probudí. Pokud se tak nestane, ujistěte se, že máte správně nastaveno Wake-On-LAN.</string>
<string name="wol_fail">Nezdařilo se odeslat Wake-On-LAN pakety</string>
<string name="help">Nápověda</string>
<string name="delete_pc_msg">Určitě chcete smazat tento PC\?</string>
<string name="slow_connection_msg">Pomalé připojení k PC
\nSnižte datový tok</string>
<string name="poor_connection_msg">Špatné připojení k PC</string>
<string name="perf_overlay_streamdetails">Video stream: %1$s %2$.2f FPS</string>
<string name="perf_overlay_decoder">Dekodér: %1$s</string>
<string name="perf_overlay_incomingfps">Příchozí snímková frekvence po síti: %1$.2f FPS</string>
<string name="text_native_res_dialog">GeForce Experience oficiálně nepodporuje nativní rozlišení a proto nenastaví rozlišení displeje vašeho hostitelského PC. Musíte jej nastavit ručně ve hře.
\n
\nPokud v NVIDIA Control Panelu vytvoříte vlastní rozlišení pro vaše zařízení, prosím ujistěte se, že jste si přečetli a že chápete varování od NVIDIE ohledně možného poškození monitoru, nestability PC a dalších možných problémů.
\n
\nNejsme zodpovědni za žádné problémy, které vzniknou používáním vlastního rozlišení na vašem PC.
\n
\nA nakonec, vaše zařízení nebo hostitelský počítač nemusí podporovat streamování v nativním rozlišení. Pokud vám to nefunguje, bohužel se s tím nedá nic dělat.</string>
<string name="title_fps_list">Snímková frekvence videa</string>
<string name="summary_fps_list">Zvyšte pro plynulejší video stream. Snižte pro lepší výkon na levnějších zařízeních.</string>
<string name="title_seekbar_bitrate">Datový tok videa</string>
<string name="summary_seekbar_bitrate">Zvyšte pro lepší kvalitu obrazu. Snižte pro zlepšení výkonu u pomalých připojení.</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="title_checkbox_stretch_video">Natáhnout video na celou obrazovku</string>
<string name="resolution_prefix_native">Nativní</string>
<string name="category_on_screen_controls_settings">Nastavení ovládání na obrazovce</string>
<string name="title_checkbox_show_onscreen_controls">Zobrazovat ovládání na obrazovce</string>
<string name="summary_checkbox_show_onscreen_controls">Zobrazit překrytí virtuálního ovladače na dotykovém displeji</string>
<string name="title_checkbox_vibrate_osc">Povolit vibrace</string>
<string name="summary_checkbox_vibrate_osc">Vibruje vašim zařízením pro emulaci vibrací ovladače při použití ovladače na obrazovce</string>
<string name="title_only_l3r3">Zobrazit pouze L3 a R3</string>
<string name="summary_checkbox_enable_pip">Umožní, aby byl stream sledován (ale ne ovládá) během multitaskingu</string>
<string name="title_language_list">Jazyk</string>
<string name="summary_language_list">Jazyk, který bude Moonlight používat</string>
<string name="title_checkbox_small_icon_mode">Použít malý box art</string>
<string name="summary_checkbox_small_icon_mode">Díky menšímu box artu v seznamu aplikací uvidíte na obrazovce více aplikací naráz</string>
<string name="category_host_settings">Nastavení hostitele</string>
<string name="title_checkbox_enable_sops">Optimalizovat herní nastavení</string>
<string name="summary_disable_frame_drop">Může na některých zařízeních snížit mikrozádrhy, ale může zvýšit zpoždění</string>
<string name="title_video_format">Změnit nastavení HEVC</string>
<string name="summary_video_format">HEVC sníží datový přenos, ale vyžaduje novější zařízení</string>
<string name="title_enable_hdr">Povolit HDR (experimentální)</string>
<string name="summary_enable_hdr">Streamovat v HDR, pokud jej hra a GPU počítače podporují. HDR vyžaduje GPU GTX 1000 nebo novější.</string>
<string name="videoformat_hevcalways">Vždy použít HEVC (může padat)</string>
<string name="title_frame_pacing">Frame pacing videa</string>
<string name="summary_frame_pacing">Zvolte, jak vyvážit zpoždění videa a jeho plynulost</string>
<string name="pacing_latency">Preferovat nejnižší zpoždění</string>
</resources>
+14 -3
View File
@@ -79,7 +79,7 @@
<string name="conn_terminated_title">Verbindung beendet</string>
<string name="conn_terminated_msg">Die Verbindung wurde beendet</string>
<!-- 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…
\n
\nStelle sicher, dass GameStream in den GeForce Experience SHIELD-Einstellungen aktiviert ist.</string>
@@ -218,9 +218,8 @@
<string name="pcview_menu_header_offline">Offline</string>
<string name="pcview_menu_header_online">Online</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Automatisch</string>
<string name="videoformat_auto">Automatisch</string>
<string name="videoformat_hevcalways">Immer HEVC verwenden (könnte Crashes verursachen)</string>
<string name="videoformat_hevcnever">Nie HEVC verwenden</string>
<string name="title_frame_pacing">Video Frame-Pacing</string>
<string name="summary_frame_pacing">Lege fest, wie die Videolatenz und die flüssige Wiedergabe ausgeglichen werden sollen</string>
<string name="resolution_prefix_native_fullscreen">Natives Vollbild</string>
@@ -259,4 +258,16 @@
<string name="title_checkbox_reduce_refresh_rate">Aktualisierungsrate verringern erlauben</string>
<string name="summary_checkbox_reduce_refresh_rate">Durch das Verringern der Display Aktualisierungsrate, kann, auf Kosten der Video-Latenz, der Akkuverbrauch reduziert werden</string>
<string name="resolution_prefix_native_landscape">(Landscape)</string>
<string name="frame_conversion_error">Der Host-PC hat einen schwerwiegenden Videocodierungsfehler gemeldet.
\n
\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>
</resources>
+46 -24
View File
@@ -16,7 +16,7 @@
<string name="pair_fail">Fallo al emparejar</string>
<!-- WOL messages -->
<string name="wol_pc_online">Ordenador encendido</string>
<string name="wol_no_mac">Imposible iniciar PC porque GFE no ha enviado una dirección MAC</string>
<string name="wol_no_mac">No se puede activar el PC porque no hay ninguna dirección MAC almacenada</string>
<string name="wol_waking_pc">Iniciando PC…</string>
<string name="wol_waking_msg">Puede tomar algunos segundos iniciar tu PC.
Si no se inicia asegúrate que está configurado correctamente para Wake-On-LAN.
@@ -47,10 +47,10 @@
<string name="conn_terminated_title">Conexión finalizada</string>
<string name="conn_terminated_msg">La conexión ha finalizando</string>
<!-- General strings -->
<string name="ip_hint">Dirección IP del PC con GeForce</string>
<string name="searching_pc">Buscando por PCs con GameStream ejecutándose...
<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...
\n
\nVerifica que GameStream esté activado en las opciones de SHIELD dentro de GeForce Experience.</string>
\n Asegúrate de que Sunshine se está ejecutando en el PC anfitrión o de que GameStream está activado en los ajustes de GeForce Experience SHIELD.</string>
<string name="yes">Si</string>
<string name="no">No</string>
<string name="lost_connection">Conexión perdida</string>
@@ -76,14 +76,14 @@
<string name="addpc_enter_ip">Debes introducir una dirección IP</string>
<!-- Preferences -->
<string name="category_basic_settings">Configuración básica</string>
<string name="title_resolution_list">Seleccionar resolución y FPS</string>
<string name="title_resolution_list">Seleccionar resolución</string>
<string name="summary_resolution_list">Establecer unos valores demasiado altos puede causar retraso o cierres inesperados.</string>
<string name="title_seekbar_bitrate">Seleccionar bitrate de vídeo</string>
<string name="summary_seekbar_bitrate">Usa bitrate bajo para reducir "parpadeo". Incrementa el bitrate para mayor calidad de imagen.</string>
<string name="title_checkbox_stretch_video">Ajustar vídeo a pantalla completa</string>
<string name="title_checkbox_disable_warnings">Desactivar mensajes de advertencia</string>
<string name="summary_checkbox_disable_warnings">Desactivar mensajes de advertencia en pantalla durante la transmisión</string>
<string name="category_audio_settings">Configuración de audio</string>
<string name="category_audio_settings">Ajustes del audio</string>
<string name="title_checkbox_multi_controller">Soporte para múltiples mandos</string>
<string name="summary_checkbox_multi_controller">Si no está marcado, todos los mandos aparecen como uno solo</string>
<string name="title_seekbar_deadzone">Ajustar zona muerta del stick analógico</string>
@@ -106,12 +106,11 @@
<string name="title_checkbox_host_audio">Reproducir audio en PC</string>
<string name="summary_checkbox_host_audio">Reproducir audio en el ordenador y en este dispositivo</string>
<string name="category_advanced_settings">Configuración avanzada</string>
<string name="title_video_format">Cambiar configuración HEVC</string>
<string name="summary_video_format">HEVC reduce el ancho de banda de vídeo, pero requiere un dispositivo reciente</string>
<string name="title_video_format">Cambiar la configuración del códec</string>
<string name="summary_video_format">Los códecs más recientes pueden reducir los requisitos del ancho de banda del vídeo si tu dispositivo los admite. Las selecciones de los códecs pueden ignorarse si no son compatibles con el software del host o la GPU.</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Usar HEVC sólo si es estable</string>
<string name="videoformat_hevcalways">Siempre usar HEVC (puede fallar)</string>
<string name="videoformat_hevcnever">Nunca usar HEVC</string>
<string name="videoformat_auto">Automático (Recomendado)</string>
<string name="videoformat_hevcalways">Preferir HEVC</string>
<string name="nettest_title_done">Prueba de Red Completada</string>
<string name="scut_not_paired">PC no emparejado</string>
<string name="scut_invalid_uuid">El PC proporcionado no es válido</string>
@@ -122,9 +121,9 @@
<string name="pcview_menu_test_network">Probar Conexión de Red</string>
<string name="pcview_menu_details">Ver Detalles</string>
<string name="nettest_title_waiting">Probando Conexión de Red</string>
<string name="nettest_text_waiting">Moonlight esta probando tu conexión de red para determinar si NVIDIA GameStream esta bloqueado.
<string name="nettest_text_waiting">Moonlight está probando tu conexión a la red para determinar si algún puerto necesario está bloqueado.
\n
\nEsto puede tomar algunos segundos </string>
\nEsto puede tardar unos segundos…</string>
<string name="nettest_text_inconclusive">La prueba de red no pudo ejecutarse debido a que no se pudo alcanzar ningún servidor de prueba de conexión de Moonlight. Revisa tu conexión a internet o prueba nuevamente mas tarde.</string>
<string name="nettest_text_failure">La actual conexión de red de tu dispositivo parece estar bloqueando Moonlight. La Transmisión mediante Internet puede no funcionar mientras estes conectado a esta red.
\n
@@ -165,7 +164,7 @@
<string name="resolution_1440p">1440p</string>
<string name="resolution_4k">4K</string>
<string name="suffix_osc_opacity">%</string>
<string name="title_checkbox_enable_pip">Actividad modo Pantalla-en-Pantalla para observador</string>
<string name="title_checkbox_enable_pip">Activar modo Pantalla-en-Pantalla para modo espectador</string>
<string name="resolution_720p">720p</string>
<string name="fps_120">120 FPS</string>
<string name="audioconf_71surround">7.1 Sonido Envolvente</string>
@@ -177,16 +176,14 @@
<string name="audioconf_stereo">Estéreo</string>
<string name="check_ports_msg">Revisa la configuración de tu firewall, así como, las reglas de redireccionamiento para él(los) puerto(s):</string>
<string name="error_usb_prohibited">El acceso a USB está restringido en tu dispositivo por el administrador. Revisar tus ajustes en MDM o Knox.</string>
<string name="message_decoding_error">Moonlight se ha cerrado debido a una incompatibilidad con el decodificador de vídeo de este dispositivo. Asegúrate de que GeForce Experience está actualizado a la última versión en tu PC. Intenta ajustar la configuración de streaming si los bloqueos continúan.</string>
<string name="message_decoding_error">Moonlight se ha bloqueado debido a una incompatibilidad con el descodificador de vídeo de este dispositivo. Intenta ajustar la configuración de streaming si los bloqueos continúan.</string>
<string name="message_decoding_reset">La decodificación de video de tu equipo sigue fallando con las opciones elegidas. Las opciones de la transmisión han sido revertidas a las predeterminadas.</string>
<string name="video_decoder_init_failed">El descodificador de video no pudo ser iniciado. Tu dispositivo puede no soportar la resolución elegida o la tasa de cuadros por segundo.</string>
<string name="no_frame_received_error">La conexión de internet no está teniendo un buen desempeño. Reduce la tasa de bits de video o prueba en una conexión de mayor velocidad.</string>
<string name="unable_to_pin_shortcut">Tu lanzador predeterminado no permite la creación de accesos directos anclados.</string>
<string name="early_termination_error">Algo ha salido mal en el PC anfitrión cuando se inicio la transmisión.
<string name="early_termination_error">Algo ha fallado en tu ordenador al iniciar la transmisión.
\n
\nVerifica que no tengas ningún contenido protegido por DRM abierto en el equipo. También prueba reiniciando el equipo anfitrión.
\n
\nSi el problema persiste, intenta reinstalar los controladores de la tarjeta de video (GPU) además de GeForce Experience.</string>
\nAsegúrate de que no tienes ningún contenido protegido por DRM abierto en tu ordenador. También puedes probar a reiniciar el ordenador.</string>
<string name="title_details">Detalles</string>
<string name="poor_connection_msg">Conexión pobre al PC</string>
<string name="applist_menu_details">Ver Detalles</string>
@@ -195,13 +192,13 @@
<string name="applist_menu_hide_app">Esconder Aplicación</string>
<string name="applist_connect_msg">Conectando al Equipo…</string>
<string name="summary_checkbox_mouse_nav_buttons">Activar esta opción puede desconfigurar la función de clic derecho en algunos dispositivos inestables</string>
<string name="text_native_res_dialog">Modos de resolución nativa no son oficialmente soportados por GeForce Experience, así que no se no se aplicarán por su cuenta en la pantalla del equipo anfitrión. Vas a necesitar ajustarlos manualmente en el juego.
<string name="text_native_res_dialog">Es posible que la resolución nativa y/o los FPS no sean compatibles con el servidor de streaming. Es probable que tengas que configurar manualmente un modo de visualización personalizado para el PC host.
\n
\nSi eliges crear una resolución personalizada en el Panel de Control de Nvidia para ajustarse a la resolución de tu dispositivo, por favor considera haber leído y entendido la advertencia de NVIDIA respectivo a cualquier daño posible a tu monitor, inestabilidad del equipo, y otros problemas potencialmente posibles.
\nSi decides crear una resolución personalizada en el Panel de control de NVIDIA para que coincida con la configuración de tu pantalla, asegúrate de haber leído y comprendido la advertencia de NVIDIA sobre posibles daños en el monitor, inestabilidad del PC y otros problemas potenciales.
\n
\nNo somos responsables de cualquier problema por haber creador una resolución personalizada en tu PC.
\nNo nos hacemos responsables de ningún problema derivado de la creación de una resolución personalizada en tu PC.
\n
\nFinalmente, tu dispositivo o tu Pc anfitrión, podrían no soportar la transmisión a resolución nativa. Si no funciona en tu equipo, puede que solo no tengas suerte de momento.</string>
\nEs posible que tu monitor no admita la configuración de pantalla necesaria. Si es así, puede intentar configurar un monitor virtual. Por último, si tu dispositivo o PC anfitrión no soporta streaming a una resolución o frecuencia de refresco específica, lamentablemente no tienes suerte.</string>
<string name="resolution_prefix_native">Nativo</string>
<string name="summary_audio_config_list">Activar sonido envolvente de 5.1 o 7.1 canales para sistemas de teatro en casa</string>
<string name="title_checkbox_vibrate_fallback">Emular la vibración del mando con vibración del equipo</string>
@@ -244,7 +241,7 @@
<string name="title_disable_frame_drop">Nunca disminuir cuadros</string>
<string name="summary_disable_frame_drop">Puede reducir micro-tartamudeos (Stuttering) en algunos dispositivos , pero puede incrementar latencia</string>
<string name="title_enable_hdr">Activar HDR (Alto Rango Dinámico / Experimental)</string>
<string name="summary_enable_hdr">Transmitir HDR (Alto Rango Dinámico) cuando el juego, el PC y la Tarjeta de Video (GPU) lo soporten. HDR requiere de una Tarjeta de Video de la serie GTX 1000 o superior.</string>
<string name="summary_enable_hdr">Transmite en HDR cuando el juego y la GPU del PC lo admitan. HDR requiere una GPU compatible con la codificación HEVC Main 10.</string>
<string name="summary_enable_perf_overlay">Mostrar en tiempo real la información del desempeño de la transmisión mientras está activa la misma</string>
<string name="title_enable_post_stream_toast">Mostrar mensajes sobre latencia mientras se transmite</string>
<string name="category_help">Ayuda</string>
@@ -256,4 +253,29 @@
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="title_frame_pacing">Ritmo de cuadros por segundo en video</string>
<string name="resolution_prefix_native_portrait">(Retrato)</string>
<string name="frame_conversion_error">El PC anfitrión ha reportado un error fatal en el codificador de video.
\n
\nIntenta deshabilitar el modo HDR, cambiar la resolución de la transmisión, o cambiar la resolución de pantalla del PC anfitrión.</string>
<string name="resolution_prefix_native_landscape">(Panorama)</string>
<string name="summary_checkbox_reduce_refresh_rate">Tasa de refresco menores pueden ahorrar energía a cambio de una mayor latencia de video</string>
<string name="title_checkbox_reduce_refresh_rate">Permitir reducción de la tasa de refresco</string>
<string name="title_full_range">Forzar video de rango completo (Experimental)</string>
<string name="summary_full_range">Esto provocará la pérdida de detalles en las áreas claras y oscuras si su dispositivo no muestra correctamente el contenido de video de rango completo.</string>
<string name="pair_pairing_help">Si el hostal del ordenador ejecuta Sunshine, navegue a la interfaz de usuario web de Sunshine para ingresar el PIN.</string>
<string name="pcview_menu_eol">Fin de servicio de NVIDIA GameStream</string>
<string name="fps_suffix_fps">FPS</string>
<string name="title_native_fps_dialog">Advertencia sobre FPS nativos</string>
<string name="category_gamepad_settings">Ajustes del Gamepad</string>
<string name="title_checkbox_gamepad_motion_sensors">Permitir el uso de los sensores de movimiento del gamepad</string>
<string name="videoformat_av1always">Preferir AV1 (Experimental)</string>
<string name="videoformat_h264always">Prefiero H.264</string>
<string name="perf_overlay_hostprocessinglatency">Latencia de procesamiento del host mín/máx/promedio: %1$.1f/%2$.1f/%3$.1f ms</string>
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Fuerza la entrada del touchpad del gamepad para controlar el ratón del host, incluso cuando se emula un gamepad con touchpad.</string>
<string name="title_checkbox_gamepad_touchpad_as_mouse">Controla siempre el ratón con el touchpad</string>
<string name="summary_checkbox_gamepad_motion_sensors">Permite a los hosts compatibles solicitar datos de los sensores de movimiento al emular un gamepad con los sensores de movimiento. La desactivación puede reducir ligeramente el consumo de energía y el uso de la red si los sensores de movimiento no se utilizan en el juego.</string>
<string name="toast_controller_type_changed">El tipo del Gamepad puede cambiar debido a la emulación del sensor de movimiento</string>
<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>
<string name="title_checkbox_gamepad_motion_fallback">Emular el sensor de movimiento del gamepad</string>
</resources>
+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<resources></resources>
+41 -22
View File
@@ -18,7 +18,7 @@
<string name="pcview_menu_details">Voir les détails</string>
<!-- Network test strings -->
<string name="nettest_title_waiting">Test de la connexion réseau</string>
<string name="nettest_text_waiting">Moonlight teste votre connexion réseau pour déterminer si NVIDIA GameStream est bloqué.
<string name="nettest_text_waiting">Moonlight teste votre connexion réseau pour déterminer si les ports requis sont bloqués.
\n
\nCela peut prendre quelques secondes…</string>
<string name="nettest_title_done">Test du réseau terminé</string>
@@ -40,7 +40,7 @@
<string name="pair_already_in_progress">Appariement déjà en cours</string>
<!-- WOL messages -->
<string name="wol_pc_online">L\'ordinateur est en ligne</string>
<string name="wol_no_mac">Impossible de réveiller le PC car GFE n\'a pas envoyé d\'adresse MAC</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_msg">Votre PC peut prendre quelques secondes pour se réveiller.
Si ce n\'est pas le cas, assurez-vous qu\'il est correctement configuré pour Wake-On-LAN.
@@ -59,7 +59,7 @@
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>
<string name="title_decoding_error">Le décodeur vidéo s\'est écrasé</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. Assurez-vous que GeForce Experience soit mis à jour vers la dernière version sur votre PC. Essayez de régler les paramètres de diffusion si les plantages continuent.</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="title_decoding_reset">Paramètres vidéo réinitialiser</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="error_usb_prohibited">L\'accès USB est interdit par votre appareil. Vérifiez vos paramètres Knox ou MDM.</string>
@@ -77,9 +77,10 @@
<string name="conn_terminated_title">Connexion terminée</string>
<string name="conn_terminated_msg">La connexion a été interrompue</string>
<!-- General strings -->
<string name="ip_hint">Adresse IP de GeForce PC</string>
<string name="searching_pc">Recherche de PC avec GameStream en cours…\n\n
Assurez-vous que GameStream est activé dans les paramètres GeForce Experience SHIELD.</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…
\n
\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="no">Non</string>
<string name="lost_connection">Perte de connexion avec le PC</string>
@@ -125,8 +126,8 @@
<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="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="title_seekbar_bitrate">Sélectionnez le bitrate vidéo à obtenir</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="title_seekbar_bitrate">Bitrate vidéo</string>
<string name="summary_seekbar_bitrate">Augmentez-le pour une meilleure qualité dimage. 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_disable_warnings">Désactiver les messages d\'avertissement</string>
<string name="title_checkbox_enable_pip">Activer le mode observateur dans l\'image</string>
@@ -137,7 +138,7 @@
<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="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="title_checkbox_multi_controller">Prise en charge de plusieurs contrôleurs</string>
<string name="title_checkbox_multi_controller">Forcer la présence d\'un contrôleur</string>
<string name="summary_checkbox_multi_controller">Lorsqu\'elle n\'est pas cochée, tous les contrôleurs sont regroupés</string>
<string name="title_checkbox_vibrate_fallback">Emuler support vibration de secours</string>
<string name="summary_checkbox_vibrate_fallback">Emuler des tremblements si votre manette ne le prend pas en charge</string>
@@ -185,10 +186,10 @@
<string name="summary_checkbox_disable_warnings">Désactiver les messages d\'avertissement de connexion à l\'écran pendant la diffusion</string>
<string name="title_disable_frame_drop">Ne jamais laisser tomber les frames</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 HEVC</string>
<string name="summary_video_format">HEVC réduit les besoins en bande passante vidéo mais nécessite un périphérique très récent</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="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. HDR nécessite un GPU série GTX 1000 ou une version ultérieure.</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="title_enable_perf_overlay">Activer la superposition de performance</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="title_enable_post_stream_toast">Afficher le message de latence après la diffusion en continu</string>
@@ -201,21 +202,19 @@
<string name="pcview_menu_header_online">En ligne</string>
<string name="resolution_prefix_native">Native</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="text_native_res_dialog">Les modes de résolution native ne sont pas officiellement supportées par GeForce Experience, l\'écran de votre hôte ne changera donc pas sa résolution. Vous devrez changer la résolution de chaque jeu dans les paramètres de celui-ci.
<string name="text_native_res_dialog">La résolution native et/ou le FPS peuvent ne pas être pris en charge par le serveur de streaming. Vous devrez probablement configurer manuellement un mode d\'affichage personnalisé correspondant pour le PC hôte.
\n
\nSi vous créez une résolution personnalisée dans le panneau de contrôle NVIDIA identique à celle de votre appareil, gardez à l\'esprit les avertissement de NVIDIA en ce qui est des potentiels dégâts à votre moniteur, une instabilité générale, et encore d\'autres problèmes.
\nSi vous choisissez de créer une résolution personnalisée dans le panneau de configuration NVIDIA pour correspondre aux paramètres de votre écran, assurez-vous d\'avoir lu et compris l\'avertissement de NVIDIA concernant les dommages possibles au moniteur, l\'instabilité du PC et d\'autres problèmes potentiels.
\n
\nNous ne sommes pas responsables des problèmes qui peuvent arriver suite à l\'utilisation de cette fonctionnalité.
\nNous ne sommes pas responsables des problèmes résultant de la création d\'une résolution personnalisée sur votre PC.
\n
\nEnfin, votre appareil et/ou vôtre PC hôte peut ne pas supporter cette fonctionnalité. Si ça ne marche pas, on ne peut malheureusement rien y faire.</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="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="early_termination_error">Quelque chose s\'est mal passé sur votre PC hôte en démarrant le flux.
\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.
\n
\nSi le problème persiste, essayez de réinstaller les pilotes de votre GPU ainsi que GeForce Experience.</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="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>
@@ -228,9 +227,8 @@
<string name="audioconf_stereo">Stéréo</string>
<string name="audioconf_51surround">Son surround 5.1</string>
<string name="audioconf_71surround">Son surround 7.1</string>
<string name="videoformat_hevcauto">Automatique</string>
<string name="videoformat_hevcalways">Utilisez toujours HEVC (mais il peut planter)</string>
<string name="videoformat_hevcnever">N\'utilisez jamais HEVC</string>
<string name="videoformat_auto">Automatique (recommandé)</string>
<string name="videoformat_hevcalways">Préférez le HEVC</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="pacing_latency">Préférer une latence plus faible</string>
@@ -259,4 +257,25 @@
<string name="summary_checkbox_reduce_refresh_rate">Des taux de rafraîchissement d\'affichage plus bas peuvent économiser de l\'énergie au détriment d\'une latence vidéo plus importante</string>
<string name="summary_checkbox_enable_audiofx">Permet aux effets audio de fonctionner lors du streaming, mais peut augmenter la latence</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.
\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>
<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="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="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="fps_suffix_fps">FPS</string>
<string name="title_native_fps_dialog">Avertissement FPS natif</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_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="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_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="toast_controller_type_changed">Le type de manette peut être modifié en raison de 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.
\nRemarque : l\'activation de cette option peut faire apparaître votre manette de jeu comme une manette PlayStation du côté hôte.</string>
<string name="title_checkbox_gamepad_motion_fallback">Émuler les capteurs de mouvement de la manette</string>
</resources>
+69 -17
View File
@@ -4,10 +4,10 @@
<string name="title_enable_post_stream_toast">A késleltetési üzenet megjelenítése streaming után</string>
<string name="summary_enable_perf_overlay">Valós idejű adatfolyam-adat megjelenítése streaming közben</string>
<string name="title_enable_perf_overlay">Teljesítmény statisztikák megjelenítése közvetítés közben</string>
<string name="summary_enable_hdr">Streaming HDR, amikor a játék és a PC GPU támogatja. A HDR-hez GTX 1000 sorozatú vagy újabb verzió szükséges.</string>
<string name="summary_enable_hdr">HDR streamelés, ha a játék és a PC GPU támogatja. A HDR-hez HEVC Main 10 kódolási támogatással rendelkező GPU szükséges.</string>
<string name="title_enable_hdr">HDR engedélyezése (kísérleti)</string>
<string name="summary_video_format">A HEVC csökkenti a video sávszélesség követelményeit, de újabb eszközt igényel</string>
<string name="title_video_format">Módosítsa a HEVC beállításait</string>
<string name="summary_video_format">Az újabb kodekek csökkenthetik a videó sávszélességigényét, ha a készülék támogatja őket. A codec-kiválasztások figyelmen kívül hagyhatók, ha a gazdaszoftver vagy a GPU nem támogatja őket.</string>
<string name="title_video_format">Módosítsa a Kodek beállításait</string>
<string name="summary_disable_frame_drop">Csökkentheti a mikrodadogást egyes eszközökön, de növelheti a késést</string>
<string name="title_disable_frame_drop">Soha ne ejtse le a kereteket</string>
<string name="summary_checkbox_disable_warnings">Streaming közben tiltsa le a képernyőn megjelenő csatlakozási figyelmeztető üzeneteket</string>
@@ -72,13 +72,13 @@
<string name="title_seekbar_bitrate">Videó bitráta</string>
<string name="summary_fps_list">Növelje a gördülékenyebb videofolyamot. Csökkenjen a jobb teljesítmény érdekében az alsó kategóriás eszközökön.</string>
<string name="title_fps_list">Videó képkockasebessége</string>
<string name="text_native_res_dialog">A natív felbontási módokat a GeForce Experience hivatalosan nem támogatja, így maga nem állítja be a gazdagép kijelzőjének felbontását. A játék során manuálisan kell beállítania.
<string name="text_native_res_dialog">Előfordulhat, hogy a streaming szerver nem támogatja a natív felbontást és/vagy FPS-t. Valószínűleg kézzel kell beállítania egy megfelelő egyéni megjelenítési módot a fogadó számítógépen.
\n
\nHa úgy dönt, hogy az NVIDIA vezérlőpultján egyedi felbontást hoz létre, hogy megfeleljen az eszköz felbontásának, kérjük, olvassa el és értette az NVIDIA figyelmeztetéseit a monitor esetleges károsodásával, a számítógép instabilitásával és más lehetséges problémákkal kapcsolatban.
\nHa úgy dönt, hogy egyéni felbontást hoz létre az NVIDIA Vezérlőpultban a képernyő beállításainak megfelelően, kérjük, győződjön meg róla, hogy elolvasta és megértette az NVIDIA figyelmeztetését a monitor lehetséges károsodására, a számítógép instabilitására és más lehetséges problémákra vonatkozóan.
\n
\nNem vagyunk felelősek a PC-n egyedi felbontás létrehozásából eredő problémákért.
\nNem vállalunk felelősséget a számítógépén egyéni felbontás létrehozásából eredő problémákért.
\n
\nVégül előfordulhat, hogy az eszköz vagy a fogadó PC nem támogatja a natív felbontású adatfolyamot. Ha a készülékén nem működik, sajnos csak nincs szerencséje.</string>
\nElőfordulhat, hogy az Ön monitora nem támogatja a szükséges kijelzőkonfigurációt. Ebben az esetben megpróbálhat egy virtuális monitort beállítani. Végül, ha a készülék vagy a gazdaszámítógép nem támogatja a streaminget egy adott felbontáson vagy frissítési frekvencián, akkor sajnos nincs szerencséje.</string>
<string name="title_native_res_dialog">Natív felbontás figyelmeztetés</string>
<string name="summary_resolution_list">Növelje a kép tisztaságának növelése érdekében. Csökkenjen a jobb teljesítmény érdekében az alsó kategóriás eszközökön és a lassabb hálózatokon.</string>
<string name="title_resolution_list">Videó felbontás</string>
@@ -124,10 +124,10 @@
<string name="lost_connection">Megszakadt a kapcsolat a PC-vel</string>
<string name="no">Nem</string>
<string name="yes">Igen</string>
<string name="searching_pc">PC-k keresése futó GameStream segítségével ...
<string name="searching_pc">A helyi hálózaton lévő PC-k keresése...
\n
\n Győződjön meg arról, hogy a GameStream engedélyezve van a GeForce Experience SHIELD beállításaiban.</string>
<string name="ip_hint">A GeForce PC IP-címe</string>
\nGyőződj meg róla, hogy a Sunshine fut a gazdaszámítógépen, vagy a GameStream engedélyezve van a GeForce Experience SHIELD beállításaiban.</string>
<string name="ip_hint">A számítógép IP-címe</string>
<string name="conn_terminated_msg">A kapcsolat megszakadt</string>
<string name="conn_terminated_title">A kapcsolat megszűnt</string>
<string name="conn_error_msg">Nem sikerült elindítani</string>
@@ -139,9 +139,7 @@
<string name="check_ports_msg">Ellenőrizze a tűzfal és a port-továbbítási szabályokat a port(ok)ra vonatkozóan:</string>
<string name="early_termination_error">Valami nem sikerült a fogadó PC-n az adatfolyam indításakor.
\n
\nGyőződjön meg arról, hogy a fogadó PC-n nincs megnyitva DRM-védett tartalom. Megpróbálhatja újraindítani a gazdagépet is.
\n
\nHa a probléma továbbra is fennáll, próbálja meg újratelepíteni a GPU illesztőprogramokat és a GeForce Experience szoftvert.</string>
\nGyőződjön meg arról, hogy a fogadó PC-n nincs megnyitva DRM-védett tartalom. Megpróbálhatja újraindítani a gazdagépet is.</string>
<string name="no_frame_received_error">A hálózati kapcsolat nem működik megfelelően. Csökkentse a videó bitráta beállítását, vagy próbálkozzon gyorsabb kapcsolattal.</string>
<string name="no_video_received_error">Nem kapott videót a gazdagéptől.</string>
<string name="video_decoder_init_failed">A videó dekóder inicializálása nem sikerült. Előfordulhat, hogy készüléke nem támogatja a kiválasztott felbontást vagy képkockasebességet.</string>
@@ -149,7 +147,7 @@
<string name="error_usb_prohibited">Az USB-hozzáférést az eszköz rendszergazdája tiltja. Ellenőrizze a Knox vagy az MDM beállításait.</string>
<string name="message_decoding_reset">Az eszköz videodekóderje továbbra is összeomlik a kiválasztott adatfolyam-beállításoknál. A streaming beállításait visszaállította az alapértelmezettre.</string>
<string name="title_decoding_reset">Videó Beállítások Alapra</string>
<string name="message_decoding_error">A Moonlight összeomlott, mert inkompatibilis volt az eszköz videó dekóderével. Győződjön meg arról, hogy a GeForce Experience frissítve van a számítógép legújabb verziójára. Próbálja meg módosítani a streaming beállításokat, ha az összeomlások továbbra is fennállnak.</string>
<string name="message_decoding_error">A Moonlight összeomlott az eszköz videódekóderével való inkompatibilitás miatt. Próbálja meg módosítani a streaming-beállításokat, ha az összeomlások továbbra is fennállnak.</string>
<string name="title_decoding_error">A videó dekóder összeomlott</string>
<string name="error_404">A GFE HTTP 404 hibát adott vissza. Győződjön meg arról, hogy a számítógépen támogatott GPU fut. A távoli asztali szoftver használata szintén ezt a hibát okozhatja. Próbálja újraindítani a gépet, vagy telepítse újra a GFE-t.</string>
<string name="conn_error_title">Csatlakozási hiba</string>
@@ -165,7 +163,7 @@
<string name="wol_fail">Nem sikerült elküldeni a Wake-On-LAN csomagokat</string>
<string name="wol_waking_msg">Néhány másodpercbe telhet, mire a számítógép felébred. Ha nem, ellenőrizze, hogy megfelelően van-e konfigurálva a Wake-On-LAN számára.</string>
<string name="wol_waking_pc">PC elindítása…</string>
<string name="wol_no_mac">Nem lehet elindítani a PC-t, mert a GFE nem küldött MAC-címet</string>
<string name="wol_no_mac">Nem lehet felébreszteni a számítógépet, mert nincs tárolt MAC-cím</string>
<string name="wol_pc_online">A számítógép elérhető</string>
<string name="pair_already_in_progress">A párosítás már folyamatban van</string>
<string name="pairing">Párosítás…</string>
@@ -185,9 +183,9 @@
\n
\nHa az interneten keresztül kíván közvetíteni, telepítse a Moonlight Internet Hosting Tool alkalmazást a számítógépére, és futtassa a mellékelt Internet Streaming Tester szoftvert a számítógép internetkapcsolatának ellenőrzéséhez.</string>
<string name="nettest_title_done">Hálózati kapcsolat teszt kész</string>
<string name="nettest_text_waiting">A Moonlight a hálózati kapcsolatot teszteli annak megállapítására, hogy az NVIDIA GameStream blokkolva van-e.
<string name="nettest_text_waiting">A Moonlight teszteli a hálózati kapcsolatot, hogy megállapítsa, nem blokkoltak-e szükséges portokat.
\n
\nEz eltarthat néhány másodpercig …</string>
\nEz néhány másodpercig eltarthat</string>
<string name="pcview_menu_test_network">Hálózati kapcsolat teszt</string>
<string name="nettest_title_waiting">Hálózati kapcsolat ellenőrzése</string>
<string name="pcview_menu_details">Részletek megtekintése</string>
@@ -207,4 +205,58 @@
<string name="scut_not_paired">PC nincs csatlakoztatva</string>
<string name="scut_deleted_pc">PC eltávolítva</string>
<string name="resolution_prefix_native_fullscreen">Natív teljes képernyős</string>
<string name="summary_setup_guide">Útmutató a játék-PC streamingre való beállításához</string>
<string name="title_troubleshooting">Hibaelhárítási útmutató</string>
<string name="title_checkbox_reduce_refresh_rate">A frissítési sebesség csökkentésének engedélyezése</string>
<string name="summary_frame_pacing">A videók késleltetésének és simaságának egyensúlyának megadása</string>
<string name="title_checkbox_enable_audiofx">Rendszeres kiegyenlítő támogatás engedélyezése</string>
<string name="resolution_360p">360p</string>
<string name="title_native_fps_dialog">Natív FPS figyelmeztetés</string>
<string name="pacing_balanced">Kiegyensúlyozott</string>
<string name="summary_full_range">Ez részletvesztést okoz a világos és sötét területeken, ha a készülék nem jeleníti meg megfelelően a teljes tartományú videotartalmat.</string>
<string name="summary_privacy_policy">A Moonlight adatvédelmi szabályzatának megtekintése</string>
<string name="resolution_4k">4K</string>
<string name="pacing_smoothness">A legsimább videó előnyben részesítése (jelentősen növelheti a késleltetést)</string>
<string name="fps_120">120 FPS</string>
<string name="category_help">Segítség</string>
<string name="videoformat_av1always">AV1 előnyben részesítése (kísérleti)</string>
<string name="audioconf_71surround">7.1 Térhatású hangzás</string>
<string name="pcview_menu_eol">NVIDIA GameStream szolgáltatás vége</string>
<string name="title_checkbox_gamepad_motion_sensors">Gamepad mozgásérzékelők használatának engedélyezése</string>
<string name="resolution_720p">720p</string>
<string name="videoformat_auto">Automatikus (ajánlott)</string>
<string name="pacing_balanced_alt">Kiegyensúlyozott FPS-korlátozással</string>
<string name="frame_conversion_error">A fogadó számítógép végzetes videokódolási hibát jelentett.
\n
\nPróbálja meg letiltani a HDR módot, megváltoztatni a streaming felbontást, vagy megváltoztatni a host PC kijelzőjének felbontását.</string>
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Kényszeríti a gamepad touchpad bevitelét a host egér vezérlésére, még akkor is, ha egy touchpaddal ellátott gamepadot emulál.</string>
<string name="title_frame_pacing">Videó képkocka ütemezése</string>
<string name="resolution_1440p">1440p</string>
<string name="resolution_480p">480p</string>
<string name="videoformat_hevcalways">HEVC előnyben részesítése</string>
<string name="fps_60">60 FPS</string>
<string name="audioconf_51surround">5.1 Térhatású hangzás</string>
<string name="summary_checkbox_enable_audiofx">Lehetővé teszi az audioeffektek működését streaming közben, de növelheti a hang késleltetését</string>
<string name="fps_90">90 FPS</string>
<string name="summary_checkbox_gamepad_motion_sensors">Lehetővé teszi a támogatott hosztok számára, hogy mozgásérzékelős adatokat kérjenek, amikor mozgásérzékelőkkel ellátott gamepadot emulálnak. A letiltás némileg csökkentheti az energia- és hálózathasználatot, ha a játékban nem használnak mozgásérzékelőket.</string>
<string name="resolution_1080p">1080p</string>
<string name="summary_seekbar_deadzone">Megjegyzés: Egyes játékok nagyobb holtteret kényszeríthetnek ki, mint amire a Moonlight be van állítva.</string>
<string name="audioconf_stereo">Sztereó</string>
<string name="videoformat_h264always">Inkább H.264</string>
<string name="title_privacy_policy">Adatvédelmi irányelvek</string>
<string name="fps_suffix_fps">FPS</string>
<string name="category_gamepad_settings">Gamepad beállítások</string>
<string name="fps_30">30 FPS</string>
<string name="summary_troubleshooting">Tippek a gyakori streaming problémák diagnosztizálásához és javításához</string>
<string name="title_checkbox_absolute_mouse_mode">Távoli asztali egér mód</string>
<string name="title_full_range">Teljeskörű videó erőltetése (kísérleti)</string>
<string name="summary_checkbox_reduce_refresh_rate">Az alacsonyabb kijelzőfrissítési frekvencia energiát takaríthat meg némi további videokésleltetés árán</string>
<string name="resolution_prefix_native_portrait">(Portré)</string>
<string name="summary_checkbox_absolute_mouse_mode">Ezáltal az egérgyorsítás természetesebben viselkedik a távoli asztali használat során, de sok játékkal nem kompatibilis.</string>
<string name="pair_pairing_help">Ha a számítógépen Sunshine fut, lépj a Sunshine webes felhasználói felületére a PIN-kód megadásához.</string>
<string name="title_setup_guide">Telepítési útmutató</string>
<string name="title_checkbox_gamepad_touchpad_as_mouse">Az egeret mindig az érintőpaddal vezérelje</string>
<string name="resolution_prefix_native_landscape">(Tájkép)</string>
<string name="perf_overlay_hostprocessinglatency">Host feldolgozási késleltetés min/max/átlag: %1$.1f/%2$.1f/%3$.1f ms</string>
<string name="pacing_latency">A legalacsonyabb késleltetés előnyben részesítése</string>
</resources>
+119 -1
View File
@@ -14,7 +14,7 @@
<string name="pcview_menu_send_wol">Kirim permintaan Wake-On-LAN</string>
<string name="pcview_menu_delete_pc">Hapus komputer</string>
<string name="nettest_title_waiting">Menguji koneksi jaringan</string>
<string name="nettest_text_waiting">Moonlight sedang menguji koneksi jaringan untuk mencari tahu apakah NVIDIA GameStream diblokir.
<string name="nettest_text_waiting">Moonlight sedang menguji koneksi jaringan untuk mencari tahu apakah jalur diblokir.
\n
\nIni mungkin membutuhkan beberapa saat…</string>
<string name="nettest_text_inconclusive">Uji koneksi jaringan tidak dapat dilakukan karena tidak ada server pengujian Moonlight yang bisa dijangkau. Cek koneksi Internet Anda atau coba lagi nanti.</string>
@@ -93,4 +93,122 @@
\n
\nJika masalah berkelanjutan, coba install ulang GeForce Experience dan driver video grafis Anda.</string>
<string name="help">Bantuan</string>
<string name="pcview_menu_eol">NVIDIA GameStream End-of-Service</string>
<string name="applist_menu_resume">Lanjutkan Sesi</string>
<string name="applist_menu_quit_and_start">Keluar dari Game Saat Ini dan Mulai</string>
<string name="applist_menu_quit">Keluar dari Sesi</string>
<string name="applist_quit_confirmation">Anda yakin ingin keluar dari aplikasi yang sedang berjalan\? Semua data yang belum disimpan akan hilang.</string>
<string name="applist_details_id">ID Aplikasi:</string>
<string name="addpc_wrong_sitelocal">Alamat itu sepertinya salah. Anda harus menggunakan alamat IP publik perute untuk streaming melalui Internet.</string>
<string name="category_basic_settings">Pengaturan dasar</string>
<string name="title_fps_list">Kecepatan bingkai video</string>
<string name="summary_fps_list">Tingkatkan untuk streaming video yang lebih lancar. Turunkan untuk kinerja yang lebih baik pada perangkat kelas bawah.</string>
<string name="title_seekbar_bitrate">Kecepatan bit video</string>
<string name="summary_seekbar_bitrate">Tingkatkan untuk kualitas gambar yang lebih baik. Kurangi untuk meningkatkan kinerja pada koneksi yang lebih lambat.</string>
<string name="title_checkbox_flip_face_buttons">Balikkan tombol wajah</string>
<string name="summary_checkbox_flip_face_buttons">Mengalihkan tombol wajah A/B dan X/Y untuk gamepad dan kontrol di layar</string>
<string name="title_only_l3r3">Hanya tampilkan L3 dan R3</string>
<string name="dialog_title_reset_osc">Atur Ulang Tata Letak</string>
<string name="dialog_text_reset_osc">Yakin ingin menghapus tata letak kontrol di layar yang tersimpan\?</string>
<string name="toast_reset_osc_success">Kontrol di layar diatur ulang ke default</string>
<string name="resolution_prefix_native_landscape">(Lanskap)</string>
<string name="resolution_prefix_native_portrait">(Potret)</string>
<string name="summary_checkbox_enable_audiofx">Mengizinkan efek audio berfungsi saat streaming, tetapi dapat meningkatkan latensi audio</string>
<string name="category_input_settings">Pengaturan Masukan</string>
<string name="title_checkbox_touchscreen_trackpad">Gunakan layar sentuh sebagai trackpad</string>
<string name="title_checkbox_vibrate_fallback">Meniru dukungan gemuruh dengan getaran</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="summary_checkbox_absolute_mouse_mode">Ini dapat membuat akselerasi mouse berperilaku lebih alami untuk penggunaan desktop jarak jauh, tetapi tidak kompatibel dengan banyak game.</string>
<string name="category_on_screen_controls_settings">Pengaturan Kontrol di Layar</string>
<string name="title_checkbox_show_onscreen_controls">Tampilkan kontrol di layar</string>
<string name="summary_checkbox_small_icon_mode">Seni kotak yang lebih kecil di kisi aplikasi memungkinkan lebih banyak aplikasi terlihat di layar</string>
<string name="title_checkbox_host_audio">Putar audio di PC</string>
<string name="title_checkbox_enable_sops">Optimalkan pengaturan game</string>
<string name="title_checkbox_disable_warnings">Nonaktifkan pesan peringatan</string>
<string name="summary_checkbox_disable_warnings">Nonaktifkan pesan peringatan koneksi di layar saat streaming</string>
<string name="error_unknown_host">Gagal menyelesaikan host</string>
<string name="perf_overlay_dectime">Waktu decoding rata-rata: %1$.2f ms</string>
<string name="category_host_settings">Pengaturan tuan rumah</string>
<string name="frame_conversion_error">PC host melaporkan kesalahan penyandian video yang fatal.
\n
\nCoba nonaktifkan mode HDR, ubah resolusi streaming, atau ubah resolusi tampilan PC host Anda.</string>
<string name="applist_menu_cancel">Membatalkan</string>
<string name="applist_menu_details">Melihat rincian</string>
<string name="applist_menu_scut">Buat Pintasan</string>
<string name="applist_menu_hide_app">Sembunyikan Aplikasi</string>
<string name="applist_refresh_title">Daftar Aplikasi</string>
<string name="applist_refresh_msg">Menyegarkan aplikasi…</string>
<string name="applist_quit_fail">Gagal untuk keluar</string>
<string name="title_add_pc">Tambahkan PC Secara Manual</string>
<string name="msg_add_pc">Menghubungkan ke PC…</string>
<string name="addpc_fail">Tidak dapat terhubung ke komputer yang ditentukan. Pastikan port yang diperlukan diizinkan melalui firewall.</string>
<string name="addpc_success">Berhasil menambahkan komputer</string>
<string name="addpc_enter_ip">Anda harus memasukkan alamat IP</string>
<string name="title_resolution_list">Resolusi video</string>
<string name="summary_resolution_list">Tingkatkan untuk meningkatkan kejernihan gambar. Turunkan untuk kinerja yang lebih baik pada perangkat kelas bawah dan jaringan yang lebih lambat.</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="title_checkbox_stretch_video">Regangkan video ke layar penuh</string>
<string name="resolution_prefix_native">Asli</string>
<string name="resolution_prefix_native_fullscreen">Layar Penuh Asli</string>
<string name="category_audio_settings">Pengaturan Audio</string>
<string name="title_audio_config_list">Konfigurasi suara surround</string>
<string name="title_checkbox_enable_audiofx">Aktifkan dukungan equalizer sistem</string>
<string name="summary_checkbox_touchscreen_trackpad">Jika diaktifkan, layar sentuh berfungsi seperti trackpad. Jika dinonaktifkan, layar sentuh langsung mengontrol kursor mouse.</string>
<string name="title_checkbox_multi_controller">Deteksi kehadiran gamepad otomatis</string>
<string name="summary_checkbox_multi_controller">Menghapus centang opsi ini memaksa gamepad untuk selalu ada</string>
<string name="summary_checkbox_vibrate_fallback">Getarkan perangkat Anda untuk meniru gemuruh jika gamepad Anda tidak mendukungnya</string>
<string name="title_seekbar_deadzone">Sesuaikan zona mati stik analog</string>
<string name="title_checkbox_xb1_driver">Xbox 360/Satu driver gamepad USB</string>
<string name="summary_checkbox_xb1_driver">Mengaktifkan driver USB bawaan untuk perangkat tanpa dukungan pengontrol Xbox asli</string>
<string name="title_checkbox_usb_bind_all">Ganti dukungan gamepad Xbox asli</string>
<string name="summary_checkbox_usb_bind_all">Gunakan driver USB Moonlight untuk semua gamepad yang didukung, meskipun ada dukungan pengontrol Xbox asli</string>
<string name="title_checkbox_mouse_nav_buttons">Aktifkan tombol mouse mundur dan maju</string>
<string name="title_checkbox_absolute_mouse_mode">Mode mouse desktop jarak jauh</string>
<string name="summary_checkbox_show_onscreen_controls">Tampilkan hamparan pengontrol virtual di layar sentuh</string>
<string name="title_checkbox_vibrate_osc">Aktifkan getaran</string>
<string name="summary_checkbox_vibrate_osc">Getarkan perangkat Anda untuk meniru gemuruh untuk kontrol di layar</string>
<string name="summary_only_l3r3">Sembunyikan semua tombol virtual kecuali L3 dan R3</string>
<string name="summary_reset_osc">Menyetel ulang semua kontrol di layar ke ukuran dan posisi default</string>
<string name="title_osc_opacity">Ubah opasitas kontrol di layar</string>
<string name="summary_osc_opacity">Jadikan kontrol di layar lebih/kurang transparan</string>
<string name="dialog_title_osc_opacity">Ubah opasitas</string>
<string name="suffix_osc_opacity">%</string>
<string name="category_ui_settings">Pengaturan UI</string>
<string name="summary_checkbox_enable_pip">Mengizinkan streaming untuk dilihat (tetapi tidak dikontrol) saat melakukan banyak tugas</string>
<string name="title_language_list">Bahasa</string>
<string name="title_checkbox_small_icon_mode">Gunakan seni kotak kecil</string>
<string name="summary_checkbox_host_audio">Putar audio dari komputer dan perangkat ini</string>
<string name="category_advanced_settings">Pengaturan lanjutan</string>
<string name="title_unlock_fps">Buka kunci semua frekuensi gambar yang memungkinkan</string>
<string name="summary_unlock_fps">Streaming pada 90 atau 120 FPS dapat mengurangi latensi pada perangkat kelas atas, tetapi dapat menyebabkan kelambatan atau ketidakstabilan pada perangkat yang tidak dapat mendukungnya</string>
<string name="title_checkbox_reduce_refresh_rate">Izinkan pengurangan kecepatan penyegaran</string>
<string name="summary_checkbox_reduce_refresh_rate">Kecepatan refresh tampilan yang lebih rendah dapat menghemat daya dengan mengorbankan beberapa latensi video tambahan</string>
<string name="applist_refresh_error_title">Kesalahan</string>
<string name="pair_pairing_help">Jika PC host Anda menjalankan Sunshine, buka UI web Sunshine untuk memasukkan PIN.</string>
<string name="applist_quit_app">Berhenti</string>
<string name="perf_overlay_renderingfps">Frekuensi gambar rendering: %1$.2f FPS</string>
<string name="perf_overlay_netlatency">Rata-rata latensi jaringan: %1$d ms (variasi: %2$d ms)</string>
<string name="perf_overlay_netdrops">Bingkai hilang oleh koneksi jaringan Anda: %1$.2f%%</string>
<string name="applist_connect_msg">Menghubungkan ke PC…</string>
<string name="applist_menu_tv_channel">Tambahkan ke Saluran</string>
<string name="applist_refresh_error_msg">Gagal mendapatkan daftar aplikasi</string>
<string name="applist_quit_success">Berhasil keluar</string>
<string name="addpc_unknown_host">Tidak dapat menyelesaikan alamat PC. Pastikan Anda tidak salah ketik di alamat.</string>
<string name="title_native_res_dialog">Peringatan Resolusi Asli</string>
<string name="text_native_res_dialog">Mode resolusi asli tidak didukung secara resmi oleh GeForce Experience, sehingga tidak akan mengatur sendiri resolusi tampilan host. Anda harus mengaturnya secara manual saat bermain.
\n
\nJika Anda memilih untuk membuat resolusi khusus di Panel Kontrol NVIDIA agar sesuai dengan resolusi perangkat Anda, pastikan Anda telah membaca dan memahami peringatan NVIDIA terkait kemungkinan kerusakan monitor, ketidakstabilan PC, dan potensi masalah lainnya.
\n
\nKami tidak bertanggung jawab atas masalah apa pun yang diakibatkan oleh pembuatan resolusi khusus pada PC Anda.
\n
\nTerakhir, perangkat atau PC host Anda mungkin tidak mendukung streaming pada resolusi asli. Jika tidak berfungsi pada perangkat Anda, sayangnya Anda kurang beruntung.</string>
<string name="summary_audio_config_list">Aktifkan suara surround 5.1 atau 7.1 untuk sistem home theater</string>
<string name="summary_seekbar_deadzone">Catatan: Beberapa game dapat menerapkan zona mati yang lebih besar daripada yang dikonfigurasi untuk digunakan oleh Moonlight.</string>
<string name="title_checkbox_mouse_emulation">Emulasi mouse melalui gamepad</string>
<string name="summary_checkbox_mouse_emulation">Menekan lama tombol Mulai akan mengalihkan gamepad ke mode mouse</string>
<string name="title_reset_osc">Hapus tata letak kontrol di layar yang disimpan</string>
<string name="summary_checkbox_mouse_nav_buttons">Mengaktifkan opsi ini dapat merusak klik kanan pada beberapa perangkat bermasalah</string>
<string name="title_checkbox_enable_pip">Aktifkan mode pengamat Gambar-dalam-Gambar</string>
<string name="summary_language_list">Bahasa yang digunakan untuk Moonlight</string>
<string name="summary_checkbox_enable_sops">Izinkan GFE mengubah setelan game untuk streaming yang optimal</string>
</resources>
+43 -18
View File
@@ -23,7 +23,7 @@
<string name="pair_already_in_progress">Accoppiamento già in corso</string>
<!-- WOL messages -->
<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_msg">Il PC potrebbe impiegare qualche secondo per risvegliarsi.
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="unpair_success">Disaccoppiato con successo</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 -->
<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>
@@ -60,8 +60,9 @@
<string name="conn_terminated_msg">La connessione è stata interrotta</string>
<!-- General strings -->
<string name="ip_hint">Indirizzo IP del PC</string>
<string name="searching_pc">Ricerca di PC con GameStream avviato…\n\n
Assicurati che GameStream sia abilitato nelle impostazioni SHIELD di GeForce Experience.</string>
<string name="searching_pc">Ricerca di PC nella rete locale…
\n
\n Assicurati che Sunshine sia avviato o che GameStream sia abilitato nelle impostazioni SHIELD di GeForce Experience.</string>
<string name="yes"></string>
<string name="no">No</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>
<!-- Preferences -->
<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="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>
@@ -133,10 +134,10 @@
<string name="category_advanced_settings">Impostazioni avanzate</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="title_video_format">Modifica impostazioni HEVC</string>
<string name="summary_video_format">HEVC riduce i requisiti di larghezza di banda video ma richiede un dispositivo molto recente</string>
<string name="title_video_format">Modifica impostazioni del codec</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="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="pcview_menu_header_online">Online</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_streamdetails">Flusso video: %1$s %2$.2f FPS</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
\nPotrebbero volerci alcuni secondi…</string>
<string name="nettest_title_done">Test della Rete Completato</string>
@@ -208,9 +209,8 @@
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">Surround 5.1</string>
<string name="audioconf_71surround">Surround 7.1</string>
<string name="videoformat_hevcauto">Automatico</string>
<string name="videoformat_hevcalways">Usa sempre HEVC (potrebbe essere instabile)</string>
<string name="videoformat_hevcnever">Non usare mai HEVC</string>
<string name="videoformat_auto">Automatico (Consigliato)</string>
<string name="videoformat_hevcalways">Preferisci HEVC</string>
<string name="title_frame_pacing">Bilanciamento frame video</string>
<string name="summary_frame_pacing">Specifica come bilanciare il ritardo video e la fluidità</string>
<string name="summary_enable_perf_overlay">Mostra informazioni real time sulla trasmissione</string>
@@ -227,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="early_termination_error">Qualcosa è andato storto sul PC sorgente mentre la trasmissione veniva avviata.
\n
\nAssicurati di non avere nessun contenuto protetto da DRM aperto sul PC sorgente. Puoi anche provare a spengere e riaccendere il PC sorgente.
\n
\nSe il problema persiste, prova a installare di nuovo i driver della scheda video e GeForce Experience.</string>
\nAssicurati di non avere nessun contenuto protetto da DRM aperto sul PC sorgente. Puoi anche provare a spengere e riaccendere il PC sorgente.</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="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
\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
\nNon saremo responsabili per qualsiasi problema risultante dalla creazione di una risoluzione personalizzata sul tuo PC.
\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_renderingfps">Frame rate renderizzato: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Frame scartati dalla tua connessione di rete: %1$.2f%%</string>
@@ -254,4 +252,31 @@
<string name="title_privacy_policy">Informativa sulla privacy</string>
<string name="summary_troubleshooting">Visualizza i suggerimenti per la diagnosi e la risoluzione dei problemi di streaming più comuni</string>
<string name="summary_privacy_policy">Visualizza l\'informativa sulla privacy di Moonlight</string>
<string name="frame_conversion_error">Il PC host ha segnalato un errore fatale di codifica video.
\n
\nProva a disabilitare la modalità HDR, modificare la risoluzione dello streaming o la risoluzione del display del tuo PC host.</string>
<string name="summary_checkbox_reduce_refresh_rate">Una minore frequenza di aggiornamento del display può risparmiare energia a scapito di una latenza video aggiuntiva</string>
<string name="resolution_prefix_native_landscape">(Panorama)</string>
<string name="resolution_prefix_native_portrait">(Ritratto)</string>
<string name="title_checkbox_enable_audiofx">Abilita il supporto per l\'equalizzatore di sistema</string>
<string name="summary_checkbox_enable_audiofx">Consente agli effetti audio di funzionare durante lo streaming, ma può aumentare la latenza audio</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="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>
+155
View File
@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="scut_deleted_pc">מחשב נמחק</string>
<string name="scut_not_paired">מחשב לא מצורף</string>
<string name="help_loading_msg">טוען עמוד עזרה…</string>
<string name="pcview_menu_header_online">פעיל</string>
<string name="pcview_menu_unpair_pc">הסר אימות</string>
<string name="pcview_menu_details">הראה פרטים</string>
<string name="nettest_text_waiting">מונלייט בודק את הרשת שלך ובודק אם ישנם פורטים הכרחיים חסומים
\n
\nהמתן כמה שניות…</string>
<string name="wol_no_mac">לא מצליח להעיר את המחשב, אין כתובת MAC</string>
<string name="scut_pc_not_found">מחשב לא נמצא</string>
<string name="help_loading_title">עזרה</string>
<string name="scut_invalid_uuid">המחשב אינו תואם</string>
<string name="scut_invalid_app_id">האפליקציה אינה מתאימה</string>
<string name="pcview_menu_header_offline">כבוי</string>
<string name="pcview_menu_header_unknown">מרענן</string>
<string name="pcview_menu_app_list">הראה את כל האפליקציות</string>
<string name="pcview_menu_pair_pc">אמת מחשב</string>
<string name="pcview_menu_send_wol">שלח פקודת \"Wake-On-LAN\"</string>
<string name="pcview_menu_delete_pc">מחק מחשב</string>
<string name="pcview_menu_test_network">בדוק חיבור רשת</string>
<string name="pcview_menu_eol">סוף פעילות שירות NVIDIA GameStream</string>
<string name="nettest_title_waiting">בודק חיבור רשת</string>
<string name="nettest_title_done">בדיקת רשת הושלמה</string>
<string name="nettest_text_inconclusive">בדיקת הרשת לא התבצעה בגלל שאין קישוריות לשרתי הבדיקה של מונלייט. בבקשה בדוק את החיבור לאינטרנט או נסה שוב מאוחר יותר.</string>
<string name="nettest_text_failure">גישה של מונלייט לרשת חסומה במכשיר הנוכחי. הזרמה על גבי האינטרנט לא יכוה לעבוד כל עוד מונלייט מחובר לרשת הנוכחית.
\n
\nהפורטים הבאים חסומים:
\n</string>
<string name="nettest_text_blocked">חיבור הרשת הנוכחי חוסם את מונלייט. הזרמה על גבי האינטרנט אינה אפשרית כל עוד מונלייט מחובר לרשת הנוכחית.</string>
<string name="pair_pc_offline">מחשב לא פעיל</string>
<string name="pair_pairing_title">מחבר</string>
<string name="pair_pairing_msg">אנא הזן את הקוד PIN הבא במחשב המארח:</string>
<string name="pair_pairing_help">אם המחשב המארח פועל על Sunshine, נווט אל דף הניהול על מנת להזין קוד PIN.</string>
<string name="pair_incorrect_pin">קוד PIN שגוי</string>
<string name="pair_fail">חיבור נכשל</string>
<string name="wol_pc_online">מחשב פעיל</string>
<string name="wol_fail">נכשל לשלוח פקודת Wake-On-LAN</string>
<string name="unpairing">מנתק חיבור…</string>
<string name="unpair_success">ניתוק הושלם</string>
<string name="unpair_fail">ניתוק נכשל</string>
<string name="unpair_error">המחשב לא חובר</string>
<string name="error_pc_offline">המחשב לא פעיל</string>
<string name="error_unknown_host">נכשל לאתר את המארח</string>
<string name="title_decoding_error">מפענח וידיאו קרס</string>
<string name="unable_to_pin_shortcut">האפליקציה אינה מרשה יצירת קיצורי דרך נעוצים.</string>
<string name="no_video_received_error">לא התקבל אות וידיאו מהמארח.</string>
<string name="conn_client_latency">מהירות פיענוח פריים ממוצעת:</string>
<string name="conn_error_title">שגיאת חיבור</string>
<string name="conn_terminated_msg">החיבור הופסק</string>
<string name="ip_hint">כתובת IP של המחשב המארח</string>
<string name="title_details">פרטים</string>
<string name="poor_connection_msg">חיבור חלש למחשב</string>
<string name="perf_overlay_decoder">מפענח: %1$s</string>
<string name="perf_overlay_incomingfps">פריימים לשניה מהרשת: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">פריימים שנפלו בחיבור רשת: %1$.2f%%</string>
<string name="perf_overlay_dectime">זמן פענוח ממוצע: %1$.2f ms</string>
<string name="applist_connect_msg">מתחבר למחשב…</string>
<string name="applist_menu_resume">חזור לשידור</string>
<string name="applist_menu_quit_and_start">סגור משחק נוכחי והתחל</string>
<string name="applist_menu_details">הראה פרטים</string>
<string name="applist_menu_scut">צור קיצור דרך</string>
<string name="applist_quit_app">יוצא</string>
<string name="applist_quit_success">יציאה הושלמה בהצלחה</string>
<string name="applist_details_id">מספר אפליקציה:</string>
<string name="title_add_pc">הוספת מחשב ידנית</string>
<string name="addpc_enter_ip">חייב להכניס כתובת IP</string>
<string name="category_basic_settings">הגדרות בסיסיות</string>
<string name="title_resolution_list">רזולוציית וידיאו</string>
<string name="title_native_res_dialog">אזהרת רזולוצייה טבעית</string>
<string name="title_fps_list">פריימים לשניה</string>
<string name="wol_waking_msg">ייקחו כמה שניות להפעיל את המחשב. אם הוא לא, אנא וודא שהוא מוגדר נכון לפונקציית Wake-On-LAN.</string>
<string name="nettest_text_success">הרשת שלך איננה חוסמת את מונלייט, בבקשה בדוק את הגדרות חומת האש במחשב המארח.
\n
\nאם אתה מנסה להזרים דרך האינטרנט, אנא התקן את הכל Moonlight Internet Hosting Tool על המחשב והפעל את כלי הבדיקה המצורף בכדי לבדוק את חיבור האינטרנט.</string>
<string name="pairing">מאמת…</string>
<string name="pair_pc_ingame">מחשב באמצע משחק. נא לצאת מהמשחק לפני ביצוע חיבור.</string>
<string name="pair_already_in_progress">פעולת החיבור מתבצעת</string>
<string name="wol_waking_pc">מעיר מחשב…</string>
<string name="error_manager_not_running">שירות \"ניהול-מחשב\" לא פעיל. אנא חכה כמה שניות להפעלה מחדש של האפליקציה.</string>
<string name="title_decoding_reset">הגדרות וידיאו אופסו</string>
<string name="error_404">GFE החזיר שגיאת 404. אנא וודא שהמחשב עם כרטיס מסך נתמך. שימוש בתוכנת חיבור מרוחק יכולה לגרום לשגיאה זו. נסה להפעיל מחדש את המחשב או להתקין GFE.</string>
<string name="error_usb_prohibited">גישה למכשירי USB נעולה על ידי מנהל המחשב. בדוק הגדרות knox או MDM.</string>
<string name="message_decoding_error">מונלייט קרס עקב אי-תאימות עם המפענח. נסה לשנות את הגדרות ההזרמה אם הקריסות נמשכות.</string>
<string name="message_decoding_reset">המפענח ממשיך לקרוס בהגדרות הנוכחיות. הגדרות ההזרמה אופסו לברירת המחדל.</string>
<string name="video_decoder_init_failed">נכשלה טעינת מפענח הוידיאו. המכשיר שלך כנראה אינו תומך ברזולוציה או פריימים לשניה שנבחרו.</string>
<string name="no_frame_received_error">חיבור הרשת של אינו מתפקד כראוי. הורד את הגדרות ה-Bitrate או נסה חיבור מהיר יותר.</string>
<string name="check_ports_msg">בדוק את חומת האש וניהול פורטים עבור הפורטים הבאים:</string>
<string name="conn_establishing_title">מתחיל חיבור</string>
<string name="addpc_success">מחשב נוסף בהצלחה</string>
<string name="early_termination_error">מששהו קרה במחשב המארח כשהחלה הזרמה.
\n
\nאנא וודא שאין תוכן מוגן DRM פתוח במחשב. אפשר לנסות להפעיל מחדש את המחשב.</string>
<string name="slow_connection_msg">חיבור איטי למחשב
\nהורד Bitrate</string>
<string name="frame_conversion_error">המחשב המארח דיווח על שגיאת הצפנת וידיאו.
\n
\nנסה לבטל הגדרת HDR, החלפת רזולוציית הזרמה או לשנות את רזולוציית המחשב המארח.</string>
<string name="conn_establishing_msg">מתחבר</string>
<string name="conn_starting">מתחיל</string>
<string name="conn_metered">אזהרה: החיבור הנוכחי הוא נמדד!</string>
<string name="conn_terminated_title">החיבור הופסק</string>
<string name="lost_connection">נאבד החיבור למחשב</string>
<string name="delete_pc_msg">אתה בטוח שאתה רוצה להסיר מחשב זה\?</string>
<string name="conn_client_latency_hw">מהירות פענוח חומרתי:</string>
<string name="conn_error_msg">נכשל להפעיל</string>
<string name="searching_pc">מחפש מחשבים ברשת המקומית שלך...
\n
\nוודא שסאנשיין או GeForce Experience פועלים.</string>
<string name="yes">כן</string>
<string name="no">לא</string>
<string name="help">עזרה</string>
<string name="perf_overlay_streamdetails">הזרמת וידיאו: %1$s %2$.2f FPS</string>
<string name="perf_overlay_renderingfps">פריימים מרונדרים: %1$.2f FPS</string>
<string name="applist_menu_hide_app">הסתר אפליקציה</string>
<string name="perf_overlay_netlatency">מהירות תגובה ממוצעת: %1$d ms (שונות: %2$d ms)</string>
<string name="applist_menu_quit">הפסק שידור</string>
<string name="applist_menu_cancel">בטל</string>
<string name="applist_refresh_error_msg">נכשל להשיג רשימת אפליקציות</string>
<string name="applist_quit_fail">יציאה נכשלה</string>
<string name="applist_menu_tv_channel">הוסף לערוץ</string>
<string name="applist_refresh_title">רשימת אפליקציות</string>
<string name="applist_refresh_msg">מרענן אפליקציות…</string>
<string name="applist_refresh_error_title">שגיאה</string>
<string name="applist_quit_confirmation">אתה בטוח שאתה רוצה לסגור את האפליקציה הנוכחית\? מידע שלא נשמר ייאבד.</string>
<string name="msg_add_pc">מתחבר למחשב…</string>
<string name="addpc_unknown_host">נכשל לאתר כתובת מחשב. נא לוודא שאין שגיאה בכתובת.</string>
<string name="addpc_fail">לא ניתן להתחבר למחשב שנבחר. נא לבדוק שהפורטים הנחוצים פתוחים בחומת האש.</string>
<string name="addpc_wrong_sitelocal">הכתובת לא נראת נכונה. צריך להשתמש בכתובת IP הציבורית בכדי להתחבר דרך האינטרנט.</string>
<string name="summary_resolution_list">להגביר לשיפור איכות התמונה. להוריד לשיפור ביצועים על מערכות ישנות ורשתות איטיות.</string>
<string name="text_native_res_dialog">רזולוציות טבעיות אינן נתמכות רשמית דרך Geforce Expereience, הרזולוציה לא מוגדרת במסך המארח. יש להגדירה ידנית בזמן משחק.
\n
\nיש לקרוא ולהבין את ההנחיות של NVIDIA לגבי אי יציבות ונזקים אם מגדירים רזולוציה מותאמת אישית דרך פאנל הניהול.
\n
\nמונלייט אינו אחראי לבעיות או נזקים שנגרמים כתוצאה משימוש ברזולוציה מותאמת אישית.
\n
\nהמכשיר שלך כנראה ואינו תומך ברזולוציה טבעית.</string>
<string name="summary_seekbar_bitrate">הגבר לשיפור איכות התמונה. הנמך בכדי לשפר ביצועים על גבי חיבור רשת איטי.</string>
<string name="summary_audio_config_list">הפעל קול היקפי בהגדרת 5.1 או 7.1 עבור מערכות קולנוע ביתי</string>
<string name="summary_checkbox_enable_audiofx">אפשר לאפקטי סאונד לפעול בזמן הזרמה, יגרום להשהיית אודיו</string>
<string name="conn_hardware_latency">זמן פענוח ממוצע:</string>
<string name="summary_fps_list">הגבר להזרמת וידיאו חלקה יותר. הנמך לביצועים ויציבות במכשירים חלשים.</string>
<string name="title_seekbar_bitrate">וידיאו ביטרייט</string>
<string name="suffix_seekbar_bitrate_mbps">מגהביט</string>
<string name="title_checkbox_stretch_video">מתחית וידיאו למסך מלא</string>
<string name="resolution_prefix_native">טבעי</string>
<string name="resolution_prefix_native_fullscreen">טבעי במסך מלא</string>
<string name="category_audio_settings">הגדרות אודיו</string>
<string name="title_audio_config_list">הגדרת קול היקפי (Surround sound)</string>
<string name="title_checkbox_enable_audiofx">הפעל תמיכה באקולייזר</string>
<string name="category_input_settings">הגדרות קלט</string>
<string name="title_checkbox_touchscreen_trackpad">השתמש במסך מגע כמשטח מגע</string>
</resources>
+23 -20
View File
@@ -1,13 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- PC view menu entries -->
<string name="pcview_menu_app_list">ゲームリストを表示</string>
<string name="pcview_menu_pair_pc">コンピュータとペアリング</string>
<string name="pcview_menu_unpair_pc">ペアリングを解除r</string>
<string name="pcview_menu_send_wol">Wake-On-LANリクエストを送信する</string>
<string name="pcview_menu_delete_pc">コンピュータをリストから削除する</string>
<!-- Pair messages -->
<string name="pairing">ペアリング中</string>
<string name="pair_pc_offline">コンピュータはオフラインです</string>
@@ -16,26 +14,22 @@
<string name="pair_pairing_msg">ペアリングしたいコンピュータのPINコードを入力してください:</string>
<string name="pair_incorrect_pin">PINコードが間違っています</string>
<string name="pair_fail">ペアリングに失敗しました</string>
<!-- WOL messages -->
<string name="wol_pc_online">コンピュータはオンラインです</string>
<string name="wol_no_mac">GFEがMACアドレスを送信しなかったため、コンピュータを起動することができません</string>
<string name="wol_waking_pc">コンピュータを起動中</string>
<string name="wol_waking_msg">コンピュータが起動するまで数秒かかる可能性があります。Wake-On-LANが正しく構成されているか確認してください</string>
<string name="wol_fail">Wake-On-LANパケットの送信に失敗しました</string>
<!-- Unpair messages -->
<string name="unpairing">ペアリングの解除中</string>
<string name="unpair_success">ペアリングの解除に成功しました</string>
<string name="unpair_fail">ペアリングの解除に失敗しました</string>
<string name="unpair_error">このデバイスはペアリングされませんでした</string>
<!-- Errors -->
<string name="error_pc_offline">コンピュータはオフラインです</string>
<string name="error_manager_not_running">ComputerManagerサービスが動作していません。しばらく待つか、Moonlightを再起動してください</string>
<string name="error_unknown_host">ホストが解決できません</string>
<string name="error_404">GFEがHTTP 404を返しました。コンピュータでサポートされているGPUが動作しているか確認してください。リモートデスクトップソフトウェアでもこのエラーが発生する可能性があります。コンピュータを再起動するか、GFEを再インストールしてください</string>
<!-- Start application messages -->
<string name="conn_establishing_title">接続を確立</string>
<string name="conn_establishing_msg">接続を開始</string>
@@ -48,14 +42,12 @@
<string name="conn_error_msg">開始できません</string>
<string name="conn_terminated_title">接続を終了</string>
<string name="conn_terminated_msg">接続は終了しました</string>
<!-- General strings -->
<string name="ip_hint">コンピュータのIPアドレス</string>
<string name="searching_pc">コンピュータを検索中</string>
<string name="yes">はい</string>
<string name="no">いいえ</string>
<string name="lost_connection">コンピュータとの接続が失われました</string>
<!-- AppList activity -->
<string name="applist_menu_resume">セッションを続ける</string>
<string name="applist_menu_quit">セッションを終了する</string>
@@ -69,7 +61,6 @@
<string name="applist_quit_success">ゲームを終了しました</string>
<string name="applist_quit_fail">ゲームが終了できませんでした</string>
<string name="applist_quit_confirmation">本当にゲームを終了しますか? 保存されていないデータは破棄されます</string>
<!-- Add computer manually activity -->
<string name="title_add_pc">手動でコンピュータを追加する</string>
<string name="msg_add_pc">コンピュータに接続中</string>
@@ -77,7 +68,6 @@
<string name="addpc_success">コンピュータの追加に成功しました</string>
<string name="addpc_unknown_host">コンピュータのアドレスが解決できません。コンピュータのアドレスを確認してください</string>
<string name="addpc_enter_ip">IPアドレスを入力してください</string>
<!-- Preferences -->
<string name="category_basic_settings">基本的な設定</string>
<string name="title_resolution_list">解像度とフレームレート</string>
@@ -87,32 +77,26 @@
<string name="title_checkbox_stretch_video">映像を全画面に拡大</string>
<string name="title_checkbox_disable_warnings">警告を無効化</string>
<string name="summary_checkbox_disable_warnings">ストリーミング中に画面に警告メッセージを表示しない</string>
<string name="category_audio_settings">音声</string>
<string name="title_checkbox_multi_controller">複数のゲームコントローラ</string>
<string name="summary_checkbox_multi_controller">チェックを外すと、全てのゲームコントローラが単一の物として認識されます</string>
<string name="title_seekbar_deadzone">アナログゲームコントローラのデッドゾーン</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Xbox 360/Oneコントローラ</string>
<string name="summary_checkbox_xb1_driver">XboxゲームコントローラをサポートしないデバイスでXboxゲームコントローラ用のドライバを有効にします</string>
<string name="category_on_screen_controls_settings">オンスクリーンコントローラ</string>
<string name="title_checkbox_show_onscreen_controls">オンスクリーンコントローラ</string>
<string name="summary_checkbox_show_onscreen_controls">タッチスクリーン上にオンスクリーンコントローラを表示します</string>
<string name="category_ui_settings">インターフェース</string>
<string name="title_language_list">言語</string>
<string name="summary_language_list">Moonlightで使用する言語</string>
<string name="title_checkbox_small_icon_mode">小さなアイコン</string>
<string name="summary_checkbox_small_icon_mode">グリッドで小さなアイコンを使用します</string>
<string name="category_host_settings">ホスト</string>
<string name="title_checkbox_enable_sops">ゲーム設定の最適化</string>
<string name="summary_checkbox_enable_sops">GFEがゲームの設定を最適化します</string>
<string name="title_checkbox_host_audio">コンピュータで音声を再生</string>
<string name="summary_checkbox_host_audio">音声をコンピュータとこのデバイスの両方で再生します</string>
<string name="category_advanced_settings">高度な設定</string>
<string name="title_video_format">HEVC</string>
<string name="summary_video_format">HEVCは動画に必要な帯域幅を圧縮します。この機能にはなるべく新しいデバイスが必要です</string>
@@ -129,9 +113,28 @@
<string name="toast_reset_osc_success">オンスクリーンコントローラをデフォルトに戻しました</string>
<string name="title_checkbox_vibrate_osc">振動</string>
<string name="summary_checkbox_vibrate_osc">コントローラの振動を真似します</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">安定している場合にHEVCを有効化</string>
<string name="videoformat_hevcalways">HEVCを強制的に有効化(クラッシュする可能性があります)</string>
<string name="videoformat_hevcnever">HEVCを無効化</string>
</resources>
<string name="scut_not_paired">コンピュータとペアリングされてません</string>
<string name="scut_invalid_uuid">指定したコンピュータは有効ではないです</string>
<string name="scut_invalid_app_id">指定したアプリは無効です</string>
<string name="help_loading_msg">ヘルプページを読み込み中…</string>
<string name="nettest_text_success">ネットワークは Moonlight をブロックしていません。接続に問題があるようでしたらコンピュータのファイアーウォールの設定を確認してください。
\n
\nインターネット上でゲームをストリームする場合は Moonlight Internet Hosting Tool をインストールして付属のInternet Streaming Tester をはしらせコンピュータの接続を確認してください。</string>
<string name="nettest_text_inconclusive">Moonlight のコネクションテスト用のサーバーがアクセスできなかったためネットワークテストができませんでした。インターネットの接続を確認し、再度お試しください。</string>
<string name="help_loading_title">ヘルプ表示</string>
<string name="pcview_menu_header_unknown">リロード中</string>
<string name="scut_deleted_pc">コンピュータを検知しました</string>
<string name="scut_pc_not_found">コンピュータが見つかりませんでした</string>
<string name="pcview_menu_header_offline">オフライン</string>
<string name="pcview_menu_eol">NVIDIA GameStream はサービスが終了しています</string>
<string name="nettest_text_waiting">Moonlight はポートがブロックされていないか確かめるためネットワーク接続をてすとしています。
\n
\n少々お待ちください…</string>
<string name="pcview_menu_header_online">オンライン</string>
<string name="pcview_menu_test_network">ネットワーク接続テスト</string>
<string name="nettest_title_done">ネットワークテスト終了</string>
<string name="pcview_menu_details">詳細を表示</string>
<string name="nettest_title_waiting">ネットワーク接続テスト中</string>
</resources>
+52 -29
View File
@@ -23,7 +23,7 @@
<string name="pair_already_in_progress">페어링이 이미 진행중입니다</string>
<!-- WOL messages -->
<string name="wol_pc_online">컴퓨터가 온라인 상태입니다</string>
<string name="wol_no_mac">Geforce Experience가 MAC 주소를 보내지 않아 PC를 켤 수 없습니다.</string>
<string name="wol_no_mac">저장된 MAC 주소가 없기 때문에 PC를 켤 수 없습니다.</string>
<string name="wol_waking_pc">PC를 깨우는 중…</string>
<string name="wol_waking_msg">PC를 켜는 데에 약간의 시간이 걸립니다. PC가 켜지지 않으면, Wake-On-Lan이 설정되어있는지 확인하세요.</string>
<string name="wol_fail">Wake-On-LAN 패킷을 보내는 데에 실패했습니다</string>
@@ -52,9 +52,10 @@
<string name="conn_terminated_title">연결 종료 됨</string>
<string name="conn_terminated_msg">연결이 종료되었습니다</string>
<!-- General strings -->
<string name="ip_hint">GeForce PC의 IP 주소</string>
<string name="searching_pc">GameStream이 실행중인 PC를 검색중…\n\n
GameStream이 Geforce Experience 설정에서 활성화되어있는지 확인하세요.</string>
<string name="ip_hint">호스트 PC의 IP 주소</string>
<string name="searching_pc">로컬 네트워크의 호스트 PC를 검색중…
\n
\n 호스트 PC에서 Sunshine이 실행 중인지 또는 GeForce Experience SHIELD 설정에서 GameStream이 활성화되어 있는지 확인하십시오.</string>
<string name="yes"></string>
<string name="no">아니오</string>
<string name="lost_connection">PC 연결 끊김</string>
@@ -90,8 +91,8 @@
<string name="title_checkbox_disable_warnings">경고 메세지 끄기</string>
<string name="summary_checkbox_disable_warnings">화면 상의 연결 경고 메세지를 스트리밍 중에 비활성화합니다.</string>
<string name="category_audio_settings">오디오 설정</string>
<string name="title_checkbox_multi_controller">다중 컨트롤러 지</string>
<string name="summary_checkbox_multi_controller">이 옵션을 선택하지 않으면 모든 컨트롤러가 하나로 표시됩니다</string>
<string name="title_checkbox_multi_controller">자동 컨트롤러 유무 감</string>
<string name="summary_checkbox_multi_controller">이 옵션을 선택 취소하면 컨트롤러가 항상 표시됩니다</string>
<string name="title_seekbar_deadzone">아날로그 스틱 데드존 설정</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Xbox 360/One 컨트롤러 드라이버</string>
@@ -110,11 +111,11 @@
<string name="title_checkbox_host_audio">PC에서 소리 재생</string>
<string name="summary_checkbox_host_audio">이 장치와 컴퓨터에서 소리를 재생합니다.</string>
<string name="category_advanced_settings">고급 설정</string>
<string name="title_video_format">HEVC 설정 변경</string>
<string name="summary_video_format">HEVC는 낮은 대역폭으로 더 좋은 화질을 볼 수 있게 해주지만 최신 장치가 필요합니다.</string>
<string name="title_video_format">코덱 설정 변경</string>
<string name="summary_video_format">최신 코덱은 장치에서 지원하는 경우 비디오 대역폭 요구 사항을 낮출 수 있습니다. 호스트 소프트웨어 또는 GPU에서 지원하지 않는 경우 코덱 선택을 무시할 수 있습니다.</string>
<string name="suffix_osc_opacity">%</string>
<string name="title_checkbox_enable_pip">PIP모드 활성화</string>
<string name="summary_checkbox_vibrate_fallback">게임 패드가 진동을 지원하지 않는 경우 장치를 진동 시켜 진동을 활성화합니다</string>
<string name="summary_checkbox_vibrate_fallback">컨트롤러가 진동을 지원하지 않는 경우 장치를 진동 시켜 진동을 활성화합니다</string>
<string name="title_checkbox_vibrate_fallback">게임패드 진동을 장치에서 사용하기</string>
<string name="summary_checkbox_touchscreen_trackpad">활성화시 터치 스크린이 트랙 패드처럼 작동합니다. 비활성화 된 경우 터치 스크린처럼 작동합니다.</string>
<string name="title_checkbox_touchscreen_trackpad">터치 스크린을 트랙 패드로 사용하기</string>
@@ -124,13 +125,13 @@
<string name="resolution_prefix_native">네이티브</string>
<string name="summary_fps_list">높을수록 화면이 더 부드러워집니다. 저사양 기기에서는 낮추는것이 좋습니다.</string>
<string name="title_fps_list">FPS 설정</string>
<string name="text_native_res_dialog">1. 네이티브 해상도 모드는 GeForce Experience에서 공식적으로 지원지 않으므로 호스트PC의 디스플레이 해상도는 변경되지 않습니다. 따라서 스트리밍 중에 수동으로 해상도를 변경해야합니다.
<string name="text_native_res_dialog">네이티브 해상도 및 FPS는 스트리밍 서버에서 지원지 않을 수 있습니다. 호스트 PC에 대해 일치하는 사용자 지정 디스플레이 모드를 수동으로 구성해야 할 수 있습니다.
\n
\n2. 장치 해상도와 일치하도록 NVIDIA 제어판에서 사용자 정의 해상도를 생성 할 경우 호스트 PC의 모니터 손상, 기타 잠재적 문제에 대한 NVIDIA의 경고를 읽고 이해했는지 확인하십시오.
\n
\n3. Moonlight는 PC에서 사용자 정의 해상도를 생성하여 발생하는 문제에 대해 책임을 지지 않습니다.
\n화면 설정과 일치하도록 NVIDIA 제어판에서 사용자 정의 해상도를 생성 할 경우 모니터 손상, PC 불안정 및 기타 잠재적 문제에 대한 NVIDIA의 경고를 읽고 이해했는지 확인하십시오.
\n
\n4. 장치 또는 호스트 PC가 네이티브 해상도의 스트리밍을 지원하지 않을 수 있습니다.</string>
\nMoonlight는 PC에서 사용자 지정 해상도를 생성하여 발생하는 문제에 대해 책임을 지지 않습니다.
\n
\n모니터가 필요한 디스플레이 구성을 지원하지 않을 경우 가상 모니터 설정을 시도할 수 있습니다. 장치나 호스트 PC가 특정 해상도나 새로 고침 빈도로 스트리밍을 지원하지 않을 수 있습니다.</string>
<string name="title_native_res_dialog">네이티브 해상도 주의사항</string>
<string name="addpc_wrong_sitelocal">주소가 잘못된 것 같습니다. 인터넷을 통해 스트리밍하려면 라우터의 공용 IP 주소를 사용해야합니다.</string>
<string name="applist_details_id">앱 ID:</string>
@@ -151,16 +152,14 @@
<string name="check_ports_msg">다음 포트의 방화벽 및 포트 포워딩 설정을 확인하십시오:</string>
<string name="early_termination_error">스트림을 시작할 때 호스트 PC에서 문제가 발생했습니다.
\n
\n호스트 PC에 DRM으로 보호 된 콘텐츠가 열려 있지 않은지 확인하거나 호스트 PC를 재부팅하십시오 .
\n
\n문제가 지속되면 GPU 드라이버와 GeForce Experience를 다시 설치해보십시오.</string>
\n호스트 PC에 DRM으로 보호 된 콘텐츠가 열려 있지 않은지 확인하거나 호스트 PC를 재부팅하십시오 .</string>
<string name="no_frame_received_error">네트워크 연결이 불안정합니다. 비트레이트를 낮추거나 더 빠른 네트워크에 연결하십시오.</string>
<string name="no_video_received_error">호스트로부터 비디오를 받지 못했습니다.</string>
<string name="video_decoder_init_failed">비디오 디코더를 실행하지 못했습니다. 이 장치가 선택한 해상도 또는 프레임 속도를 지원하지 않을 수 있습니다.</string>
<string name="error_usb_prohibited">기기 관리자에 의해 USB 액세스가 차단되었습니다. Knox 또는 MDM 설정을 확인하십시오.</string>
<string name="message_decoding_reset">선택한 스트리밍 설정에서 장치의 비디오 디코더가 계속 문제가 발생합니다. 스트리밍 설정이 기본값으로 재설정되었습니다.</string>
<string name="title_decoding_reset">비디오 설정 초기화</string>
<string name="message_decoding_error">이 장치의 비디오 디코더와 호환되지 않아 Moonlight에서 오류가 발생했습니다. GeForce Experience가 PC의 최신 버전으로 업데이트되었는지 확인하십시오. 충돌이 계속되면 스트리밍 설정을 조정 해보십시오.</string>
<string name="message_decoding_error">이 장치의 비디오 디코더와 호환되지 않아 Moonlight에서 오류가 발생했습니다. 충돌이 계속되면 스트리밍 설정을 조정 해보십시오.</string>
<string name="title_decoding_error">비디오 디코더 오류</string>
<string name="nettest_text_blocked">기기의 현재 네트워크가 Moonlight를 차단하고 있습니다. 이 네트워크에 연결되어 있으면 인터넷을 통한 스트리밍이 작동하지 않을 수 있습니다.</string>
<string name="nettest_text_failure">기기의 현재 네트워크가 Moonlight를 차단하는 것 같습니다. 이 네트워크에 연결되어 있으면 인터넷을 통한 스트리밍이 작동하지 않을 수 있습니다.
@@ -172,7 +171,7 @@
\n
\n인터넷을 통해 연결하려는 경우 PC에 Moonlight Internet Hosting Tool을 설치하고 Internet Streaming Tester를 실행하여 PC의 인터넷 연결을 확인하십시오.</string>
<string name="nettest_title_done">네트워크 연결 테스트 완료</string>
<string name="nettest_text_waiting">NVIDIA GameStream이 차단되었는지 확인하기 위해 네트워크 연결을 테스트하고 있습니다.
<string name="nettest_text_waiting">Moonlight는 필요한 포트가 차단되었는지 확인하기 위해 네트워크 연결을 테스트하고 있습니다.
\n
\n잠시 기다려 주세요…</string>
<string name="pcview_menu_header_unknown">상태 확인중</string>
@@ -190,8 +189,8 @@
<string name="title_enable_post_stream_toast">스트리밍 후 지연시간 정보 표시</string>
<string name="title_enable_perf_overlay">스트리밍 중 성능 정보 표시</string>
<string name="summary_enable_perf_overlay">스트리밍하는 동안 실시간 스트림 성능 정보 표시</string>
<string name="summary_enable_hdr">게임 및 PC의 GPU가 HDR을 지원하는 경우 HDR을 활성화합니다. HDR에는 GTX 1000 시리즈 또는 그 이상의 GPU가 필요합니다.</string>
<string name="title_enable_hdr">HDR활성화 (실험중인 기능)</string>
<string name="summary_enable_hdr">게임 및 PC의 GPU가 HDR을 지원하는 경우 HDR을 활성화합니다. HDR에는 HEVC Main 10 인코딩을 지원하는 GPU가 필요합니다.</string>
<string name="title_enable_hdr">HDR활성화 (실험)</string>
<string name="summary_disable_frame_drop">일부 장치에서 미세한 끊김 현상을 줄일 수 있지만 지연 시간이 늘어날 수 있습니다.</string>
<string name="title_disable_frame_drop">프레임드랍 최적화</string>
<string name="summary_unlock_fps">90 또는 120FPS로 스트리밍하면 지연 시간이 줄어들 수 있지만 이를 지원할 수 없는 장치에서는 지연 또는 불안정 할 수 있습니다</string>
@@ -207,23 +206,22 @@
<string name="title_reset_osc">가상 컨트롤러 배치 초기화</string>
<string name="summary_only_l3r3">L3 및 R3을 제외한 모든 가상 버튼을 숨깁니다</string>
<string name="title_only_l3r3">L3와 R3버튼만 표시하기</string>
<string name="summary_checkbox_flip_face_buttons">게임 패드 및 가상 컨트롤러의 A / B 와 X / Y 버튼을 바꿉니다</string>
<string name="summary_checkbox_flip_face_buttons">컨트롤러 및 가상 컨트롤러의 A / B 와 X / Y 버튼을 바꿉니다</string>
<string name="summary_checkbox_vibrate_osc">가상 컨트롤러에서 장치를 진동하여 게임패드 진동을 구현합니다</string>
<string name="title_checkbox_vibrate_osc">진동 활성화</string>
<string name="title_checkbox_flip_face_buttons">버튼 바꾸기</string>
<string name="summary_checkbox_mouse_nav_buttons">이 옵션을 활성화하면 일부 장치에서 오른쪽 클릭에 문제가 있을 수 있습니다</string>
<string name="title_checkbox_mouse_nav_buttons">마우스 사이드버튼 활성화</string>
<string name="summary_checkbox_mouse_emulation">패드의 Start 버튼을 길게 누르면 게임 패드가 마우스 모드로 전환됩니다</string>
<string name="summary_checkbox_usb_bind_all">Xbox 컨트롤러를 기본으로 지원하는 경우에도 지원되는 모든 게임 패드에 Moonlight의 USB 드라이버를 사용합니다</string>
<string name="title_checkbox_usb_bind_all">기본 Xbox 게임 패드 지원 무시</string>
<string name="title_checkbox_mouse_emulation">게임패드를 마우스처럼 사용하기</string>
<string name="summary_checkbox_mouse_emulation">패드의 Start 버튼을 길게 누르면 컨트롤러가 마우스 모드로 전환됩니다</string>
<string name="summary_checkbox_usb_bind_all">Xbox 컨트롤러를 기본으로 지원하는 경우에도 지원되는 모든 컨트롤러에 Moonlight의 USB 드라이버를 사용합니다</string>
<string name="title_checkbox_usb_bind_all">기본 Xbox 컨트롤러 지원 무시</string>
<string name="title_checkbox_mouse_emulation">컨트롤러를 마우스처럼 사용하기</string>
<string name="perf_overlay_streamdetails">비디오 스트림 : %1$s %2$.2f FPS</string>
<string name="unable_to_pin_shortcut">현재 런처에서는 바로가기 생성이 불가능합니다.</string>
<string name="resolution_prefix_native_fullscreen">네이티브 (전체화면)</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">자동</string>
<string name="videoformat_hevcalways">항상 HEVC 사용(깨질 가능성 있음)</string>
<string name="videoformat_hevcnever">HEVC 사용하지 않기</string>
<string name="videoformat_auto">자동 (권장)</string>
<string name="videoformat_hevcalways">HEVC 선호</string>
<string name="summary_seekbar_deadzone">참고: 일부 게임은 이 설정값보다 더 큰 데드존이 적용되있을 수 있습니다.</string>
<string name="resolution_1080p">1080p</string>
<string name="resolution_360p">360p</string>
@@ -255,4 +253,29 @@
<string name="title_frame_pacing">비디오 프레임 처리방식</string>
<string name="pacing_smoothness">가장 부드러운 비디오 선호(대기 시간이 크게 증가할 수 있음)</string>
<string name="category_help">도움말</string>
<string name="resolution_prefix_native_landscape">(가로)</string>
<string name="resolution_prefix_native_portrait">(세로)</string>
<string name="title_checkbox_reduce_refresh_rate">주사율 감소 허용</string>
<string name="summary_checkbox_reduce_refresh_rate">화면 주사율을 낮춰서 영상 지연 시간이 증가하고 전력을 절약할 수 있습니다.</string>
<string name="frame_conversion_error">호스트 PC에서 치명적인 비디오 인코딩 오류를 보고했습니다.
\n
\nHDR 모드를 비활성화하거나 스트리밍 해상도를 변경하거나 호스트 PC의 디스플레이 해상도를 변경해 보십시오.</string>
<string name="summary_full_range">밝기범위를 \"전체(0~255)\"로 설정합니다. 장치의 디스플레이가 \"제한(16~235)\" 범위로 출력하는 경우 밝기가 제대로 표현되지 않습니다.</string>
<string name="title_full_range">전체 범위 비디오 활성화 (실험용)</string>
<string name="title_checkbox_gamepad_motion_sensors">컨트롤러 모션 센서 사용 허용</string>
<string name="summary_checkbox_gamepad_motion_sensors">모션 센서가 있는 컨트롤러를 에뮬레이션할 때 지원되는 호스트가 모션 센서 데이터를 요청할 수 있습니다. 비활성화하면 게임에서 동작 센서를 사용하지 않는 경우 전원 및 네트워크 사용량이 약간 줄어들 수 있습니다.</string>
<string name="summary_checkbox_gamepad_touchpad_as_mouse">터치패드로 컨트롤러를 에뮬레이션하는 경우에도 호스트 마우스를 제어하기 위해 컨트롤러 터치패드 입력을 강제합니다.</string>
<string name="pcview_menu_eol">NVIDIA GameStream 지원 종료</string>
<string name="pair_pairing_help">호스트 PC에서 Sunshine을 실행 중인 경우 Sunshine 웹 UI로 이동하여 PIN을 입력합니다.</string>
<string name="perf_overlay_hostprocessinglatency">호스트 처리 대기 시간 최소/최대/평균: %1$.1f/%2$.1f/%3$.1f ms</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_checkbox_gamepad_touchpad_as_mouse">항상 터치패드로 마우스 제어</string>
<string name="videoformat_av1always">AV1 선호 (실험용)</string>
<string name="videoformat_h264always">H.264 선호</string>
<string name="toast_controller_type_changed">모션 센서 에뮬레이션으로 인해 컨트롤러 유형이 변경될 수 있습니다</string>
<string name="summary_checkbox_gamepad_motion_fallback">연결된 컨트롤러 또는 기기의 Android 버전에서 컨트롤러 센서가 지원되지 않는 경우 장치에 내장된 모션 센서를 사용합니다.
\n참고: 이 옵션을 활성화하면 사용 중인 컨트롤러가 호스트에서 PlayStation 컨트롤러로 나타날 수 있습니다.</string>
<string name="title_checkbox_gamepad_motion_fallback">컨트롤러의 모션 센서 에뮬레이션 지원</string>
</resources>
-2
View File
@@ -223,7 +223,5 @@
<string name="applist_menu_tv_channel">Toevoegen aan Kanaal</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Gebruik HEVC alleen als het stabiel is.</string>
<string name="videoformat_hevcalways">Gebruik HEVC altijd (mogelijkheid tot crashes)</string>
<string name="videoformat_hevcnever">Gebruik HEVC nooit</string>
</resources>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="scut_deleted_pc">PC usunięty</string>
<string name="scut_pc_not_found">PC nie znaleziony</string>
<string name="pcview_menu_header_unknown">Odświeżanie</string>
<string name="scut_not_paired">PC niesparowany</string>
</resources>
+7 -3
View File
@@ -53,14 +53,13 @@
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="fps_60">60 FPS</string>
<string name="videoformat_hevcalways">Sempre usar HEVC (talvez crashe)</string>
<string name="videoformat_hevcauto">Automático</string>
<string name="videoformat_hevcalways">Prefira HEVC</string>
<string name="videoformat_auto">Automático (recomendado)</string>
<string name="fps_120">120 FPS</string>
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">5.1 Surround</string>
<string name="audioconf_71surround">7.1 Surround</string>
<string name="fps_90">90 FPS</string>
<string name="videoformat_hevcnever">Nunca usar HEVC</string>
<string name="scut_deleted_pc">PC deletado</string>
<string name="scut_not_paired">PC não pareado</string>
<string name="help_loading_title">Ver Ajuda</string>
@@ -245,4 +244,9 @@
<string name="resolution_prefix_native_portrait">(Retrato)</string>
<string name="title_checkbox_enable_audiofx">Habilitar sistema de suporte à equalização</string>
<string name="summary_checkbox_enable_audiofx">Permitir que efeitos de audio funcionem durante o streaming, pode acrescentar latência de audio</string>
<string name="title_full_range">Forçar vídeo de gama completa de cores (Experimental)</string>
<string name="frame_conversion_error">O PC host relatou um erro fatal de codificação de vídeo.
\n
\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>
</resources>
+226
View File
@@ -23,4 +23,230 @@
<string name="nettest_text_waiting">Moonlight está testando sua conexão com a rede para determinar se o NVIDIA GameStream está bloqueado.
\n
\nEste processo pode demorar alguns segundos…</string>
<string name="pacing_balanced">Balanceado</string>
<string name="nettest_text_success">A sua rede não parece estar a bloquear o Moonlight. Se ainda tiver problemas a se conectar, verifique as configurações de firewall do seu PC.
\n
\nSe estiver a tentar transmitir pela Internet, instale o Moonlight Internet Hosting Tool no seu PC e execute o Internet Streaming Tester para verificar a conexão com a Internet do seu PC.</string>
<string name="nettest_text_failure">A conexão de rede atual do seu aparelho parece estar a bloquear o Moonlight. A transmissão pela Internet pode não funcionar enquanto estiver conectado a esta rede.
\n
\nAs seguintes portas de rede estão bloqueadas:
\n</string>
<string name="nettest_text_blocked">A conexão de rede atual do seu aparelho está a bloquear o Moonlight. A transmissão pela Internet pode não funcionar enquanto estiver conectado a esta rede.</string>
<string name="wol_waking_msg">Pode levar alguns segundos até o seu PC acordar. Se isso não acontecer, verifique se ele está configurado corretamente para Wake-On-LAN.</string>
<string name="wol_fail">Falha ao enviar pacotes Wake-On-LAN</string>
<string name="unpair_success">Despareado com sucesso</string>
<string name="unpair_fail">Falha ao desparear</string>
<string name="title_decoding_error">Decodificador de Vídeo Crashou</string>
<string name="title_decoding_reset">Resetar Configurações de Vídeo</string>
<string name="message_decoding_error">Moonlight crashou devido a uma incompatibilidade com o decodificador de vídeo deste aparelho. Certifique-se de que o GeForce Experience esteja atualizado à versão mais recente no seu PC. Tente ajustar as configurações de transmissão se as falhas continuarem.</string>
<string name="unable_to_pin_shortcut">O seu launcher atual não permite a criação de atalhos fixados.</string>
<string name="video_decoder_init_failed">Falha ao iniciar o decodificador de vídeo. O seu aparelho pode não suportar a resolução ou taxa de quadros selecionada.</string>
<string name="frame_conversion_error">O PC host relatou um erro fatal de codificação de vídeo.
\n
\nTente desativar o modo HDR, alterar a resolução de streaming ou alterar a resolução do PC host.</string>
<string name="early_termination_error">Algo deu errado no seu PC ao iniciar a transmissão.
\n
\nCertifique-se de não ter nenhum conteúdo protegido por DRM aberto no seu PC. Também pode tentar reiniciar ele.
\n
\nSe o problema persistir, tente reinstalar os drivers da GPU e o GeForce Experience.</string>
<string name="conn_metered">Aviso: A sua conexão de rede atual é limitada!</string>
<string name="conn_client_latency">Latência média de decodificação de quadros:</string>
<string name="conn_client_latency_hw">latência do decodificador de hardware:</string>
<string name="conn_error_msg">Falha ao iniciar</string>
<string name="conn_terminated_title">Conexão Encerrada</string>
<string name="conn_terminated_msg">A conexão foi encerrada</string>
<string name="ip_hint">Endereço de IP do PC GeForce</string>
<string name="searching_pc">Procurando por PCs a executar o GameStream...
\n
\nCertifique-se de que o GameStream esteja ativado nas configurações do SHIELD do GeForce Experience.</string>
<string name="perf_overlay_renderingfps">Taxa de quadros renderizando: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Quadros dropados pela rede: %1$.2f%%</string>
<string name="perf_overlay_netlatency">Latência média da rede: %1$d ms (variação: %2$d ms)</string>
<string name="applist_menu_scut">Criar Atalho</string>
<string name="applist_refresh_msg">A recarregar apps…</string>
<string name="applist_refresh_error_msg">Falha ao obter a lista de apps</string>
<string name="applist_quit_app">Saindo</string>
<string name="applist_quit_success">Saiu com sucesso</string>
<string name="applist_quit_fail">Falha ao sair</string>
<string name="text_native_res_dialog">Os modos de resolução nativa não são oficialmente suportados pelo GeForce Experience, portanto, ele não definirá a resolução da ecrã do host. Precisará configurá-lo manualmente durante o jogo.
\n
\nSe optar por criar uma resolução personalizada no Painel de controle da NVIDIA para corresponder à resolução do seu aparelho, certifique-se de ter lido e entendido o aviso da NVIDIA sobre possíveis danos ao monitor, instabilidade do PC e outros problemas potenciais.
\n
\nNão nos responsabilizamos por quaisquer problemas resultantes da criação de uma resolução personalizada no seu PC.
\n
\nPor fim, o seu aparelho ou PC host pode não suportar transmissões na resolução nativa. Se não funcionar no seu aparelho, está sem sorte, infelizmente.</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="resolution_prefix_native_landscape">(Paisagem)</string>
<string name="resolution_prefix_native_portrait">(Retrato)</string>
<string name="title_audio_config_list">Configurações de som Surround</string>
<string name="title_checkbox_enable_audiofx">Ativar sistema de suporte à equalização</string>
<string name="title_checkbox_multi_controller">Detecção automática de gamepad</string>
<string name="summary_checkbox_vibrate_fallback">Vibra o seu aparelho para emular rumble se o seu gamepad não suportar</string>
<string name="title_seekbar_deadzone">Ajustar zona morta do analógico</string>
<string name="summary_checkbox_enable_audiofx">Permitir que efeitos de audio funcionem durante o streaming, pode acrescentar latência de audio</string>
<string name="summary_checkbox_xb1_driver">Ativa um driver USB integrado para aparelhos sem suporte nativo aos controles Xbox</string>
<string name="title_checkbox_usb_bind_all">Substituir o suporte nativo ao gamepad do Xbox</string>
<string name="summary_checkbox_usb_bind_all">Use o driver USB do Moonlight para todos os gamepads suportados, mesmo se houver suporte nativo ao controle Xbox</string>
<string name="title_checkbox_mouse_emulation">Emulação de rato pelo gamepad</string>
<string name="summary_checkbox_mouse_emulation">Segure o botão Start para mudar o gamepad ao modo de rato</string>
<string name="summary_checkbox_flip_face_buttons">Inverte os botões A/B e X/Y dos gamepads e controles de ecrã</string>
<string name="title_checkbox_absolute_mouse_mode">Modo de rato para área de trabalho remota</string>
<string name="summary_checkbox_absolute_mouse_mode">Isso pode alterar a aceleração do rato para se comportar mais naturalmente para uso em desktop remoto, mas é incompatível com muitos jogos.</string>
<string name="category_on_screen_controls_settings">Configurações de Controles de Ecrã</string>
<string name="title_checkbox_show_onscreen_controls">Mostrar controles no ecrã</string>
<string name="summary_checkbox_show_onscreen_controls">Ativa o controle virtual no ecrã de toque</string>
<string name="summary_only_l3r3">Esconde todos os botões virtuais exceto o L3 e R3</string>
<string name="dialog_title_reset_osc">Resetar Layout</string>
<string name="toast_reset_osc_success">Controles de ecrã redefinidos para o padrão</string>
<string name="title_osc_opacity">Mudar a opacidade dos controles de ecrã</string>
<string name="dialog_title_osc_opacity">Mudar opacidade</string>
<string name="suffix_osc_opacity">%</string>
<string name="category_ui_settings">Configurações de Interface</string>
<string name="title_checkbox_enable_pip">Ativar modo Picture-in-Picture</string>
<string name="summary_checkbox_enable_pip">Permite que a transmissão seja visualizada (mas não controlada) enquanto usa outros apps</string>
<string name="summary_checkbox_small_icon_mode">Diminui o tamanho dos ícones permitindo que mais apps sejam visíveis no ecrã</string>
<string name="summary_checkbox_host_audio">Reproduz o áudio do computador e deste aparelho</string>
<string name="category_advanced_settings">Configurações Avançadas</string>
<string name="title_unlock_fps">Liberar todas as taxas de quadros possíveis</string>
<string name="summary_unlock_fps">Transmitir a 90 ou 120 FPS pode reduzir a latência em aparelhos de última geração, mas pode causar atraso ou instabilidade em aparelhos que não suportam</string>
<string name="title_checkbox_reduce_refresh_rate">Permitir redução de taxa de atualização</string>
<string name="summary_checkbox_reduce_refresh_rate">Taxas menores de atualização do display podem gravar energia ao custo de latência de video adicional</string>
<string name="summary_checkbox_disable_warnings">Desativa as mensagens de aviso de conexão no ecrã durante a transmissão</string>
<string name="summary_disable_frame_drop">Talvez reduza o micro-stuttering em alguns aparelhos, mas pode aumentar a latência</string>
<string name="summary_video_format">HEVC reduz os requisitos de largura de banda de vídeo, mas requer um aparelho mais atual</string>
<string name="title_enable_hdr">Ativar HDR (Experimental)</string>
<string name="summary_full_range">Isso causará perda de detalhes em áreas claras e escuras se o seu aparelho não exibir corretamente todo o conteúdo de vídeo em cores.</string>
<string name="title_disable_frame_drop">Nunca dropar quadros</string>
<string name="summary_enable_perf_overlay">Exibe informações de performance em tempo real durante a transmissão</string>
<string name="title_enable_post_stream_toast">Mostrar aviso de latência após terminar a transmissão</string>
<string name="title_troubleshooting">Guia de solução de problemas</string>
<string name="summary_troubleshooting">Veja dicas para diagnosticar e corrigir problemas comuns de streaming</string>
<string name="resolution_360p">360p</string>
<string name="resolution_1080p">1080p</string>
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="fps_120">120 FPS</string>
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">5.1 Surround</string>
<string name="videoformat_auto">Automático (recomendado)</string>
<string name="title_frame_pacing">Ritmo de quadros</string>
<string name="pacing_smoothness">Preferir vídeo mais suave (pode aumentar significativamente a latência)</string>
<string name="summary_seekbar_deadzone">Nota: Alguns jogos podem impor uma zona morta maior do que o Moonlight está configurado para usar.</string>
<string name="dialog_text_reset_osc">Tem certeza de que deseja apagar o layout salvo dos controles de ecrã\?</string>
<string name="category_host_settings">Configurações de Host</string>
<string name="pacing_balanced_alt">Equilibrado com limite de FPS</string>
<string name="audioconf_71surround">7.1 Surround</string>
<string name="videoformat_hevcalways">Prefira HEVC</string>
<string name="error_404">GFE retornou um erro HTTP 404. Verifique se o seu PC tem uma GPU compatível. O uso do software de área de trabalho remota também pode causar esse erro. Tente reiniciar o seu computador ou reinstalar o GFE.</string>
<string name="message_decoding_reset">O decodificador de vídeo do seu aparelho continua crashando nas configurações de transmissão selecionadas. As suas configurações de transmissão foram redefinidas para o padrão.</string>
<string name="error_usb_prohibited">O acesso USB é proibido pelo administrador do seu aparelho. Verifique as suas configurações de Knox ou MDM.</string>
<string name="no_video_received_error">Nenhum vídeo recebido do host.</string>
<string name="no_frame_received_error">A sua conexão de rede não está funcionando bem. Reduza a configuração da taxa de bits do vídeo ou tente uma conexão mais rápida.</string>
<string name="check_ports_msg">Verifique o firewall e permita a(s) seguinte(s) para porta(s):</string>
<string name="conn_hardware_latency">Latência média de decodificação de hardware:</string>
<string name="conn_starting">Iniciando</string>
<string name="conn_error_title">Erro de Conexão</string>
<string name="yes">Sim</string>
<string name="no">Não</string>
<string name="lost_connection">Conexão perdida com o PC</string>
<string name="title_details">Detalhes</string>
<string name="help">Ajuda</string>
<string name="delete_pc_msg">Tem certeza de que deseja apagar este PC\?</string>
<string name="poor_connection_msg">Conexão ruim com o PC</string>
<string name="slow_connection_msg">Conexão lenta com o PC
\nReduza sua taxa de bits</string>
<string name="perf_overlay_streamdetails">Transmissão: %1$s %2$.2f FPS</string>
<string name="perf_overlay_decoder">Decodificador: %1$s</string>
<string name="perf_overlay_incomingfps">Taxa de quadros recebidos pela rede:: %1$.2f FPS</string>
<string name="perf_overlay_dectime">Tempo médio de decodificação: %1$.2f ms</string>
<string name="applist_connect_msg">Conectando ao PC…</string>
<string name="applist_menu_resume">Retomar Sessão</string>
<string name="applist_menu_quit">Sair da Sessão</string>
<string name="applist_menu_quit_and_start">Sair do Jogo Atual e Iniciar</string>
<string name="applist_menu_cancel">Cancelar</string>
<string name="applist_menu_details">Ver Detalhes</string>
<string name="applist_menu_tv_channel">Adicionar ao Canal</string>
<string name="applist_menu_hide_app">Esconder app</string>
<string name="applist_refresh_title">Lista de apps</string>
<string name="applist_refresh_error_title">Erro</string>
<string name="applist_quit_confirmation">Tem certeza de que deseja sair da app em execução\? Todos os dados não salvos serão perdidos.</string>
<string name="applist_details_id">ID do App:</string>
<string name="title_add_pc">Adicionar PC Manualmente</string>
<string name="msg_add_pc">Conectando ao PC…</string>
<string name="addpc_success">Computador adicionado com sucesso</string>
<string name="addpc_unknown_host">Não foi possível encontrar o PC. Certifique-se de que não cometeu um erro de digitação no endereço.</string>
<string name="addpc_enter_ip">Deve inserir um endereço de IP</string>
<string name="addpc_wrong_sitelocal">Esse endereço não parece certo. Deve usar o endereço de IP público do seu roteador para transmitir pela Internet.</string>
<string name="category_basic_settings">Configurações Básicas</string>
<string name="title_resolution_list">Resolução</string>
<string name="summary_resolution_list">Aumente para melhorar a clareza da imagem. Diminua para melhor desempenho em aparelhos de baixo custo e redes mais lentas.</string>
<string name="title_native_res_dialog">Alerta de Resolução Nativa</string>
<string name="title_fps_list">Taxa de quadros por segundo</string>
<string name="title_seekbar_bitrate">Taxa de bits</string>
<string name="summary_seekbar_bitrate">Aumente para uma melhor qualidade de imagem. Diminua para melhorar o desempenho em conexões mais lentas.</string>
<string name="title_checkbox_stretch_video">Esticar vídeo ao ecrã cheio</string>
<string name="resolution_prefix_native">Nativa</string>
<string name="resolution_prefix_native_fullscreen">Ecrã Cheio Nativo</string>
<string name="category_audio_settings">Configurações de Áudio</string>
<string name="summary_audio_config_list">Ativa o som Surround 5.1 ou 7.1 para sistemas de home theater</string>
<string name="category_input_settings">Configurações de Controles</string>
<string name="title_checkbox_touchscreen_trackpad">Usar o ecrã como um trackpad</string>
<string name="summary_checkbox_touchscreen_trackpad">Se ativado, o ecrã sensível ao toque funciona como um trackpad. Se desativado, o ecrã controla diretamente o cursor do rato.</string>
<string name="summary_checkbox_multi_controller">Desmarque esta opção para forçar o gamepad a estar sempre presente</string>
<string name="title_checkbox_vibrate_fallback">Emular suporte rumble com vibração</string>
<string name="title_checkbox_vibrate_osc">Ativar vibração</string>
<string name="summary_checkbox_vibrate_osc">Vibra o seu aparelho para emular rumble nos controles de ecrã</string>
<string name="title_only_l3r3">Mostrar somente L3 e R3</string>
<string name="title_reset_osc">Limpar o layout salvo dos controles de ecrã</string>
<string name="summary_reset_osc">Redefine todos os controles no ecrã para tamanho e posição padrão dele</string>
<string name="summary_osc_opacity">Deixe os controles de ecrã mais/menos transparentes</string>
<string name="title_language_list">Idioma</string>
<string name="summary_language_list">Idioma para ser usado no Moonlight</string>
<string name="title_checkbox_small_icon_mode">Mostrar ícones menores</string>
<string name="summary_checkbox_enable_sops">Permitir que o GFE modifique as configurações do jogo para otimizar a transmissão</string>
<string name="title_checkbox_host_audio">Reproduzir áudio no PC</string>
<string name="title_checkbox_disable_warnings">Desativar mensagens de alerta</string>
<string name="title_video_format">Mudar configurações do HEVC</string>
<string name="summary_enable_hdr">Transmita HDR quando o jogo e a GPU do PC suportarem. O HDR requer uma GPU da série GTX 1000 ou posterior.</string>
<string name="title_enable_perf_overlay">Mostrar status de performance durante a transmissão</string>
<string name="nettest_title_done">Teste de Internet Completo</string>
<string name="nettest_text_inconclusive">O teste de rede não pôde ser executado porque nenhum dos servidores de teste de conexão do Moonlight estava acessível. Verifique a sua conexão com a Internet ou tente novamente mais tarde.</string>
<string name="pairing">A parear…</string>
<string name="pair_pc_offline">Esse computador está offline</string>
<string name="pair_pc_ingame">Esse computador está atualmente num jogo. Deve fechar o jogo antes de parear.</string>
<string name="pair_pairing_msg">Insira o seguinte PIN no PC de destino:</string>
<string name="pair_incorrect_pin">PIN incorreto</string>
<string name="pair_already_in_progress">Pareamento já em andamento</string>
<string name="wol_pc_online">Esse computador está disponível</string>
<string name="wol_no_mac">Não foi possível acordar o PC porque o GFE não enviou um endereço MAC</string>
<string name="wol_waking_pc">Acordando o PC…</string>
<string name="unpairing">Despareando…</string>
<string name="unpair_error">Aparelho não pareado</string>
<string name="error_pc_offline">Esse computador está indisponível</string>
<string name="error_manager_not_running">O serviço ComputerManager não está em execução. Aguarde alguns segundos ou reinicie a app..</string>
<string name="error_unknown_host">Falha ao encontrar o host</string>
<string name="title_setup_guide">Guia de configuração</string>
<string name="title_full_range">Forçar vídeo de gama completa de cores (Experimental)</string>
<string name="conn_establishing_title">Estabelecendo Conexão</string>
<string name="conn_establishing_msg">Iniciando a conexão</string>
<string name="addpc_fail">Não foi possível conectar ao computador especificado. Certifique-se de que as portas necessárias sejam permitidas pelo firewall.</string>
<string name="summary_fps_list">Aumente para uma transmissão de vídeo mais suave. Diminua para melhor desempenho em aparelhos de baixo custo.</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Driver de gamepad USB Xbox 360/One</string>
<string name="title_checkbox_enable_sops">Otimizar configurações de jogo</string>
<string name="summary_enable_post_stream_toast">Exibe uma mensagem com informações de latência após o término da transmissão</string>
<string name="category_help">Ajuda</string>
<string name="summary_setup_guide">Veja instruções sobre como configurar o seu PC para streaming</string>
<string name="resolution_1440p">1440p</string>
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="pacing_latency">Preferir baixa latência</string>
<string name="title_checkbox_mouse_nav_buttons">Ativar os botões de voltar e avançar do rato</string>
<string name="summary_checkbox_mouse_nav_buttons">Ativar esta opção pode bugar o clique com o botão direito em alguns aparelhos com bugs</string>
<string name="title_checkbox_flip_face_buttons">Inverter botões</string>
<string name="title_privacy_policy">Política de privacidade</string>
<string name="summary_privacy_policy">Veja a política de privacidade do Moonlight</string>
<string name="resolution_480p">480p</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>
</resources>
-2
View File
@@ -196,7 +196,5 @@
<string name="audioconf_51surround">Sunet Surround 5.1</string>
<string name="audioconf_71surround">Sunet Surround 7.1</string>
<string name="videoformat_hevcauto">Folosește HEVC doar dacă e stabil</string>
<string name="videoformat_hevcalways">Folosește HEVC mereu (se poate bloca)</string>
<string name="videoformat_hevcnever">Nu folosi HEVC</string>
</resources>
+38 -6
View File
@@ -84,7 +84,7 @@
<!-- Preferences -->
<string name="category_basic_settings">Общие Настройки</string>
<string name="title_resolution_list">Выберите разрешение и частоту кадров</string>
<string name="summary_resolution_list">Выбор слишком высокого значеня для своего устройства может вызвать тормоза или вылеты</string>
<string name="summary_resolution_list">Увеличьте для повышения чёткости изображения. Уменьшите для лучшей производительности на медленных устройствах или сетях.</string>
<string name="title_seekbar_bitrate">Выберите битрейт видео</string>
<string name="summary_seekbar_bitrate">Низкий битрейт уменьшит зависания. Увеличение битрейта улучшит качество изображения.</string>
<string name="title_checkbox_stretch_video">Растягивать видео на весь экран</string>
@@ -184,7 +184,7 @@
<string name="scut_invalid_uuid">Указанный PC недействителен</string>
<string name="scut_invalid_app_id">Указанное приложение недействительно</string>
<string name="suffix_osc_opacity">%</string>
<string name="suffix_seekbar_bitrate_mbps">Мб/с</string>
<string name="suffix_seekbar_bitrate_mbps">Мбит/с</string>
<string name="applist_menu_hide_app">Скрыть приложение</string>
<string name="pcview_menu_test_network">Тестовое подключение к сети</string>
<string name="pcview_menu_header_unknown">Обновление</string>
@@ -213,13 +213,45 @@
<string name="perf_overlay_streamdetails">Видеострим: %1$s %2$.2f FPS</string>
<string name="resolution_prefix_native_fullscreen">Родной полноэкранный режим</string>
<string name="perf_overlay_netlatency">Средняя задержка сети: %1$d мс (дисперсия: %2$d мс)</string>
<!-- Array strings -->
<string name="audioconf_stereo">Стерео</string>
<string name="audioconf_51surround">5.1 Объёмный звук</string>
<string name="audioconf_71surround">7.1 Объёмный звук</string>
<string name="videoformat_hevcauto">Использовать HEVC только если безопасно</string>
<string name="videoformat_auto">Автоматически</string>
<string name="videoformat_hevcalways">Всегда использовать HEVC если доступно</string>
<string name="videoformat_hevcnever">Никогда не использовать HEVC</string>
<string name="pacing_latency">Минимальная задержка</string>
<string name="pacing_balanced">Баланс</string>
<string name="pacing_smoothness">Максимальная плавность (может значительно увеличить задержку)</string>
<string name="title_checkbox_enable_audiofx">Включить поддержку системного эквалайзера</string>
<string name="summary_checkbox_absolute_mouse_mode">Может сделать движения мыши естественней для удаленного рабочего стола, но несовместимо с большинством игр.</string>
<string name="summary_checkbox_reduce_refresh_rate">Сниженная частота обновления может экономить батарею за счет дополнительной задержки видео</string>
<string name="resolution_prefix_native_landscape">(Горизонтальный)</string>
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="fps_120">120 FPS</string>
<string name="frame_conversion_error">Хост-ПК сообщил о критической ошибке кодирования видео.
\n
\nПопробуйте выключить HDR, изменить разрешение стрима или разрешение экрана на хост-ПК.</string>
<string name="summary_checkbox_enable_audiofx">Позволяет работать аудио эффектам во время стрима, но может увеличить задержку звука</string>
<string name="title_setup_guide">Инструкция по настройке</string>
<string name="summary_setup_guide">Посмотреть инструкцию о том как настроить ваш пк для стриминга</string>
<string name="title_troubleshooting">Руководство по устранению неполадок</string>
<string name="summary_frame_pacing">Укажите как сбалансировать задержку и плавностью видео</string>
<string name="summary_privacy_policy">Посмотреть политику конфиденциальности Moonlight</string>
<string name="title_privacy_policy">Политика конфиденциальности</string>
<string name="resolution_360p">360p</string>
<string name="resolution_1080p">1080p</string>
<string name="resolution_1440p">1440p</string>
<string name="summary_troubleshooting">Посмотрите советы по обнаружению и устранению проблем</string>
<string name="category_help">Помощь</string>
<string name="resolution_720p">720p</string>
<string name="resolution_prefix_native_portrait">(Портретный)</string>
<string name="summary_seekbar_deadzone">Некоторые игры могут принудительно увеличить мёртвую зону вместо указанной в Moonlight.</string>
<string name="title_checkbox_absolute_mouse_mode">Режим удалённого рабочего стола для мыши</string>
<string name="title_checkbox_reduce_refresh_rate">Разрешить снижение частоты обновления</string>
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="title_frame_pacing">Скорость вывода/отрисовки кадра</string>
<string name="pacing_balanced_alt">Сбалансированно с лимитом FPS</string>
<string name="resolution_480p">480p</string>
</resources>
+262
View File
@@ -0,0 +1,262 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="scut_deleted_pc">PC raderad</string>
<string name="scut_not_paired">PC inte kopplad</string>
<string name="scut_pc_not_found">PC inte hittad</string>
<string name="scut_invalid_uuid">Den angivna PC:n är inte giltig</string>
<string name="scut_invalid_app_id">Angiven App är inte giltlig</string>
<string name="help_loading_title">Hjälpvisare</string>
<string name="help_loading_msg">Laddar hjälpsida…</string>
<string name="pcview_menu_header_online">Online</string>
<string name="pcview_menu_header_offline">Offline</string>
<string name="pcview_menu_header_unknown">Uppdaterar</string>
<string name="pcview_menu_app_list">Visa alla appar</string>
<string name="pcview_menu_pair_pc">Para ihop med PC</string>
<string name="pcview_menu_unpair_pc">Koppla bort</string>
<string name="pcview_menu_send_wol">Skicka begäran om Wake-On-LAN</string>
<string name="pcview_menu_delete_pc">Radera PC</string>
<string name="pcview_menu_test_network">Testa nätverksanslutning</string>
<string name="pcview_menu_details">Visa detaljer</string>
<string name="pcview_menu_eol">NVIDIA GameStream upphör att fungera</string>
<string name="nettest_title_waiting">Testning av nätverksanslutning</string>
<string name="nettest_text_waiting">Moonlight testar din nätverksanslutning för att avgöra om några nödvändiga portar är blockerade.
\n
\nDetta kan ta några sekunder…</string>
<string name="pair_pc_ingame">Datorn är för närvarande i ett spel. Du måste stänga spelet innan fogning.</string>
<string name="pairing">Fogar…</string>
<string name="pair_pairing_title">Fogning</string>
<string name="pair_pairing_msg">Ange följande PIN-kod på måldatorn:</string>
<string name="pair_pairing_help">Om värddatorn kör Sunshine går du till Sunshine-webbgränssnittet för att ange PIN-koden.</string>
<string name="pair_incorrect_pin">Felaktig PIN-kod</string>
<string name="pair_fail">Fogning misslyckad</string>
<string name="pair_already_in_progress">Fogning redan i utveckling</string>
<string name="wol_pc_online">Datorn är online</string>
<string name="wol_no_mac">Det går inte att väcka datorn eftersom det inte finns någon lagrad MAC-adress</string>
<string name="wol_waking_pc">Väcker dator…</string>
<string name="wol_waking_msg">Det kan ta några sekunder innan datorn vaknar upp. Om den inte gör det, kontrollera att den är korrekt konfigurerad för Wake-On-LAN.</string>
<string name="wol_fail">Misslyckades med att skicka Wake-On-LAN-paket</string>
<string name="unpairing">Bortkopplar…</string>
<string name="unpair_success">Bortkoppling framgångsrik</string>
<string name="unpair_fail">Misslyckad bortkoppling</string>
<string name="unpair_error">Enheten blev inte fogad</string>
<string name="error_pc_offline">Dator är offline</string>
<string name="error_unknown_host">Misslyckades med att lösa värd</string>
<string name="title_decoding_error">Videoavkodare brakade</string>
<string name="message_decoding_error">Moonlight har brakat på grund av en inkompatibilitet med den här enhetens videodekoder. Försök att jämka streaminginställningarna om braket fortsätter.</string>
<string name="title_decoding_reset">Återställning av videoinställningar</string>
<string name="error_usb_prohibited">USB-åtkomst är förbjuden av enhetens administratör. Kontrollera dina Knox- eller MDM-inställningar.</string>
<string name="unable_to_pin_shortcut">Din nuvarande lanseringsprogramvara tillåter inte att du skapar genvägar som är fastlåsta.</string>
<string name="no_video_received_error">Ingen video har tagits emot från värden.</string>
<string name="no_frame_received_error">Din nätverksanslutning fungerar inte bra. Minska inställningen för videobitrate eller prova en snabbare anslutning.</string>
<string name="check_ports_msg">Kontrollera din brandvägg och dina regler för portvidarebefordran för port(er):</string>
<string name="conn_establishing_title">Upprättar fogning</string>
<string name="conn_establishing_msg">Startar fogning</string>
<string name="conn_metered">Varning: Din aktiva nätverksfogning är mätbar!</string>
<string name="conn_client_latency">Genomsnittlig latenstid för ramavkodning:</string>
<string name="conn_client_latency_hw">Latency för hårdvaruavkodare:</string>
<string name="conn_hardware_latency">Genomsnittlig latenstid för maskinvaruavkodning:</string>
<string name="conn_starting">Börjar</string>
<string name="conn_error_title">Fogningsfel</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_msg">Fogningen har förstörts</string>
<string name="yes">Ja</string>
<string name="no">Nej</string>
<string name="lost_connection">Tappade fogning till dator</string>
<string name="title_details">Detaljer</string>
<string name="help">Hjälp</string>
<string name="delete_pc_msg">Är du säker på att du vill ta bort den här datorn\?</string>
<string name="slow_connection_msg">Långsam anslutning till datorn
\nMinska din bithastighet</string>
<string name="poor_connection_msg">Dålig anslutning till datorn</string>
<string name="perf_overlay_streamdetails">Videoström: %1$s %2$.2f FPS</string>
<string name="perf_overlay_decoder">Avkodare: %1$s</string>
<string name="perf_overlay_incomingfps">Inkommande bildfrekvens från nätverket: %1$.2f FPS</string>
<string name="perf_overlay_renderingfps">Renderingens bildfrekvens: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Ramar som tappats av din nätverksanslutning: %1$.2f%%</string>
<string name="perf_overlay_dectime">Genomsnittlig avkodningstid: %1$.2f ms</string>
<string name="applist_connect_msg">Fogar till dator…</string>
<string name="applist_menu_resume">Återuppta session</string>
<string name="applist_menu_quit">Avsluta session</string>
<string name="applist_menu_quit_and_start">Avsluta aktuellt spel och starta</string>
<string name="applist_menu_cancel">Avbryt</string>
<string name="applist_menu_details">Visa detaljer</string>
<string name="applist_menu_scut">Skapa genväg</string>
<string name="applist_menu_tv_channel">Lägg till i kanal</string>
<string name="applist_menu_hide_app">Dölj appen</string>
<string name="applist_refresh_title">Applista</string>
<string name="applist_refresh_msg">Friskar upp appar…</string>
<string name="applist_refresh_error_title">Fel</string>
<string name="applist_refresh_error_msg">Misslyckades att få app lista</string>
<string name="applist_quit_app">Avslutar</string>
<string name="applist_quit_success">Framgångsrikt avslutad</string>
<string name="applist_quit_confirmation">Är du säker på att du vill avsluta den pågående appen\? Alla osparade datamatrial kommer att gå förlorade.</string>
<string name="title_add_pc">Lägg till en dator manuellt</string>
<string name="msg_add_pc">Fogar till datorn…</string>
<string name="addpc_fail">Det går inte att foga till den angivna datorn. Kontrollera att de nödvändiga portarna tillåts genom brandväggen.</string>
<string name="addpc_success">Lyckades lägga till dator</string>
<string name="addpc_unknown_host">Det går inte att lösa PC-adressen. Kontrollera att du inte har skrivit fel i adressen.</string>
<string name="applist_details_id">Applikations identitet:</string>
<string name="addpc_enter_ip">Du måste ange en IP-adress</string>
<string name="addpc_wrong_sitelocal">Den adressen ser inte rätt ut. Du måste använda routerns offentliga IP-adress för att streama via Internet.</string>
<string name="category_basic_settings">Grundinställningar</string>
<string name="title_resolution_list">Videoupplösning</string>
<string name="summary_resolution_list">Öka för att förbättra bildens tydlighet. Sänk för bättre prestanda på mindre avancerade enheter och långsammare nätverk.</string>
<string name="title_fps_list">Videobildfrekvens</string>
<string name="summary_fps_list">Öka för en jämnare videoström. Sänk för bättre prestanda på enheter med lägre prestanda.</string>
<string name="title_seekbar_bitrate">Videobitrate</string>
<string name="suffix_seekbar_bitrate_mbps">Mbit/s</string>
<string name="resolution_prefix_native">Ursprung</string>
<string name="resolution_prefix_native_fullscreen">Ursprungshelskärm</string>
<string name="resolution_prefix_native_landscape">(Landskap)</string>
<string name="resolution_prefix_native_portrait">(Porträtt)</string>
<string name="category_audio_settings">Ljudinställningar</string>
<string name="title_audio_config_list">Konfiguration av surroundljud</string>
<string name="title_checkbox_enable_audiofx">Aktivera stöd för systemets equalizer</string>
<string name="category_input_settings">Inmatningsinställningar</string>
<string name="title_checkbox_touchscreen_trackpad">Använd pekskärmen som en styrplatta</string>
<string name="summary_checkbox_touchscreen_trackpad">Om den är aktiverad fungerar pekskärmen som en styrplatta. Om den är inaktiverad styr pekskärmen direkt muspekaren.</string>
<string name="title_checkbox_multi_controller">Automatiskt upptäckande av närvarande spelkontroll</string>
<string name="title_checkbox_vibrate_fallback">Efterlikna stöd för rumble med vibrationer</string>
<string name="summary_checkbox_vibrate_fallback">Vibrerar enheten för att efterlikna rumble om din spelplatta inte har stöd för det</string>
<string name="summary_seekbar_deadzone">Observera: Vissa spel kan kräva en större dödzon än vad Moonlight är konfigurerat för att använda.</string>
<string name="title_seekbar_deadzone">Jämka analogstickans dödzon</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Drivrutin för Xbox 360/One USB-spelplatta</string>
<string name="summary_checkbox_xb1_driver">Aktiverar en inbyggd USB-drivrutin för enheter som inte har stöd för Xbox-kontroller</string>
<string name="title_checkbox_usb_bind_all">Behärska det ursprungliga stödet för Xbox-spelplatta</string>
<string name="title_checkbox_mouse_emulation">Erterliknande av mus genom spelplatta</string>
<string name="summary_checkbox_mouse_emulation">Om du trycker länge på startknappen skiftar du spelplatta till musläge</string>
<string name="title_checkbox_mouse_nav_buttons">Sätt på musknapparna bakåt och framåt</string>
<string name="summary_checkbox_flip_face_buttons">Skiftar ansiktsknapparna A/B och X/Y för spelplattor och kontroller på skärmen</string>
<string name="title_checkbox_flip_face_buttons">Skifta ansiktsknappar</string>
<string name="title_checkbox_absolute_mouse_mode">Musläget för fjärrskrivbord</string>
<string name="summary_checkbox_absolute_mouse_mode">Detta kan göra musacceleration mer naturligt för fjärrskrivbordsanvändning, men det är oförenligt med många spel.</string>
<string name="category_on_screen_controls_settings">Inställningar för kontroller på skärmen</string>
<string name="title_checkbox_vibrate_osc">Sätt på darrning</string>
<string name="summary_checkbox_vibrate_osc">Darrar din enhet för att ge svar på skärmkontrollerna</string>
<string name="title_only_l3r3">Visa bara L3 och R3</string>
<string name="summary_only_l3r3">Dölj alla synliga knappar utom L3 och R3</string>
<string name="title_reset_osc">Rensa sparad formgivning för kontroller på skärmen</string>
<string name="dialog_title_reset_osc">Återställ formgivning</string>
<string name="dialog_text_reset_osc">Är du säker på att du vill ta bort din sparade layout för skärmenheterna\?</string>
<string name="toast_reset_osc_success">Kontroller på skärmen återställs till ursprungsinställningen</string>
<string name="title_osc_opacity">Jämka genomskinligheten av skärmkontrollerna</string>
<string name="suffix_osc_opacity">%</string>
<string name="title_checkbox_enable_pip">Sätt på bild-i-bild-observatörsläge</string>
<string name="title_language_list">Språk</string>
<string name="summary_language_list">Språk att använda för Moonlight</string>
<string name="title_checkbox_small_icon_mode">Använd liten omslagskonst</string>
<string name="summary_checkbox_small_icon_mode">Mindre lådor i appgallret gör att fler appar syns på skärmen</string>
<string name="category_host_settings">Värdinställningar</string>
<string name="title_checkbox_enable_sops">Optimera spelinställningarna</string>
<string name="summary_checkbox_enable_sops">Tillåt GFE att ändra spelinställningar för optimal strömning</string>
<string name="title_checkbox_host_audio">Spela upp ljud på datorn</string>
<string name="summary_checkbox_host_audio">Spela upp ljud från datorn och den här enheten</string>
<string name="category_advanced_settings">Utvecklade inställningar</string>
<string name="title_unlock_fps">Lås upp alla möjliga bildfrekvenser</string>
<string name="title_checkbox_reduce_refresh_rate">Tillåt minskning av uppdateringsfrekvensen</string>
<string name="title_checkbox_disable_warnings">Ta bort varningsmedelanden</string>
<string name="summary_checkbox_disable_warnings">Ta bort varningsmeddelanden om inmatning på skärmen när du strömmar</string>
<string name="title_disable_frame_drop">Tappa aldrig bildramar</string>
<string name="summary_disable_frame_drop">Kan minska mikrohack på vissa enheter, men kan öka latensen</string>
<string name="title_video_format">Ändra codec-inställningar</string>
<string name="summary_video_format">Nyare codecs kan sänka videobandbreddskraven om din enhet stöder dem. Codec-val kan ignoreras om det inte stöds av värdprogramvaran eller GPU:n.</string>
<string name="title_enable_hdr">Sätt på HDR (Prövning)</string>
<string name="summary_enable_hdr">Strömma HDR när spelet och datorns GPU stöder det. HDR kräver en GPU med stöd för HEVC Main 10-kodning.</string>
<string name="title_full_range">Tvinga video med fullt omfång (Prövning)</string>
<string name="title_enable_perf_overlay">Visa prestandastatistik under ströming</string>
<string name="summary_enable_perf_overlay">Visa information om strömningens duglighet i nutid medans du strömmar</string>
<string name="summary_enable_post_stream_toast">Visa ett meddelande med information om latens när strömmen avslutas</string>
<string name="category_help">Hjälp</string>
<string name="title_setup_guide">Installationsguide</string>
<string name="title_troubleshooting">Vägledning för felsökning</string>
<string name="summary_troubleshooting">Visa gissningar för att utvärdera och åtgärda vanliga strömningsbeskymmer</string>
<string name="title_privacy_policy">Integritetspolicy</string>
<string name="summary_privacy_policy">Visa Moonlights integritetspolicy</string>
<string name="resolution_360p">360p</string>
<string name="resolution_480p">480p</string>
<string name="resolution_720p">720p</string>
<string name="resolution_1440p">1440p</string>
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">5.1 surroundljud</string>
<string name="audioconf_71surround">7.1 surroundljud</string>
<string name="title_frame_pacing">Videorams fart</string>
<string name="pacing_latency">Föredrar lägsta latenstid</string>
<string name="pacing_balanced">Balanserad</string>
<string name="pacing_balanced_alt">Balanserad med FPS-gräns</string>
<string name="pacing_smoothness">Föredrar smidigast video (kan öka latensen avsevärt)</string>
<string name="nettest_title_done">Nätverkstestet fullföljt</string>
<string name="nettest_text_failure">Din enhets aktuella nätverksanslutning verkar blockera Moonlight. Streaming via Internet kanske inte fungerar när du är ansluten till det här nätverket.
\n
\nFöljande nätverksportar blockerades:
\n</string>
<string name="nettest_text_success">Ditt nätverk verkar inte blockera Moonlight. Om du fortfarande har problem med anslutningen kan du kontrollera datorns brandväggsinställningar.
\n
\nOm du försöker streama via Internet installerar du Moonlight Internet Hosting Tool på din dator och kör den medföljande Internet Streaming Tester för att kontrollera datorns Internetanslutning.</string>
<string name="nettest_text_inconclusive">Nätverkstestet kunde inte utföras eftersom ingen av Moonlights servrar för anslutningstestning kunde nås. Kontrollera din internetanslutning eller försök igen senare.</string>
<string name="nettest_text_blocked">Enhetens aktuella nätverksanslutning blockerar Moonlight. Streaming via Internet kanske inte fungerar när du är ansluten till det här nätverket.</string>
<string name="pair_pc_offline">Dator är offline</string>
<string name="error_manager_not_running">Tjänsten ComputerManager körs inte. Vänta några sekunder eller starta om programmet.</string>
<string name="error_404">GFE returnerade ett HTTP 404-fel. Kontrollera att din dator har en GPU som stöds. Användning av fjärrskrivbordsprogram kan också orsaka det här felet. Försök att starta om maskinen eller installera om GFE.</string>
<string name="message_decoding_reset">Enhetens videoavkodare fortsätter att braka vid de valda streaminginställningarna. Dina streaminginställningar har återställts till standardinställningen.</string>
<string name="video_decoder_init_failed">Videodekodern misslyckades med att initialisera. Din enhet kanske inte stöder den valda upplösningen eller bildfrekvensen.</string>
<string name="early_termination_error">Något gick fel på din värddator när du startade strömmen.
\n
\nKontrollera att du inte har något DRM-skyddat innehåll öppet på din värddator. Du kan också försöka starta om din värddator.</string>
<string name="frame_conversion_error">Värddatorn rapporterade ett allvarligt fel i videokodningen.
\n
\nFörsök att inaktivera HDR-läget, ändra streamingupplösningen eller ändra värddatorns skärmupplösning.</string>
<string name="ip_hint">IP-adress för värddatorn</string>
<string name="searching_pc">Söker efter värddatorer i det lokala nätverket...
\n
\n Kontrollera att Sunshine körs på värddatorn eller att GameStream är aktiverat i inställningarna för GeForce Experience SHIELD.</string>
<string name="perf_overlay_netlatency">Genomsnittlig nätverksfördröjning: %1$d ms (varians: %2$d ms)</string>
<string name="applist_quit_fail">Misslyckades att avsluta</string>
<string name="title_native_res_dialog">Varning för ursprunglig upplösning</string>
<string name="text_native_res_dialog">Inbyggd upplösning och/eller FPS kanske inte stöds av streamingservern. Du kommer förmodligen att behöva konfigurera ett matchande anpassat visningsläge för värddatorn manuellt.
\n
\nOm du väljer att skapa en anpassad upplösning i NVIDIAs kontrollpanel för att matcha dina skärminställningar, se till att du har läst och förstått NVIDIAs varning om möjlig bildskärmsskada, PC-instabilitet och andra potentiella problem.
\n
\nVi är inte ansvariga för eventuella problem som uppstår av att skapa en anpassad upplösning på din PC.
\n
\nDet kan vara så att din bildskärm inte stöder en nödvändig bildskärmskonfiguration. Om så är fallet kan du försöka ställa in en virtuell skärm. Slutligen, om din enhet eller värddator inte stöder streaming med en specifik upplösning eller uppdateringsfrekvens, har du tyvärr ingen tur.</string>
<string name="summary_seekbar_bitrate">Öka för bättre bildkvalitet. Minska för att förbättra prestandan på långsammare anslutningar.</string>
<string name="title_checkbox_stretch_video">Sträck ut videon till helskärm</string>
<string name="summary_audio_config_list">Aktivera 5.1 eller 7.1 surroundljud för hemmabiosystem</string>
<string name="summary_checkbox_enable_audiofx">Ljudeffekter kan fungera under streaming, men kan öka ljudfördröjningen</string>
<string name="summary_checkbox_multi_controller">Om du avmarkerar det här alternativet tvingas en spelplatta att alltid finnas med</string>
<string name="summary_checkbox_usb_bind_all">Använd Moonlights USB-drivrutin för alla gamepads som stöds, även om det finns stöd för Xbox-kontroller i original</string>
<string name="summary_checkbox_mouse_nav_buttons">Om du lägger till det här alternativet kan högerklickandet gå sönder på vissa felaktiga enheter</string>
<string name="title_checkbox_show_onscreen_controls">Visa kontrollerna på skärmen</string>
<string name="summary_checkbox_show_onscreen_controls">Visa en virtuell styrenhet på pekskärmen</string>
<string name="summary_reset_osc">Återställ alla kontroller på skärmen till deras standard storlek och position</string>
<string name="dialog_title_osc_opacity">Jämka genomskinligheten</string>
<string name="summary_osc_opacity">Gör kontrollerna på skärmen mer/mindre genomskinliga</string>
<string name="summary_checkbox_enable_pip">Gör det möjligt att se strömmen (men inte att styra den) medan du gör andra saker samtidigt</string>
<string name="category_ui_settings">Inställningar för användargränssnittet</string>
<string name="summary_unlock_fps">Streaming med 90 eller 120 FPS kan minska latenstiden på avancerade enheter, men kan orsaka fördröjning eller instabilitet på enheter som inte har stöd för det</string>
<string name="summary_checkbox_reduce_refresh_rate">Lägre uppdateringsfrekvenser på skärmen kan spara ström på bekostnad av ytterligare videolatens</string>
<string name="summary_full_range">Detta kan leda till förlust av detalj i ljusa och mörka områden om enheten inte visar videoinnehåll med fullt omfång på rätt sätt.</string>
<string name="fps_120">120 FPS</string>
<string name="title_enable_post_stream_toast">Visa meddelande om latenstid efter strömning</string>
<string name="summary_setup_guide">Visa instruktioner om hur du utformar din speldator för strömning</string>
<string name="resolution_1080p">1080p</string>
<string name="fps_60">60 FPS</string>
<string name="summary_frame_pacing">Ange hur du ska balansera videofördröjning och jämnhet</string>
<string name="fps_suffix_fps">FPS</string>
<string name="title_native_fps_dialog">Native FPS varning</string>
<string name="category_gamepad_settings">Spelkontroller inställningar</string>
<string name="title_checkbox_gamepad_motion_sensors">Tillåt användning av spelkontrollens rörelsesensorer</string>
<string name="videoformat_auto">Automatisk (Rekommenderad)</string>
<string name="videoformat_av1always">Föredra AV1 (experimentell)</string>
<string name="videoformat_hevcalways">Föredra HEVC</string>
<string name="videoformat_h264always">Föredra H.264</string>
<string name="perf_overlay_hostprocessinglatency">Värdbearbetningsfördröjning min/max/genomsnitt: %1$.1f/%2$.1f/%3$.1f ms</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_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>
</resources>
+37 -16
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- PC view menu entries -->
<string name="pcview_menu_app_list">Подивитися перелік додатків</string>
<string name="pcview_menu_app_list">Подивитися перелік застосунків</string>
<string name="pcview_menu_pair_pc">Створити пару з пристроєм</string>
<string name="pcview_menu_unpair_pc">Розірвати пару</string>
<string name="pcview_menu_send_wol">Надіслати запит Wake-On-LAN</string>
@@ -27,7 +27,7 @@
<string name="unpair_error">Пристрій не було спарено</string>
<!-- Errors -->
<string name="error_pc_offline">Пристрій вимкнено чи знаходиться поза мережею</string>
<string name="error_manager_not_running">Сервіс ComputerManager не запущено. Будь ласка, зачекайте кілька секунд або перезапустіть додаток.</string>
<string name="error_manager_not_running">Сервіс ComputerManager не запущено. Будь ласка, зачекайте кілька секунд або перезапустіть застосунок.</string>
<string name="error_unknown_host">Неможливо знайти хоста</string>
<string name="error_404">GFE повернув помилку HTTP 404. Переконайтеся що ваш пристрій використовує підтримуваний GPU. Використання програм для віддаленого доступу також може викликати цю помилку. Спробуйте перезавантажити пристрій або перевстановити GFE.</string>
<!-- Start application messages -->
@@ -56,14 +56,14 @@
<string name="applist_menu_quit_and_start">Вийти з поточної гри і запустити</string>
<string name="applist_menu_cancel">Скасувати</string>
<string name="applist_menu_tv_channel">Додати на канал</string>
<string name="applist_refresh_title">Перелік додатків</string>
<string name="applist_refresh_msg">Оновлення додатків…</string>
<string name="applist_refresh_title">Перелік застосунків</string>
<string name="applist_refresh_msg">Оновлення застосунків…</string>
<string name="applist_refresh_error_title">Помилка</string>
<string name="applist_refresh_error_msg">Помилка отримання переліку додатків</string>
<string name="applist_refresh_error_msg">Помилка отримання переліку застосунків</string>
<string name="applist_quit_app">Виходимо з</string>
<string name="applist_quit_success">Успішний вихід з</string>
<string name="applist_quit_fail">Помилка при виході</string>
<string name="applist_quit_confirmation">Ви впевнені, що хочете вийти з запущеного додатку? Усі незбережені дані будуть втрачені.</string>
<string name="applist_quit_confirmation">Ви впевнені, що хочете вийти з запущеного застосунку\? Усі незбережені дані будуть втрачені.</string>
<!-- Add computer manually activity -->
<string name="title_add_pc">Додати пристрій вручну</string>
<string name="msg_add_pc">З\'єднання з пристроєм…</string>
@@ -93,7 +93,7 @@
<string name="title_language_list">Мова</string>
<string name="summary_language_list">Мова, яка буде використовуватися в Moonlight</string>
<string name="title_checkbox_small_icon_mode">Використовувати маленькі іконки</string>
<string name="summary_checkbox_small_icon_mode">Використовувати маленькі іконки в сітці додатків, для відображення більшої кількості елементів на екрані</string>
<string name="summary_checkbox_small_icon_mode">Використовувати маленькі іконки в сітці застосунків, для відображення більшої кількості елементів на екрані</string>
<string name="category_host_settings">Налаштування хоста</string>
<string name="title_checkbox_enable_sops">Оптимізувати ігрові налаштування</string>
<string name="summary_checkbox_enable_sops">Дозволити GFE змінювати налаштування ігор для оптимальної трансляції</string>
@@ -121,7 +121,7 @@
<string name="error_usb_prohibited">USB доступ заборонений адміністратором пристрою. Перевірте налаштування Knox або MDM.</string>
<string name="addpc_wrong_sitelocal">Вказана адреса неправильна. Ви повинні ввести публічну IP-адресу вашого мережника (роутера) для передачі через інтернет.</string>
<string name="title_checkbox_enable_pip">Увімкнути режим перегляду \"Картинка в картинці\"</string>
<string name="summary_checkbox_enable_pip">Дозволяє переглядати трансляцію (але не керувати нею) під час роботи в інших додатках</string>
<string name="summary_checkbox_enable_pip">Дозволяє переглядати стрім (але не контролювати) під час багатозадачності</string>
<string name="title_checkbox_usb_bind_all">Вимкнути рідну підтримку Xbox контролерів від Андроїда</string>
<string name="summary_checkbox_usb_bind_all">Використовувати USB драйвер Moonlight для усіх підтриманих контролерів, навіть якщо існує рідна підтримка</string>
<string name="title_checkbox_mouse_emulation">Емуляція миші через контролер</string>
@@ -148,7 +148,7 @@
<string name="title_details">Деталі</string>
<string name="title_enable_perf_overlay">Увімкнути відображення статистики</string>
<string name="title_unlock_fps">Розблокувати всі можливі частоти кадрів</string>
<string name="applist_details_id">ID додатку:</string>
<string name="applist_details_id">ID застосунку:</string>
<string name="title_checkbox_vibrate_fallback">Емуляція вібровіддачі</string>
<string name="summary_checkbox_vibrate_osc">Вібрація пристрою для емуляції вібровіддачі при екранному управлінні</string>
<string name="summary_checkbox_vibrate_fallback">Вібрує пристрій для емуляції вібровіддачі, якщо під\'єднаний контролер не підтримує її</string>
@@ -169,7 +169,7 @@
<string name="perf_overlay_dectime">Середній час розцифрування: %1$.2f мс</string>
<string name="summary_fps_list">Збільшіть для плавнішого відео потоку. Зменшіть для кращої продуктивності на повільних пристроях.</string>
<string name="scut_invalid_uuid">Зазначений пристрій недійсний</string>
<string name="scut_invalid_app_id">Зазначений додаток недійсний</string>
<string name="scut_invalid_app_id">Зазначений застосунок недійсний</string>
<string name="title_osc_opacity">Змінити прозорість екранних елементів керування</string>
<string name="summary_osc_opacity">Зробити екранні елементи керування більш/менш прозорими</string>
<string name="dialog_title_osc_opacity">Зміна прозорості</string>
@@ -178,9 +178,9 @@
<string name="summary_enable_post_stream_toast">Показувати статистику затримки після закінчення трансляції</string>
<string name="early_termination_error">Щось пішло не так на пристрої хоста при початку трансляції.
\n
\nВпевніться що у вас не відкриті додатки з DRM змістом на пристрої хоста. Ви також можете спробувати перезапустити його.
\nПереконайтеся, що на головному ПК немає відкритого вмісту, захищеного DRM. Ви також можете спробувати перезавантажити головний ПК.
\n
\nЯкщо проблема не виправиться, спробуйте перевстановити драйвера для вашої відео карти та, GeForce Experience якщо встановлено.</string>
\nЯкщо проблема не зникає, спробуйте перевстановити драйвери GPU та GeForce Experience.</string>
<string name="nettest_text_success">Схоже що ваша мережа не блокує Moonlight. Якщо у вас й надалі проблеми з підключенням, перевірте налаштування брандмауера.
\n
\nЯкщо ви намагаєтеся транслювати через Інтернет, встановіть на своєму пристрої Moonlight Internet Hosting Tool, та запустіть випробування мережі щоб перевірити ваше з\'єднання до Інтернету.</string>
@@ -195,7 +195,7 @@
\n
\nЗрештою, пристрої клієнта чи хоста можуть не підтримувати трансляції рідною роздільною здатністю. Якщо це не працює на вашому пристрої, вам на жаль просто не пощастило.</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_streamdetails">Відео трансл: %1$s %2$.2f FPS</string>
<string name="check_ports_msg">Перевірте правила брандмауера та переадресації для наступних портів:</string>
@@ -218,9 +218,8 @@
<string name="pcview_menu_header_offline">Поза мережею</string>
<string name="pcview_menu_header_online">В мережі</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Використовувати HEVC тільки якщо безпечно</string>
<string name="videoformat_hevcalways">Завжди використовувати HEVC якщо доступно</string>
<string name="videoformat_hevcnever">Ніколи не використовувати HEVC</string>
<string name="videoformat_auto">Автоматичний (рекомендовано)</string>
<string name="videoformat_hevcalways">Використовувати HEVC</string>
<string name="title_frame_pacing">Швидкість кадрів відео</string>
<string name="summary_frame_pacing">Укажіть баланс відео затримки та плавності</string>
<string name="pacing_latency">Перевага найменшій затримці</string>
@@ -239,4 +238,26 @@
<string name="audioconf_stereo">Стерео</string>
<string name="audioconf_51surround">5.1 Об\'ємний Звук</string>
<string name="audioconf_71surround">7.1 Об\'ємний Звук</string>
<string name="summary_checkbox_enable_audiofx">Дозволяє аудіоефектам функціонувати під час потокового передавання, але може збільшити затримку звуку</string>
<string name="title_troubleshooting">Гайд з усунення несправностей</string>
<string name="title_privacy_policy">Політика конфіденційності</string>
<string name="summary_troubleshooting">Переглянути поради щодо діагностики та усунення поширених проблем з потоковою передачею</string>
<string name="summary_checkbox_reduce_refresh_rate">Більш низька частота оновлення дисплея може заощадити енергію за рахунок деякої додаткової затримки відео</string>
<string name="summary_seekbar_deadzone">Примітка: Деякі ігри можуть встановлювати більшу мертву зону, ніж та, на яку налаштовано Moonlight.</string>
<string name="title_checkbox_absolute_mouse_mode">Режим миші віддаленого робочого столу</string>
<string name="title_setup_guide">Гайд по налаштуванню</string>
<string name="summary_setup_guide">Переглянути інструкцію, як налаштувати ігровий ПК для стрімінгу</string>
<string name="pacing_balanced_alt">Збалансований з лімітом FPS</string>
<string name="resolution_prefix_native_landscape">(Горизонтальний)</string>
<string name="resolution_prefix_native_portrait">(Портретний)</string>
<string name="title_checkbox_enable_audiofx">Увімкнення підтримки системного еквалайзера</string>
<string name="summary_checkbox_absolute_mouse_mode">Це може зробити прискорення миші більш природним під час використання віддаленого робочого столу, але воно несумісне з багатьма іграми.</string>
<string name="title_checkbox_reduce_refresh_rate">Дозволити зниження частоти оновлення</string>
<string name="category_help">Допомога</string>
<string name="summary_privacy_policy">Переглянути політику конфіденційності Moonlight</string>
<string name="frame_conversion_error">Головний комп\'ютер повідомив про фатальну помилку кодування відео.
\n
\nСпробуйте вимкнути режим HDR, змінити роздільну здатність потокового відео або змінити роздільну здатність дисплея головного комп\'ютера.</string>
<string name="title_full_range">Сила повного спектру відео (експериментальна)</string>
<string name="summary_full_range">Це може призвести до втрати деталей у світлих і темних областях, якщо пристрій не відображає належним чином весь діапазон відеоконтенту.</string>
</resources>
+2
View File
@@ -2,5 +2,7 @@
<style name="AppBaseTheme" parent="android:Theme.Material">
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<!-- Avoid some systems like MIUI which break the visibility of games title -->
<item name="android:forceDarkAllowed">false</item>
</style>
</resources>
+7 -2
View File
@@ -225,7 +225,12 @@
<string name="audioconf_stereo">Stereo</string>
<string name="audioconf_51surround">Âm thanh vòm 5.1</string>
<string name="audioconf_71surround">Âm thanh vòm 7.1</string>
<string name="videoformat_hevcauto">Chỉ sử dụng HEVC nếu ổn định</string>
<string name="videoformat_hevcalways">Luôn sử dụng HEVC (có thể gây crash)</string>
<string name="videoformat_hevcnever">Không bao giờ sử dụng HEVC</string>
<string name="resolution_prefix_native_landscape">(Ngang)</string>
<string name="frame_conversion_error">PC chủ đã gặp lỗi mã hoá video nghiêm trọng.
\n
\nHãy thử tắt chế độ HDR, đổi độ phân giải stream, hoặc đổi độ phân giải màn hình PC chủ.</string>
<string name="title_checkbox_enable_audiofx">Hỗ trợ bộ cân bằng của hệ thống</string>
<string name="summary_checkbox_enable_audiofx">Cho phép hiệu ứng âm thanh hoạt động khi stream, nhưng có thể tăng độ trễ âm thanh</string>
<string name="resolution_prefix_native_portrait">(Dọc)</string>
</resources>
+38 -20
View File
@@ -27,7 +27,7 @@
<string name="pair_already_in_progress"> 配对中,请稍候 </string>
<!-- WOL messages -->
<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_msg">唤醒电脑需要一些时间。如果电脑没有唤醒,请确保 Wake-On-LAN 设置无误。</string>
<string name="wol_fail"> 无法发送Wake-On-LAN数据包 </string>
@@ -42,7 +42,7 @@
<string name="error_unknown_host"> 无法解析主机地址 </string>
<string name="error_404">GFE返回了HTTP 404 错误,确保你的电脑显卡支持串流。使用远程桌面软件同样会引起此错误,请尝试重启电脑或重装GFE。</string>
<string name="title_decoding_error"> 视频解码器崩溃 </string>
<string name="message_decoding_error"> 由于与该设备的视频解码器不兼容,Moonlight已崩溃。确保你电脑上的GFE已更新至最新版本,如果崩溃继续,请尝试调整串流设置。 </string>
<string name="message_decoding_error">由于与该设备的视频解码器不兼容,Moonlight已崩溃。如果崩溃继续,请尝试调整串流设置。</string>
<string name="title_decoding_reset"> 重置视频设置 </string>
<string name="message_decoding_reset"> 由于设备的视频解码器在你选择的串流设置上持续崩溃,已重置你的串流设置。 </string>
<string name="error_usb_prohibited"> 设备管理员已禁止USB访问。请检查您的Knox或MDM设置。 </string>
@@ -60,10 +60,10 @@
<string name="conn_terminated_title"> 连接终结 </string>
<string name="conn_terminated_msg"> 连接已被终结 </string>
<!-- General strings -->
<string name="ip_hint"> 串流电脑的IP地址 </string>
<string name="searching_pc">正在搜寻运行GAMESTREAM的电脑……
<string name="ip_hint">串流电脑的IP地址</string>
<string name="searching_pc">在你的本地网络中搜索串流主机PC...
\n
\n 确保GFE SHIELD设置里的GAMESTREAM已开启</string>
\n 确保Sunshine在主机上运行,或在GeForce Experience SHIELD设置中启用GameStream</string>
<string name="yes"> 确定 </string>
<string name="no"> 取消 </string>
<string name="lost_connection"> 与电脑失去连接 </string>
@@ -165,10 +165,10 @@
<string name="category_advanced_settings"> 高级设置 </string>
<string name="title_disable_frame_drop"> 永不掉帧 </string>
<string name="summary_disable_frame_drop"> 可能会减少在一些设备上的卡顿,但会增加延迟 </string>
<string name="title_video_format"> 更改HEVC设置 </string>
<string name="summary_video_format">HEVC能降低视频带宽需求,但需要较新的设备才能支持</string>
<string name="title_enable_hdr"> 启用 HDR 实验 </string>
<string name="summary_enable_hdr"> 当游戏和显卡支持时以HDR模式串流。 HDR需要GTX 1000系列或更高规格显卡。 </string>
<string name="title_video_format">更改编解码器设置</string>
<string name="summary_video_format">如果您的设备支持较新的编解码器,则可以降低视频带宽要求。如果主机软件或显卡不支持编解码器选择,则可能会忽略编解码器选择。</string>
<string name="title_enable_hdr">启用 HDR (实验性)</string>
<string name="summary_enable_hdr">当游戏和显卡支持时以HDR模式串流。 HDR需要显卡支持 HEVC Main 10 编码。</string>
<string name="title_enable_perf_overlay"> 启用性能信息 </string>
<string name="summary_enable_perf_overlay"> 在串流中显示实时性能信息 </string>
<string name="title_enable_post_stream_toast">串流完毕显示延迟信息</string>
@@ -186,7 +186,7 @@
\n
\n如果您想通过互联网进行流媒体传输,请在您的电脑上安装Moonlight互联网主机工具,并运行附带的互联网流媒体测试器来检查您的电脑的互联网连接。</string>
<string name="nettest_title_done">网络测试完成</string>
<string name="nettest_text_waiting">Moonlight正在测试你的网络连接,以确定NVIDIA GameStream是否被阻止
<string name="nettest_text_waiting">Moonlight正在测试你的网络连接,请确保所需端口没有被屏蔽
\n
\n这可能需要几秒钟……</string>
<string name="nettest_title_waiting">测试网络连接中</string>
@@ -196,21 +196,19 @@
<string name="pcview_menu_header_online">在线</string>
<string name="resolution_prefix_native">本地</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="text_native_res_dialog">本地分辨率模式不受GFE的官方支持,因此不会自动设置主机的显示分辨率。您需要在游戏中手动进行设置
<string name="text_native_res_dialog">流媒体服务器可能不支持原始分辨率或者 FPS。您可能需要手动为主机配置匹配的自定义显示模式
\n
\n如果您选择在NVIDIA控制面板中创建自定义分辨率以匹配设备分辨率,请确保您已阅读并理解NVIDIA关于可能导致显示器损坏电脑不稳定以及其他潜在问题的警告。
\n如果您选择在 NVIDIA 控制面板中创建与屏幕设置相匹配的自定义分辨率,请确保您已阅读并理解 NVIDIA 关于显示器可能损坏电脑不稳定其他潜在问题的警告。
\n
\n对于您在您的电脑上创建自定义分辨率而导致的任何问题,我们概不负责。
\n我们不对因在电脑上创建自定义分辨率而导致的任何问题负责。
\n
\n最后,您的设备或主机电脑可能不支持以本地分辨率串流。如果此模式无法在您的设备上正常运行,那很遗憾您运气欠佳</string>
\n您的显示器可能不支持必要的显示配置。如果是这样,您可以尝试设置虚拟显示器。最后,如果您的设备或主机不支持以特定分辨率或刷新率进行流式传输,那就很不幸了</string>
<string name="title_native_res_dialog">本地分辨率警告</string>
<string name="applist_menu_hide_app">隐藏游戏</string>
<string name="check_ports_msg">请检查您的防火墙和端口转发规则中的端口:</string>
<string name="early_termination_error">开始串流时您的主机电脑出了点问题。
\n
\n请确保没有在主机电脑上开启任何受DRM保护的内容。您也可以尝试重新启动主机电脑。
\n
\n如果问题仍然存在,请尝试重新安装GPU驱动和GFE。</string>
\n请确保没有在主机电脑上开启任何受DRM保护的内容。您也可以尝试重新启动主机电脑。</string>
<string name="no_frame_received_error">您的网络连接质量不佳。请降低视频码率设置或更换更快的网络连接。</string>
<string name="no_video_received_error">没有接收到来自主机的视频。</string>
<string name="video_decoder_init_failed">视频解码器初始化失败。您的设备可能不支持选定的分辨率或帧数。</string>
@@ -222,9 +220,8 @@
<string name="audioconf_stereo">立体声</string>
<string name="audioconf_51surround">5.1环绕声</string>
<string name="audioconf_71surround">7.1环绕声</string>
<string name="videoformat_hevcauto">自动</string>
<string name="videoformat_hevcalways">强制使用HEVC(不稳定)</string>
<string name="videoformat_hevcnever">不使用HEVC</string>
<string name="videoformat_auto">自动(推荐)</string>
<string name="videoformat_hevcalways">首选 HEVC</string>
<string name="title_frame_pacing">视频帧速调节</string>
<string name="resolution_360p">360p</string>
<string name="resolution_480p">480p</string>
@@ -257,4 +254,25 @@
<string name="summary_checkbox_enable_audiofx">串流时允许音效工作,可能会导致音频延迟增加</string>
<string name="title_checkbox_reduce_refresh_rate">允许降低刷新率</string>
<string name="summary_checkbox_reduce_refresh_rate">较低的屏幕刷新率可以在增加一些视频延迟的情况下省电</string>
<string name="frame_conversion_error">主机 PC 报告了致命的视频编码错误。
\n
\n尝试禁用 HDR 模式、更改流分辨率或更改主机 PC 的显示分辨率。</string>
<string name="summary_full_range">如果你的设备无法正确显示全范围视频内容,这会导致明暗区域的细节丢失。</string>
<string name="title_full_range">强制完全动态范围视频 (实验性)</string>
<string name="pair_pairing_help">如果你的主机运行的是 Sunshine,那请前往Sunshine的网页界面输入PIN码。</string>
<string name="pcview_menu_eol">NVIDIA GameStream 终止服务</string>
<string name="perf_overlay_hostprocessinglatency">主机处理延迟最小值/最大值/平均值: %1$.1f/%2$.1f/%3$.1f ms</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_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="videoformat_av1always">首选 AV1(实验性)</string>
<string name="videoformat_h264always">首选 H.264</string>
<string name="toast_controller_type_changed">游戏手柄类型可能会因运动传感器模拟而改变</string>
<string name="summary_checkbox_gamepad_motion_fallback">如果你连接的游戏手柄或 Android 版本不支持游戏手柄传感器,请使用设备的内置运动传感器。
\n注意:启用此选项可能会导致您的游戏手柄在主机上被识别为 PlayStation 4控制器。</string>
<string name="title_checkbox_gamepad_motion_fallback">模拟游戏手柄运动传感器支持</string>
</resources>
+59 -41
View File
@@ -27,7 +27,7 @@
<string name="pair_already_in_progress">正在配對,請稍候</string>
<!-- WOL messages -->
<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_msg">喚醒電腦需要一些時間。如果電腦沒有喚醒,請確保 Wake-On-LAN 設定無誤。</string>
<string name="wol_fail">無法傳送 Wake-On-LAN 資料包</string>
@@ -35,16 +35,16 @@
<string name="unpairing">正在取消配對…</string>
<string name="unpair_success"> 成功取消配對 </string>
<string name="unpair_fail"> 無法配對 </string>
<string name="unpair_error">裝置沒有配對</string>
<string name="unpair_error">裝置尚未配對</string>
<!-- Errors -->
<string name="error_pc_offline">電腦已離線</string>
<string name="error_manager_not_running">ComputerManager 服務未執行。請稍等幾秒或重啟應用程式。</string>
<string name="error_manager_not_running">ComputerManager 服務未執行。請稍等幾秒或重啟應用程式。</string>
<string name="error_unknown_host"> 無法解析主機位址 </string>
<string name="error_404">GFE 回了 HTTP 404 錯誤確保你的電腦顯示卡支援串流。使用遠端桌面軟體同樣會引起此錯誤,請嘗試重啟電腦或重新安裝 GFE。</string>
<string name="title_decoding_error">視訊解碼器崩潰</string>
<string name="message_decoding_error">由於與裝置的視訊解碼器不相容,Moonlight 已崩潰。確保你電腦上的 GFE 已更新至最新版本,如果崩潰繼續,請嘗試調整串流設定。</string>
<string name="error_404">GFE 回了 HTTP 404 錯誤,請確保你的電腦 GPU 支援串流。使用遠端桌面軟體同樣會引起此錯誤,請嘗試重啟電腦或重新安裝 GFE。</string>
<string name="title_decoding_error">視訊解碼器已當機</string>
<string name="message_decoding_error">由於與這個裝置的視訊解碼器不相容,Moonlight 已當機。若當機持續,請嘗試調整串流設定。</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="unable_to_pin_shortcut">您目前的啟動器不允許創建釘選的捷徑。</string>
<!-- Start application messages -->
@@ -56,14 +56,14 @@
<string name="conn_hardware_latency">硬體解碼器平均延時:</string>
<string name="conn_starting">正在啟動</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_msg">連線已終止</string>
<!-- General strings -->
<string name="ip_hint">串流電腦的 IP 位址</string>
<string name="searching_pc">正在搜尋執行 GAMESTREAM 的電腦…
<string name="ip_hint">主機電腦的 IP 位址</string>
<string name="searching_pc">正在您的區域網路中搜尋主機電腦…
\n
\n請確保 GFE SHIELD 設定裡的 GAMESTREAM 已啟用</string>
\n 請確保 Sunshine 正在您的主機電腦中執行,或在 GFE SHIELD 設定中啟用 GAMESTREAM。</string>
<string name="yes"> 確定 </string>
<string name="no"> 取消 </string>
<string name="lost_connection">與電腦失去連線</string>
@@ -74,8 +74,8 @@
\n 請降低位元速率</string>
<string name="poor_connection_msg">與電腦連線不良</string>
<string name="perf_overlay_decoder">解碼器:%1$s</string>
<string name="perf_overlay_incomingfps">網路接收影格%1$.2f FPS</string>
<string name="perf_overlay_renderingfps">渲染影格數%1$.2f FPS</string>
<string name="perf_overlay_incomingfps">網路接收影格速率%1$.2f FPS</string>
<string name="perf_overlay_renderingfps">轉譯影格速率%1$.2f FPS</string>
<string name="perf_overlay_netdrops">網路丟失影格:%1$.2f%%</string>
<string name="perf_overlay_dectime">平均解碼時間:%1$.2f ms</string>
<!-- AppList activity -->
@@ -90,10 +90,10 @@
<string name="applist_refresh_title">遊戲清單</string>
<string name="applist_refresh_msg">正在重新整理…</string>
<string name="applist_refresh_error_title"> 錯誤 </string>
<string name="applist_refresh_error_msg">取得遊戲清單失敗</string>
<string name="applist_refresh_error_msg">無法取得遊戲清單</string>
<string name="applist_quit_app">正在結束</string>
<string name="applist_quit_success">結束成功</string>
<string name="applist_quit_fail">結束失敗</string>
<string name="applist_quit_success">成功結束</string>
<string name="applist_quit_fail">無法結束</string>
<string name="applist_quit_confirmation">您確定要結束執行中的遊戲?所有未儲存的資料將丟失。</string>
<string name="applist_details_id">App ID</string>
<!-- Add computer manually activity -->
@@ -109,11 +109,11 @@
<string name="title_resolution_list">視訊解析度</string>
<string name="summary_resolution_list">高解析度提升圖像清晰度。低解析度提升在低效能裝置和較慢網路中的串流體驗。</string>
<string name="title_fps_list">視訊影格速率</string>
<string name="summary_fps_list">提高影格速率以得更順暢的視訊串流,降低可在低效能裝置上得更好的串流體驗。</string>
<string name="summary_fps_list">提高影格速率以得更順暢的視訊串流,降低可在低效能裝置上得更好的串流體驗。</string>
<string name="title_seekbar_bitrate">視訊位元速率</string>
<string name="summary_seekbar_bitrate">提高位元速率以提升圖像品質,降低可在較慢的網路中得更好的串流體驗。</string>
<string name="summary_seekbar_bitrate">提高位元速率以提升圖像品質,降低可在較慢的網路中得更好的串流體驗。</string>
<string name="title_unlock_fps">解鎖所有可用影格速率</string>
<string name="summary_unlock_fps">以 90 或 120 畫面更新率串流可能會減少在高效能裝置上的網路延時,但在不支援的裝置上造成卡頓或崩潰</string>
<string name="summary_unlock_fps">以 90 或 120 畫面更新率串流可能會減少在高效能裝置上的網路延時,但在不支援的裝置上卡頓或不穩定的狀況</string>
<string name="title_checkbox_stretch_video">將畫面延展至全螢幕</string>
<string name="title_checkbox_disable_warnings">停用錯誤訊息</string>
<string name="summary_checkbox_disable_warnings">停用串流中連線錯誤訊息</string>
@@ -140,7 +140,7 @@
<string name="title_checkbox_mouse_nav_buttons"> 啟用前進後退滑鼠鍵 </string>
<string name="summary_checkbox_mouse_nav_buttons">在一些支援不佳的裝置上啟用此項可能會使其右鍵失效</string>
<string name="title_checkbox_flip_face_buttons">反轉技能鍵</string>
<string name="summary_checkbox_flip_face_buttons">為手把和虛擬控制器交換 A/B 和 X/Y 技能按鍵</string>
<string name="summary_checkbox_flip_face_buttons">為手把和螢幕控制按鈕交換 A/B 和 X/Y 技能按鍵</string>
<string name="category_on_screen_controls_settings">螢幕控制按鈕設定</string>
<string name="title_checkbox_show_onscreen_controls">顯示螢幕控制按鈕</string>
<string name="summary_checkbox_show_onscreen_controls">在觸控式螢幕上顯示一層虛擬控制器</string>
@@ -152,7 +152,7 @@
<string name="summary_reset_osc">重設所有螢幕控制按鈕為預設大小和位置</string>
<string name="dialog_title_reset_osc">重設按鈕版面配置</string>
<string name="dialog_text_reset_osc">你確定要刪除已儲存的螢幕按鈕版面配置嗎?</string>
<string name="toast_reset_osc_success">螢幕按鈕佈局已經重設</string>
<string name="toast_reset_osc_success">螢幕控制按鈕已重設為預設值</string>
<string name="category_ui_settings">使用者介面設定</string>
<string name="title_language_list"> 語言 </string>
<string name="summary_language_list">選擇 Moonlight 顯示的語言</string>
@@ -166,38 +166,36 @@
<string name="category_advanced_settings">進階設定</string>
<string name="title_disable_frame_drop">永不丟失影格</string>
<string name="summary_disable_frame_drop">可能會減少在一些裝置上的卡頓,但會增加延時</string>
<string name="title_video_format">變更 HEVC 設定</string>
<string name="summary_video_format">HEVC 能降低視訊頻寬需求,但需要較新的裝置才能支援</string>
<string name="title_video_format">變更轉碼器設定</string>
<string name="summary_video_format">較新的轉碼器可以降低視訊頻寬需求 (若您的裝置支援)。如果主機軟體或 GPU 不支援,轉碼器選取項目可能會被忽略。</string>
<string name="title_enable_hdr">啟用 HDR (實驗性)</string>
<string name="summary_enable_hdr">遊戲和顯示卡支援時以 HDR 模式串流HDR 需要 GTX 1000 系列或更高規格顯示卡</string>
<string name="summary_enable_hdr">遊戲和 GPU 支援時以 HDR 模式串流HDR 模式需要支援 HEVC Main 10 編碼的 GPU</string>
<string name="title_enable_perf_overlay">串流時顯示效能資訊</string>
<string name="summary_enable_perf_overlay">在串流中顯示即時效能資訊</string>
<string name="title_enable_post_stream_toast">串流後顯示延時資訊</string>
<string name="summary_enable_post_stream_toast">串流結束後顯示延時資訊</string>
<string name="title_osc_opacity">變更螢幕按鈕透明度</string>
<string name="title_osc_opacity">變更螢幕控制按鈕透明度</string>
<string name="dialog_title_osc_opacity">變更不透明度</string>
<string name="suffix_osc_opacity">%</string>
<string name="summary_osc_opacity">螢幕按钮變得更透明/更不透明</string>
<string name="summary_osc_opacity">使螢幕控制按钮變得更透明/更不透明</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="resolution_prefix_native">本機</string>
<string name="text_native_res_dialog">本機解析度模式不受 GFE 的官方支援,因此不會自動設定主機的顯示解析度。您需要在遊戲中手動進行設定
<string name="resolution_prefix_native">原生</string>
<string name="text_native_res_dialog">原生解析度或 FPS 可能不受串流伺服器支援,您可能需要為主機手動設定相符的自訂顯示模式
\n
\n如果您選擇在 NVIDIA 控制面板中建立自訂解析度以符合裝置解析度,請確保您已閱讀並理解 NVIDIA 關於可能導致監視器損毀和電腦不穩定以及其他潛在問題的警告。
\n如果您選擇在 NVIDIA 控制面板中建立自訂解析度以符合您的螢幕設定,請確保您已閱讀並理解 NVIDIA 關於可能導致監視器損毀和電腦不穩定以及其他潛在問題的警告。
\n
\n對於您在您的電腦上建立自訂解析度而導致的任何問題,我們概不負責。
\n
\n最後,您的裝置或主機電腦可能不支援以本機解析度串流。如果此模式在您的裝置上無法正常執行,只能說您運氣欠佳了。</string>
<string name="title_native_res_dialog">本機解析度警告</string>
\n您的顯示器可能不支援必要的顯示組態。如果是這樣,您可以嘗試設定虛擬監視器。最后,如果您的裝置或主機不支援以特定解析度或重新整理速率串流,只能說您運氣欠佳了。</string>
<string name="title_native_res_dialog">原生解析度警告</string>
<string name="applist_menu_hide_app">隱藏遊戲</string>
<string name="check_ports_msg">檢查您的防火牆和通訊埠轉送規則中的通訊埠:</string>
<string name="early_termination_error">開始串流時您的主機電腦出了點問題。
<string name="early_termination_error">您的主機電腦在開始串流時出了點問題。
\n
\n請確保沒有在主機電腦上開啟任何受 DRM 保護的內容。您也可以嘗試重新開機主機電腦。
\n
\n如果問題仍然存在,請嘗試重新安裝 GPU 驅動程式和 GFE。</string>
\n請確保沒有在主機電腦上開啟任何受 DRM 保護的內容。您也可以嘗試重新開機主機電腦。</string>
<string name="no_frame_received_error">您的網路連線品質不佳。降低視訊位元速率設定或更換更快的連線。</string>
<string name="no_video_received_error">沒有接收到來自主機的視訊。</string>
<string name="video_decoder_init_failed">視訊解碼器初始化失敗。您的裝置可能不支援選取的解析度或影格速率。</string>
<string name="video_decoder_init_failed">無法初始化視訊解碼器,您的裝置可能不支援選取的解析度或影格速率。</string>
<string name="nettest_text_blocked">您裝置目前的網路連線封鎖了 Moonlight。連線到該網路時可能無法透過網際網路串流。</string>
<string name="nettest_text_failure">您裝置目前的網路連線似乎封鎖了 Moonlight。連線到該網路時可能無法透過網際網路串流。
\n
@@ -208,7 +206,7 @@
\n
\n如果您是嘗試透過網際網路串流,請在您的電腦上安裝 Moonlight Internet Hosting Tool,然後執行裡面的 Internet Streaming Tester 來檢查電腦的網際網路連線。</string>
<string name="nettest_title_done">網路檢測完畢</string>
<string name="nettest_text_waiting">Moonlight 正在測試您的網路連線以確認 NVIDIA 遊戲串流服務是否被封鎖。
<string name="nettest_text_waiting">Moonlight 正在測試您的網路連線以確認必要連接埠是否被封鎖。
\n
\n可能需要等待一些時間…</string>
<string name="nettest_title_waiting">正在測試網路連線</string>
@@ -218,14 +216,13 @@
<string name="pcview_menu_header_online">線上</string>
<string name="perf_overlay_netlatency">平均網路延時:%1$d ms (抖動:%2$d ms)</string>
<string name="perf_overlay_streamdetails">視訊串流:%1$s %2$.2f FPS</string>
<string name="resolution_prefix_native_fullscreen">本機全螢幕</string>
<string name="resolution_prefix_native_fullscreen">原生全螢幕</string>
<!-- Array strings -->
<string name="audioconf_stereo">立體聲</string>
<string name="audioconf_51surround">5.1 環場音效</string>
<string name="audioconf_71surround">7.1 環場音效</string>
<string name="videoformat_hevcauto">自動</string>
<string name="videoformat_hevcalways">強制使用 HEVC (可能會當機)</string>
<string name="videoformat_hevcnever">不使用 HEVC</string>
<string name="videoformat_auto">自動 (建議)</string>
<string name="videoformat_hevcalways">優先使用 HEVC</string>
<string name="resolution_4k">4K</string>
<string name="fps_30">30 FPS</string>
<string name="fps_60">60 FPS</string>
@@ -258,4 +255,25 @@
<string name="resolution_prefix_native_portrait">(直向)</string>
<string name="title_checkbox_reduce_refresh_rate">允許減小重新整理率</string>
<string name="summary_checkbox_reduce_refresh_rate">更低的顯示器重新整理速率可在犧牲一些額外視訊延遲的狀況下節省電力</string>
<string name="frame_conversion_error">主機電腦回報了一個嚴重的視訊編碼錯誤。
\n
\n嘗試停用 HDR 模式,變更串流解析度,或變更您的主機電腦的顯示器解析度。</string>
<string name="title_full_range">強制全範圍視訊 (實驗性)</string>
<string name="summary_full_range">若您的裝置無法正確地顯示全範圍視訊內容,將會導致淺色區域和深色區域的細節遺失。</string>
<string name="pair_pairing_help">若您的主機電腦正在執行 Sunshine,請導覽至 Sunshine 網頁 UI 並輸入 PIN 碼。</string>
<string name="pcview_menu_eol">NVIDIA GameStream 終止服務</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_checkbox_gamepad_touchpad_as_mouse">一律使用觸摸板控制滑鼠</string>
<string name="summary_checkbox_gamepad_motion_sensors">在使用動態感測器模擬手把時啟用支援的主機以要求動態感測器資料,若動態感測器未在遊戲中使用,停用後可能會輕微降低電力和網路使用量。</string>
<string name="videoformat_h264always">偏好 H.264</string>
<string name="perf_overlay_hostprocessinglatency">主機處理延遲最小值/最大值/平均值:%1$.1f/%2$.1f/%3$.1f ms</string>
<string name="summary_checkbox_gamepad_touchpad_as_mouse">強制手把觸摸板輸入以控制主機滑鼠,即使在使用觸摸板模擬手把時。</string>
<string name="title_checkbox_gamepad_motion_sensors">一律使用手把動態感測器</string>
<string name="videoformat_av1always">偏好 AV1 (實驗性)</string>
<string name="toast_controller_type_changed">手把類型可能會因動態感測器模擬而變更</string>
<string name="summary_checkbox_gamepad_motion_fallback">如果您連線的手把或 Android 版本不支援手把感測器,請使用裝置內建的動態感測器。
\n注意:啟用此選項可能會導致您的手把在主機被辨識為 PlayStation 控制器。</string>
<string name="title_checkbox_gamepad_motion_fallback">模擬手把動態感測器支援</string>
</resources>
+12 -2
View File
@@ -64,6 +64,10 @@
<item>Magyar</item>
<item>Ελληνικά</item>
<item>Português do Brasil</item>
<item>Čeština</item>
<item>עִבְרִית</item>
<item>Svenska</item>
<item>Indonesia</item>
</string-array>
<string-array name="language_values" translatable="false">
<item>default</item>
@@ -85,15 +89,21 @@
<item>hu</item>
<item>el</item>
<item>pt-BR</item>
<item>cs</item>
<item>iw</item>
<item>sv</item>
<item>in</item>
</string-array>
<string-array name="video_format_names">
<item>@string/videoformat_hevcauto</item>
<item>@string/videoformat_auto</item>
<item>@string/videoformat_av1always</item>
<item>@string/videoformat_hevcalways</item>
<item>@string/videoformat_hevcnever</item>
<item>@string/videoformat_h264always</item>
</string-array>
<string-array name="video_format_values" translatable="false">
<item>auto</item>
<item>forceav1</item>
<item>forceh265</item>
<item>neverh265</item>
</string-array>
+39 -19
View File
@@ -22,10 +22,11 @@
<string name="pcview_menu_delete_pc">Delete PC</string>
<string name="pcview_menu_test_network">Test Network Connection</string>
<string name="pcview_menu_details">View Details</string>
<string name="pcview_menu_eol">NVIDIA GameStream End-of-Service</string>
<!-- Network test strings -->
<string name="nettest_title_waiting">Testing Network Connection</string>
<string name="nettest_text_waiting">Moonlight is testing your network connection to determine if NVIDIA GameStream is blocked.\n\nThis may take a few seconds…</string>
<string name="nettest_text_waiting">Moonlight is testing your network connection to determine if any required ports are blocked.\n\nThis may take a few seconds…</string>
<string name="nettest_title_done">Network Test Complete</string>
<string name="nettest_text_success">Your network does not appear to be blocking Moonlight. If you still have trouble connecting, check your PC\'s firewall settings.\n\nIf you are trying to stream over the Internet, install the Moonlight Internet Hosting Tool on your PC and run the included Internet Streaming Tester to check your PC\'s Internet connection.</string>
<string name="nettest_text_inconclusive">The network test could not be performed because none of Moonlight\'s connection testing servers were reachable. Check your Internet connection or try again later.</string>
@@ -38,13 +39,14 @@
<string name="pair_pc_ingame">Computer is currently in a game. You must close the game before pairing.</string>
<string name="pair_pairing_title">Pairing</string>
<string name="pair_pairing_msg">Please enter the following PIN on the target PC:</string>
<string name="pair_pairing_help">If your host PC is running Sunshine, navigate to the Sunshine web UI to enter the PIN.</string>
<string name="pair_incorrect_pin">Incorrect PIN</string>
<string name="pair_fail">Pairing failed</string>
<string name="pair_already_in_progress">Pairing already in progress</string>
<!-- WOL messages -->
<string name="wol_pc_online">Computer is online</string>
<string name="wol_no_mac">Unable to wake PC because GFE didn\'t send a MAC address</string>
<string name="wol_no_mac">Unable to wake PC because there is no stored MAC address</string>
<string name="wol_waking_pc">Waking PC…</string>
<string name="wol_waking_msg">It may take a few seconds for your PC to wake up.
If it doesn\'t, make sure it\'s configured properly for Wake-On-LAN.
@@ -65,7 +67,7 @@
Using remote desktop software can also cause this error. Try rebooting your machine or reinstalling GFE.
</string>
<string name="title_decoding_error">Video Decoder Crashed</string>
<string name="message_decoding_error">Moonlight has crashed due to an incompatibility with this device\'s video decoder. Ensure GeForce Experience is updated to the latest version on your PC. Try adjusting the streaming settings if the crashes continue.</string>
<string name="message_decoding_error">Moonlight has crashed due to an incompatibility with this device\'s video decoder. Try adjusting the streaming settings if the crashes continue.</string>
<string name="title_decoding_reset">Video Settings Reset</string>
<string name="message_decoding_reset">Your device\'s video decoder continues to crash at your selected streaming settings. Your streaming settings have been reset to default.</string>
<string name="error_usb_prohibited">USB access is prohibited by your device administrator. Check your Knox or MDM settings.</string>
@@ -73,7 +75,8 @@
<string name="video_decoder_init_failed">Video decoder failed to initialize. Your device may not support the selected resolution or frame rate.</string>
<string name="no_video_received_error">No video received from host.</string>
<string name="no_frame_received_error">Your network connection isn\'t performing well. Reduce your video bitrate setting or try a faster connection.</string>
<string name="early_termination_error">Something went wrong on your host PC when starting the stream.\n\nMake sure you don\'t have any DRM-protected content open on your host PC. You can also try restarting your host PC.\n\nIf the issue persists, try reinstalling your GPU drivers and GeForce Experience.</string>
<string name="early_termination_error">Something went wrong on your host PC when starting the stream.\n\nMake sure you don\'t have any DRM-protected content open on your host PC. You can also try restarting your host PC.</string>
<string name="frame_conversion_error">The host PC reported a fatal video encoding error.\n\nTry disabling HDR mode, changing the streaming resolution, or changing your host PC\'s display resolution.</string>
<string name="check_ports_msg">Check your firewall and port forwarding rules for port(s):</string>
<!-- Start application messages -->
@@ -90,9 +93,9 @@
<string name="conn_terminated_msg">The connection was terminated</string>
<!-- General strings -->
<string name="ip_hint">IP address of GeForce PC</string>
<string name="searching_pc">Searching for PCs with GameStream running…\n\n
Ensure GameStream is enabled in the GeForce Experience SHIELD settings.</string>
<string name="ip_hint">IP address of host PC</string>
<string name="searching_pc">Searching for host PCs on your local network…\n\n
Ensure Sunshine is running on your host PC or GameStream is enabled in the GeForce Experience SHIELD settings.</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="lost_connection">Lost connection to PC</string>
@@ -105,6 +108,7 @@
<string name="perf_overlay_decoder">Decoder: %1$s</string>
<string name="perf_overlay_incomingfps">Incoming frame rate from network: %1$.2f FPS</string>
<string name="perf_overlay_renderingfps">Rendering frame rate: %1$.2f FPS</string>
<string name="perf_overlay_hostprocessinglatency">Host processing latency min/max/average: %1$.1f/%2$.1f/%3$.1f ms</string>
<string name="perf_overlay_netdrops">Frames dropped by your network connection: %1$.2f%%</string>
<string name="perf_overlay_netlatency">Average network latency: %1$d ms (variance: %2$d ms)</string>
<string name="perf_overlay_dectime">Average decoding time: %1$.2f ms</string>
@@ -143,7 +147,7 @@
<string name="title_resolution_list">Video resolution</string>
<string name="summary_resolution_list">Increase to improve image clarity. Decrease for better performance on lower end devices and slower networks.</string>
<string name="title_native_res_dialog">Native Resolution Warning</string>
<string name="text_native_res_dialog">Native resolution modes are not officially supported by GeForce Experience, so it will not set your host display resolution itself. You will need to set it manually while in game.\n\nIf you choose to create a custom resolution in NVIDIA Control Panel to match your device resolution, please ensure you have read and understood NVIDIA\'s warning regarding possible monitor damage, PC instability, and other potential problems.\n\nWe are not responsible for any problems resulting from creating a custom resolution on your PC.\n\nFinally, your device or host PC may not support streaming at native resolution. If it doesn\'t work on your device, you\'re just out of luck unfortunately.</string>
<string name="text_native_res_dialog">Native resolution and/or FPS may not be supported by the streaming server. You will probably need to configure a matching custom display mode for the host PC manually.\n\nIf you choose to create a custom resolution in NVIDIA Control Panel to match your screen settings, please ensure you have read and understood NVIDIA\'s warning regarding possible monitor damage, PC instability, and other potential problems.\n\nWe are not responsible for any problems resulting from creating a custom resolution on your PC.\n\nIt may be that your monitor does not support a necessary display configuration. If so, you may try to set up a virtual monitor. Finally, if your device or host PC does not support streaming at a specific resolution or refresh rate, you\'re out of luck unfortunately.</string>
<string name="title_fps_list">Video frame rate</string>
<string name="summary_fps_list">Increase for a smoother video stream. Decrease for better performance on lower end devices.</string>
<string name="title_seekbar_bitrate">Video bitrate</string>
@@ -154,6 +158,8 @@
<string name="resolution_prefix_native_fullscreen">Native Full-Screen</string>
<string name="resolution_prefix_native_landscape">(Landscape)</string>
<string name="resolution_prefix_native_portrait">(Portrait)</string>
<string name="fps_suffix_fps">FPS</string>
<string name="title_native_fps_dialog">Native FPS Warning</string>
<string name="category_audio_settings">Audio Settings</string>
<string name="title_audio_config_list">Surround sound configuration</string>
@@ -161,9 +167,7 @@
<string name="title_checkbox_enable_audiofx">Enable system equalizer support</string>
<string name="summary_checkbox_enable_audiofx">Allows audio effects to function while streaming, but may increase audio latency</string>
<string name="category_input_settings">Input Settings</string>
<string name="title_checkbox_touchscreen_trackpad">Use the touchscreen as a trackpad</string>
<string name="summary_checkbox_touchscreen_trackpad">If enabled, the touchscreen acts like a trackpad. If disabled, the touchscreen directly controls the mouse cursor.</string>
<string name="category_gamepad_settings">Gamepad Settings</string>
<string name="title_checkbox_multi_controller">Automatic gamepad presence detection</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>
@@ -177,12 +181,22 @@
<string name="summary_checkbox_usb_bind_all">Use Moonlight\'s USB driver for all supported gamepads, even if native Xbox controller support is present</string>
<string name="title_checkbox_mouse_emulation">Mouse emulation via gamepad</string>
<string name="summary_checkbox_mouse_emulation">Long pressing the Start button will switch the gamepad into mouse mode</string>
<string name="title_checkbox_mouse_nav_buttons">Enable back and forward mouse buttons</string>
<string name="summary_checkbox_mouse_nav_buttons">Enabling this option may break right clicking on some buggy devices</string>
<string name="title_checkbox_flip_face_buttons">Flip face buttons</string>
<string name="summary_checkbox_flip_face_buttons">Switches the face buttons A/B and X/Y for gamepads and the on-screen controls</string>
<string name="title_checkbox_gamepad_touchpad_as_mouse">Always control mouse with touchpad</string>
<string name="summary_checkbox_gamepad_touchpad_as_mouse">Forces gamepad touchpad input to control the host mouse, even when emulating a gamepad with a touchpad.</string>
<string name="title_checkbox_gamepad_motion_sensors">Allow use of gamepad motion sensors</string>
<string name="summary_checkbox_gamepad_motion_sensors">Enables supported hosts to request motion sensor data when emulating a gamepad with motion sensors. Disabling may slightly reduce power and network usage if motion sensors are not being used in game.</string>
<string name="title_checkbox_gamepad_motion_fallback">Emulate gamepad motion sensor support</string>
<string name="summary_checkbox_gamepad_motion_fallback">Uses your device\'s built-in motion sensors if gamepad sensors are not supported by your connected gamepad or your Android version.\nNote: Enabling this option may cause your gamepad to appear as a PlayStation controller on the host.</string>
<string name="category_input_settings">Input Settings</string>
<string name="title_checkbox_touchscreen_trackpad">Use the touchscreen as a trackpad</string>
<string name="summary_checkbox_touchscreen_trackpad">If enabled, the touchscreen acts like a trackpad. If disabled, the touchscreen directly controls the mouse cursor.</string>
<string name="title_checkbox_absolute_mouse_mode">Remote desktop mouse mode</string>
<string name="summary_checkbox_absolute_mouse_mode">This can make mouse acceleration behave more naturally for remote desktop usage, but it is incompatible with many games.</string>
<string name="title_checkbox_mouse_nav_buttons">Enable back and forward mouse buttons</string>
<string name="summary_checkbox_mouse_nav_buttons">Enabling this option may break right clicking on some buggy devices</string>
<string name="category_on_screen_controls_settings">On-screen Controls Settings</string>
<string name="title_checkbox_show_onscreen_controls">Show on-screen controls</string>
@@ -224,10 +238,12 @@
<string name="summary_checkbox_disable_warnings">Disable on-screen connection warning messages while streaming</string>
<string name="title_disable_frame_drop">Never drop frames</string>
<string name="summary_disable_frame_drop">May reduce micro-stuttering on some devices, but can increase latency</string>
<string name="title_video_format">Change HEVC settings</string>
<string name="summary_video_format">HEVC lowers video bandwidth requirements but requires a newer device</string>
<string name="title_video_format">Change codec settings</string>
<string name="summary_video_format">Newer codecs can lower video bandwidth requirements if your device supports them. Codec selections may be ignored if not supported by the host software or GPU.</string>
<string name="title_enable_hdr">Enable HDR (Experimental)</string>
<string name="summary_enable_hdr">Stream HDR when the game and PC GPU support it. HDR requires a GTX 1000 series GPU or later.</string>
<string name="summary_enable_hdr">Stream HDR when the game and PC GPU support it. HDR requires a GPU with HEVC Main 10 encoding support.</string>
<string name="title_full_range">Force full range video (Experimental)</string>
<string name="summary_full_range">This will cause loss of detail in light and dark areas if your device doesn\'t properly display full range video content.</string>
<string name="title_enable_perf_overlay">Show performance stats while streaming</string>
<string name="summary_enable_perf_overlay">Display real-time stream performance information while streaming</string>
<string name="title_enable_post_stream_toast">Show latency message after streaming</string>
@@ -241,6 +257,9 @@
<string name="title_privacy_policy">Privacy policy</string>
<string name="summary_privacy_policy">View Moonlight\'s privacy policy</string>
<!-- Toasts -->
<string name="toast_controller_type_changed">Gamepad type may be changed due to motion sensor emulation</string>
<!-- Array strings -->
<string name="resolution_360p">360p</string>
<string name="resolution_480p">480p</string>
@@ -258,9 +277,10 @@
<string name="audioconf_51surround">5.1 Surround Sound</string>
<string name="audioconf_71surround">7.1 Surround Sound</string>
<string name="videoformat_hevcauto">Automatic</string>
<string name="videoformat_hevcalways">Always use HEVC (may crash)</string>
<string name="videoformat_hevcnever">Never use HEVC</string>
<string name="videoformat_auto">Automatic (Recommended)</string>
<string name="videoformat_av1always">Prefer AV1 (Experimental)</string>
<string name="videoformat_hevcalways">Prefer HEVC</string>
<string name="videoformat_h264always">Prefer H.264</string>
<string name="title_frame_pacing">Video frame pacing</string>
<string name="summary_frame_pacing">Specify how to balance video latency and smoothness</string>
+4
View File
@@ -19,4 +19,8 @@
<locale android:name="hu"/>
<locale android:name="el"/>
<locale android:name="pt-BR"/>
<locale android:name="cs"/>
<locale android:name="iw"/>
<locale android:name="sv"/>
<locale android:name="in"/>
</locale-config>
+35 -12
View File
@@ -55,8 +55,8 @@
android:summary="@string/summary_checkbox_enable_audiofx"
android:defaultValue="false" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/category_input_settings"
android:key="category_input_settings">
<PreferenceCategory android:title="@string/category_gamepad_settings"
android:key="category_gamepad_settings">
<com.limelight.preferences.SeekBarPreference
android:key="seekbar_deadzone"
android:defaultValue="7"
@@ -64,21 +64,11 @@
android:summary="@string/summary_seekbar_deadzone"
android:text="@string/suffix_seekbar_deadzone"
android:title="@string/title_seekbar_deadzone"/>
<CheckBoxPreference
android:key="checkbox_touchscreen_trackpad"
android:title="@string/title_checkbox_touchscreen_trackpad"
android:summary="@string/summary_checkbox_touchscreen_trackpad"
android:defaultValue="true" />
<CheckBoxPreference
android:key="checkbox_multi_controller"
android:title="@string/title_checkbox_multi_controller"
android:summary="@string/summary_checkbox_multi_controller"
android:defaultValue="true" />
<CheckBoxPreference
android:key="checkbox_mouse_nav_buttons"
android:title="@string/title_checkbox_mouse_nav_buttons"
android:summary="@string/summary_checkbox_mouse_nav_buttons"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_usb_driver"
android:title="@string/title_checkbox_xb1_driver"
@@ -105,6 +95,34 @@
android:title="@string/title_checkbox_flip_face_buttons"
android:summary="@string/summary_checkbox_flip_face_buttons"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_gamepad_touchpad_as_mouse"
android:title="@string/title_checkbox_gamepad_touchpad_as_mouse"
android:summary="@string/summary_checkbox_gamepad_touchpad_as_mouse"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_gamepad_motion_sensors"
android:title="@string/title_checkbox_gamepad_motion_sensors"
android:summary="@string/summary_checkbox_gamepad_motion_sensors"
android:defaultValue="true" />
<CheckBoxPreference
android:key="checkbox_gamepad_motion_fallback"
android:title="@string/title_checkbox_gamepad_motion_fallback"
android:summary="@string/summary_checkbox_gamepad_motion_fallback"
android:defaultValue="false" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/category_input_settings"
android:key="category_input_settings">
<CheckBoxPreference
android:key="checkbox_touchscreen_trackpad"
android:title="@string/title_checkbox_touchscreen_trackpad"
android:summary="@string/summary_checkbox_touchscreen_trackpad"
android:defaultValue="true" />
<CheckBoxPreference
android:key="checkbox_mouse_nav_buttons"
android:title="@string/title_checkbox_mouse_nav_buttons"
android:summary="@string/summary_checkbox_mouse_nav_buttons"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_absolute_mouse_mode"
android:title="@string/title_checkbox_absolute_mouse_mode"
@@ -211,6 +229,11 @@
android:title="@string/title_enable_hdr"
android:summary="@string/summary_enable_hdr"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_full_range"
android:title="@string/title_full_range"
android:summary="@string/summary_full_range"
android:defaultValue="false" />
<CheckBoxPreference
android:key="checkbox_enable_perf_overlay"
android:title="@string/title_enable_perf_overlay"
@@ -38,7 +38,8 @@ public class EvdevCaptureProvider extends InputCaptureProvider {
public void run() {
int deltaX = 0;
int deltaY = 0;
byte deltaScroll = 0;
byte deltaVScroll = 0;
byte deltaHScroll = 0;
// Bind a local listening socket for evdevreader to connect to
try {
@@ -109,15 +110,22 @@ public class EvdevCaptureProvider extends InputCaptureProvider {
break;
}
// Note: The EvdevReader process already filters input events when grabbing
// is not enabled, so we don't need to that here.
switch (event.type) {
case EvdevEvent.EV_SYN:
if (deltaX != 0 || deltaY != 0) {
listener.mouseMove(deltaX, deltaY);
deltaX = deltaY = 0;
}
if (deltaScroll != 0) {
listener.mouseScroll(deltaScroll);
deltaScroll = 0;
if (deltaVScroll != 0) {
listener.mouseVScroll(deltaVScroll);
deltaVScroll = 0;
}
if (deltaHScroll != 0) {
listener.mouseHScroll(deltaHScroll);
deltaHScroll = 0;
}
break;
@@ -129,8 +137,11 @@ public class EvdevCaptureProvider extends InputCaptureProvider {
case EvdevEvent.REL_Y:
deltaY = event.value;
break;
case EvdevEvent.REL_HWHEEL:
deltaHScroll = (byte) event.value;
break;
case EvdevEvent.REL_WHEEL:
deltaScroll = (byte) event.value;
deltaVScroll = (byte) event.value;
break;
}
break;
@@ -223,35 +234,8 @@ public class EvdevCaptureProvider extends InputCaptureProvider {
}
@Override
public void enableCapture() {
super.enableCapture();
if (!started) {
// Start the handler thread if it's our first time
// capturing
handlerThread.start();
started = true;
}
else {
// This may be called on the main thread
runInNetworkSafeContextSynchronously(new Runnable() {
@Override
public void run() {
// Send a request to regrab if we're already capturing
if (!shutdown && evdevOut != null) {
try {
evdevOut.write(REGRAB_REQUEST);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
@Override
public void disableCapture() {
super.disableCapture();
public void showCursor() {
super.showCursor();
// This may be called on the main thread
runInNetworkSafeContextSynchronously(new Runnable() {
@Override
@@ -267,6 +251,39 @@ public class EvdevCaptureProvider extends InputCaptureProvider {
});
}
@Override
public void hideCursor() {
super.hideCursor();
// This may be called on the main thread
runInNetworkSafeContextSynchronously(new Runnable() {
@Override
public void run() {
// Send a request to regrab if we're already capturing
if (started && !shutdown && evdevOut != null) {
try {
evdevOut.write(REGRAB_REQUEST);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
@Override
public void enableCapture() {
if (!started) {
// Start the handler thread if it's our first time
// capturing
handlerThread.start();
started = true;
}
// Call the superclass only after we've started the handler thread.
// It will invoke hideCursor() when we call it.
super.enableCapture();
}
@Override
public void destroy() {
// We need to stop the process in this context otherwise
@@ -13,6 +13,7 @@ public class EvdevEvent {
/* Relative axes */
public static final short REL_X = 0x00;
public static final short REL_Y = 0x01;
public static final short REL_HWHEEL = 0x06;
public static final short REL_WHEEL = 0x08;
/* Buttons */

Some files were not shown because too many files have changed in this diff Show More