Compare commits

...

285 Commits

Author SHA1 Message Date
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
Cameron Gutman e8ea2a8ec1 Version 10.8.4 2022-09-22 23:17:58 -05:00
Cameron Gutman 9ed3b3a9df Fixed streaming on certain devices with GFE 3.26 2022-09-22 23:16:40 -05:00
Cameron Gutman 12487553de Version 10.8.2 2022-09-22 21:57:42 -05:00
Cameron Gutman 9c1a618b4a Fix stuck analog stick when a touch event is cancelled
This can happen if a stylus hover event is received while touching an OSC element
2022-09-21 01:11:45 -05:00
Cameron Gutman ac0e784417 Make StreamView transparent to touch events and handle everything in the background view
This is much simpler than trying to play games with touch handling between 2 views
2022-09-21 01:07:49 -05:00
Cameron Gutman 48cab6b203 Allow multi-finger gestures and absolute motion to pass seamlessly between the StreamView and background view 2022-09-21 00:21:43 -05:00
Cameron Gutman e1c0472069 Properly split touch events between regions outside the StreamView and the OSC
This restores the ability to use area outside the StreamView for the virtual trackpad and adds the ability to use OSC and the non-StreamView region for input at the same time.

Fixes #1129
2022-09-20 22:29:54 -05:00
Cameron Gutman 2c498ce707 Throw a RendererException instead of a bare IllegalStateException upon codec recovery failure 2022-09-20 21:43:35 -05:00
Cameron Gutman bc483edb29 Interrupt codec recovery when stopping the decoder 2022-09-18 18:53:37 -05:00
Cameron Gutman 9762f4c412 Only throw the codec exception on the last configuration attempt 2022-09-18 18:47:01 -05:00
Cameron Gutman 5bfce88fc5 Fix recovery timeout if no output frames are being received 2022-09-18 18:37:33 -05:00
Cameron Gutman 94ef66994d Trigger the decoder crash dialog if all recovery attempts fail 2022-09-18 18:29:45 -05:00
Cameron Gutman 257c29daca Improve handling of concurrent recoverable and non-recoverable errors and surface loss 2022-09-18 18:25:29 -05:00
Cameron Gutman 173483eb84 Only catch IllegalStateException or subclasses 2022-09-18 17:42:37 -05:00
Cameron Gutman 06099b2663 Only try to recover from CodecExceptions or IllegalStateExceptions 2022-09-18 00:20:41 -05:00
Cameron Gutman 33c1f0a71c Fix decoding crash if encoder didn't send VUI parameters 2022-09-18 00:04:29 -05:00
Cameron Gutman a3d78f1d80 Merge remote-tracking branch 'origin/weblate' 2022-09-17 23:32:55 -05:00
Cameron Gutman c573d213f8 Allow FFmpeg decoder on Waydroid 2022-09-17 14:51:03 -05:00
Cameron Gutman c72707aef9 Don't begin codec recovery if stopping 2022-09-17 13:52:22 -05:00
Cameron Gutman 313ef06c86 Only exclude touch events from non-view processing
Mouse events that go out of the StreamView area are okay
2022-09-17 13:36:44 -05:00
Cameron Gutman 6b79340c15 Don't handle motion events outside of Views to avoid spurious stream input while using OSC 2022-09-17 13:34:14 -05:00
Cameron Gutman d9a5b29372 Fix OSC handling of touches outside the StreamView 2022-09-17 13:32:40 -05:00
Cameron Gutman d2b0e093fc Reduce power by avoiding resends when OSC state is not changing 2022-09-17 13:07:52 -05:00
Cameron Gutman 945e563912 Switch to a Handler for gamepad mouse emulation 2022-09-17 12:55:15 -05:00
Cameron Gutman a7efa379eb Switch to a Handler for OSC retransmission 2022-09-16 18:21:56 -05:00
Cameron Gutman d04df4ebe5 Fix D-Pad buttons not releasing until all D-Pad input has ceased 2022-09-16 17:41:52 -05:00
Cameron Gutman 2a2c84ef3a Implement fallbacks for a failed codec restart or reset 2022-09-16 03:48:49 -05:00
Cameron Gutman bc97db893a Allow recovery of IllegalStateExceptions for older versions of Android 2022-09-16 03:28:57 -05:00
Cameron Gutman f216834df7 Limit the number of codec recovery attempts 2022-09-16 03:27:22 -05:00
Cameron Gutman be25a7d594 Fix a number of bugs in new codec recovery code 2022-09-16 03:19:36 -05:00
Cameron Gutman 10f43e8024 Try to adjust decoder exception to comply with Google Play crash message filtering 2022-09-16 00:32:34 -05:00
Cameron Gutman bbb3e8d071 Only catch RuntimeExceptions for decoders to avoid eating important exceptions 2022-09-16 00:26:02 -05:00
Cameron Gutman 4c3af35156 Update AGP to 7.3.0 2022-09-16 00:09:22 -05:00
Cameron Gutman 8656228014 Break out of wait on InterruptedException 2022-09-16 00:09:09 -05:00
Cameron Gutman 03f9ea8435 Use Handlers instead of Timers for one-shot events 2022-09-16 00:08:48 -05:00
Cameron Gutman 9cf27d8fb1 Don't throw exceptions during codec recovery 2022-09-15 02:16:24 -05:00
Cameron Gutman d1b24ea6af Consolidate touch tracking timers 2022-09-15 02:05:40 -05:00
Cameron Gutman b07ffbde29 Consolidate OSC timers 2022-09-15 01:59:29 -05:00
Cameron Gutman 1673236940 Abort if the decoder doesn't recover within 5 seconds 2022-09-15 01:37:10 -05:00
Cameron Gutman 06861a2d17 Add support for recovering from non-transient CodecExceptions 2022-09-15 01:15:15 -05:00
Cameron Gutman ef7ac62f97 Improve handling of transient CodecExceptions 2022-09-15 00:08:06 -05:00
Cameron Gutman 245a9f2751 Try a new input buffer if getInputBuffer() returns null 2022-09-14 23:54:07 -05:00
Cameron Gutman 1d38f158b5 Fix crash after the next fetchNextInputBuffer() if getInputBuffer() failed previously 2022-09-14 23:49:49 -05:00
Jorys Paulin 62a526854d Translated using Weblate (French)
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/fr/
2022-09-14 15:22:45 +02:00
Jen Kung-chih 3dda940c92 Translated using Weblate (Chinese (Traditional))
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/zh_Hant/
2022-09-13 08:19:00 +02:00
Howard Wu ab77c4720d Translated using Weblate (Chinese (Simplified))
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/zh_Hans/
2022-09-13 08:18:59 +02:00
Cameron Gutman c8f1f9325e Version 10.8.1 2022-09-11 23:47:34 -05:00
Cameron Gutman 658940d3fb Fix mishandling of IDR frames with a SEI or AUD NAL 2022-09-11 23:45:12 -05:00
Cameron Gutman 51b4ca401e Merge remote-tracking branch 'origin/weblate' 2022-09-11 23:42:58 -05:00
reloxx13 10e4ca4ef3 Translated using Weblate (German)
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/de/
2022-09-12 06:41:34 +02:00
Cameron Gutman 2bcc2bdfe5 Version 10.8 2022-09-11 22:42:49 -05:00
Cameron Gutman 6462b580bb Merge remote-tracking branch 'origin/weblate' 2022-09-08 17:56:35 -05:00
Daniel Saburi b83d91c944 Translated using Weblate (Portuguese)
Currently translated at 9.3% (21 of 225 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt/
2022-09-09 00:55:56 +02:00
Daniel Saburi 07f842bc9e Translated using Weblate (Portuguese (Brazil))
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/pt_BR/
2022-09-09 00:55:56 +02:00
Cameron Gutman 3913e845fa Add workaround for MITV4-ANSM0 low latency mode bug
Fixes #1122
2022-09-08 17:43:17 -05:00
Cameron Gutman 09f0913974 Only request unbuffered touch events on Android 11+ 2022-09-08 17:30:19 -05:00
Cameron Gutman aa9ca35115 Fix refresh rate reduction for non-exact frame rate matches 2022-09-08 17:28:43 -05:00
Cameron Gutman 010dfdf834 Reload the settings page when switching between screens on a foldable device 2022-09-08 17:26:54 -05:00
Cameron Gutman 150fac9c09 Remove the TV refresh rate workaround now that users must opt-in to lowering the refresh rate 2022-09-06 23:10:39 -05:00
Cameron Gutman ec3aef13d8 Merge remote-tracking branch 'origin/weblate' 2022-09-06 23:00:54 -05:00
Cameron Gutman 2b56005bd2 Display portrait resolution first 2022-09-06 22:52:43 -05:00
Cameron Gutman 9bc893b6ad Allow both portrait and landscape native orientations on square displays 2022-09-06 22:50:43 -05:00
Cameron Gutman 3feb92e788 Force landscape mode when using OSC 2022-09-06 22:07:44 -05:00
Cameron Gutman 1265952814 Allow streaming in any orientation when using a square display 2022-09-06 21:24:54 -05:00
Cameron Gutman f5ad5d97db Fix tapping using the virtual trackpad on the Z Fold 4 2022-09-06 20:53:45 -05:00
Cameron Gutman 5ac0939731 Don't reduce refresh rate by default in balanced mode 2022-09-06 20:21:53 -05:00
Cameron Gutman b653694860 Request unbuffered input events to reduce input latency 2022-09-06 19:09:31 -05:00
Cameron Gutman 49051a5095 Prefetch input buffers while waiting for the next frame to arrive 2022-09-06 00:59:45 -05:00
Cameron Gutman 7734de6465 Fix handling of 3 byte Annex B start sequences 2022-09-05 22:32:13 -05:00
TacoTheDank edac646434 Regenerate drawables 2022-09-03 12:08:51 -05:00
sanhoe 51c7665fdc Translated using Weblate (Korean)
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2022-09-02 17:18:21 +02:00
Jen Kung-chih 37545821fc Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-08-28 05:22:25 +02:00
Brandon Goldberg 8a1ed0f146 Translated using Weblate (Spanish)
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2022-08-25 02:22:25 +02:00
Jen Kung-chih 7a0228fb81 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-08-21 18:21:42 +02:00
Sargon-Isa 3aecf9e031 Translated using Weblate (German)
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2022-08-14 15:21:45 +02:00
Sargon-Isa c2d4d221af Translated using Weblate (German)
Currently translated at 99.0% (219 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2022-08-11 19:15:29 +02:00
Cameron Gutman 53f89fbe22 Update AGP to 7.2.2 2022-08-04 21:29:43 -05:00
Cameron Gutman eb5f7ef7af Version 10.7 2022-08-04 21:13:01 -05:00
Cameron Gutman e2fc76d21d Merge remote-tracking branch 'origin/weblate' 2022-08-02 18:36:49 -05:00
Wen-haur Chiu 1754103175 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-08-03 01:36:20 +02:00
Cameron Gutman dacd00708f Don't sleep on the main thread in touch processing code 2022-08-02 18:20:05 -05:00
Cameron Gutman a73129243c Compensate for button down time when computing extra minimum button down 2022-08-02 18:14:10 -05:00
Cameron Gutman 54a6aa9081 Remove emulated button sleeps 2022-08-02 18:08:53 -05:00
Cameron Gutman 0fbb53c606 Remove MediaCodecHelper.getMonotonicMillis() 2022-08-02 18:08:12 -05:00
Cameron Gutman eb2e79977d Use event time on input events rather than current uptime 2022-08-02 18:07:15 -05:00
Cameron Gutman b70a47f5e5 Negotiate the higher of the two decoder slices-per-frame preferences to provide best performance 2022-08-01 22:26:00 -05:00
Cameron Gutman 9d5ff72548 Update OpenSSL to fix _armv7_tick() crash
OpenSSL 1.1.1q + https://github.com/cgutman/openssl/commit/fe1a23ccf76780a16f7dc3f2ff1ef97797109c57
2022-08-01 21:50:27 -05:00
Grider 6b972b56a5 Add support for Samsung DeX mode desktop mouse(touchpad) events 2022-07-31 17:26:18 -05:00
Cameron Gutman a80d30baf7 Revert "Add support for 8bitdo sn30 pro xCloud (#1102)"
The broken mapping is due to an old firmware (see #978).

This reverts commit bfc3116661.
2022-07-31 17:12:52 -05:00
Cameron Gutman b9280e9a8e Correct language name for Brazilian Portuguese 2022-07-27 23:36:03 -05:00
Cameron Gutman c6640d201c Merge remote-tracking branch 'origin/weblate' 2022-07-27 23:34:33 -05:00
LUTEN VR 795fdc3605 Translated using Weblate (Korean)
Currently translated at 99.5% (220 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2022-07-28 06:19:17 +02:00
Cameron Gutman 05311da33d Use 4 slices per frame for software decoders 2022-07-22 20:14:53 -05:00
Cameron Gutman 2e442cb1d1 Only use 4 slices per frame on old Qualcomm devices that benefit from it
Using it everywhere decreases encoding efficiency for no gain in performance
2022-07-22 18:43:59 -05:00
Cameron Gutman fe322590cc Add an option to allow equalizer effects 2022-07-22 00:23:11 -05:00
Cameron Gutman 6cf9b25c04 Fix incorrect name for certain languages 2022-07-21 23:39:47 -05:00
Cameron Gutman 417babb3d4 Add Brazilian Portuguese to language options 2022-07-21 23:38:08 -05:00
Cameron Gutman bdaaa6f0c7 Merge remote-tracking branch 'origin/weblate' 2022-07-21 21:21:35 -05:00
mltgames 7e92dd7fe4 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt_BR/
2022-07-21 14:18:18 +02:00
Wen-haur Chiu 50601e24ed Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-07-21 14:18:18 +02:00
peerobo bfc3116661 Add support for 8bitdo sn30 pro xCloud (#1102)
* add support for 8bitdo sn30 pro xCloud

Co-authored-by: peerobo <phuongrobotics@me.com>
2022-07-20 08:37:32 -05:00
Cameron Gutman 264b6e54f2 Add Codec2 variants in the decoder prefix lists 2022-07-19 23:51:11 -05:00
Cameron Gutman 1ed7ecc82f Don't use FLAG_BYPASS_INTERRUPTION_POLICY
See https://issuetracker.google.com/issues/235875658
2022-07-19 23:02:31 -05:00
Chase Payne 19b8032d06 Fixes an issue that caused televisions to have frame pacing problems when setting the refresh rate below 50hz 2022-07-12 23:56:38 -05:00
Wen-haur Chiu 1e254ea8f4 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-07-12 06:20:34 +02:00
Cameron Gutman babfc99c35 Version 10.6 2022-07-07 23:17:08 -05:00
Bail Adnan Farid 5c802555a2 Translated using Weblate (Indonesian)
Currently translated at 35.6% (78 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/id/
2022-07-07 16:15:42 +02:00
Bail Adnan Farid fbc41c9a4e Added translation using Weblate (Indonesian) 2022-07-05 16:10:15 +02:00
Cameron Gutman 1eca461cb1 Merge remote-tracking branch 'origin/weblate' 2022-07-04 17:51:36 -05:00
Cameron Gutman ebd327c7a6 Use new ShieldControllerExtensions library for Shield Controller rumble support
https://github.com/cgutman/ShieldControllerExtensions
2022-06-30 18:04:02 -05:00
Cameron Gutman 602febe876 Use onPictureInPictureRequested() to enter PiP on Android 11 2022-06-29 23:28:52 -05:00
Cameron Gutman 84fcd3ae6a Use requestMetaKeyEvent API on Samsung devices
Inspired by #1078
2022-06-28 22:07:40 -05:00
Cameron Gutman 84296c6e1c Toggle the IME with a 3 finger tap rather than only showing it 2022-06-28 21:40:59 -05:00
Jorys Paulin 6012e0ea8c Translated using Weblate (French)
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-06-27 15:16:50 +02:00
Cameron Gutman 9c76defad0 Add workaround for Galaxy S10 devices crashing during WifiLock acquisition 2022-06-26 13:59:39 -05:00
Cameron Gutman ffd6fab35c Prevent use of proxies 2022-06-25 14:18:38 -05:00
Cameron Gutman 296f97f7ca Version 10.5 2022-06-23 23:37:19 -05:00
Artem 9cbef34f29 Translated using Weblate (Ukrainian)
Currently translated at 94.5% (207 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2022-06-22 22:20:52 +02:00
Cameron Gutman 7a65136d29 Disable predictive back gesture support because it breaks KEYCODE_BACK on InputDevices
Partially reverts b2e605838e
2022-06-18 16:19:02 -05:00
Cameron Gutman acaebea846 Merge remote-tracking branch 'origin/weblate' 2022-06-18 15:02:06 -05:00
Cameron Gutman ce850ac12f Fix crash on Xiaomi MiPad running newer custom ROMs
AVC Decoder: OMX.Nvidia.h264.decode
HEVC Decoder: OMX.Nvidia.h265.decode
AVC supported width range: [32, 3840]
AVC achievable FPS range: [146.0, 149.0]
HEVC supported width range: [32, 528]
HEVC achievable FPS range: UNSUPPORTED!
2022-06-18 15:00:10 -05:00
Cameron Gutman a93422d3ed Handle failure to bind com.nvidia.blakepairing more robustly 2022-06-18 14:31:38 -05:00
Cameron Gutman b2e605838e Opt in for new predictive back gesture support in Android 13 2022-06-18 14:26:13 -05:00
Cameron Gutman 2e14002442 Switch to the new native per-app language preference APIs on Android 13 2022-06-18 14:19:19 -05:00
Cameron Gutman c743949df5 Don't crash if no performance data was provided for the codec using the M API 2022-06-18 10:37:16 -05:00
Cameron Gutman f207a3f6d1 Use areSizeAndRateSupported() as a last resort if no performance data is available 2022-06-18 10:35:12 -05:00
Cameron Gutman d6211605a1 Fix crash on shortcut launch if PC has no known MAC address 2022-06-18 10:23:06 -05:00
Cameron Gutman b16676b54a Version 10.4 2022-06-18 10:18:37 -05:00
Licaon_Kter dc9bfe5189 Fastlane mention Sunshine (#1086)
* Mention Sunshine

* Update full DE

* Short EN

* Full EN

* remove for clarity

* clarify here too
2022-06-18 09:57:37 -05:00
metezd 80620ed4c6 Translated using Weblate (Turkish)
Currently translated at 69.4% (152 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/tr/
2022-06-15 14:17:48 +02:00
Wen-haur Chiu 76bd0ab696 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-06-15 14:17:47 +02:00
ㅤAbsurdUsername e0914df58a Translated using Weblate (Italian)
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-06-15 14:17:46 +02:00
Cameron Gutman 20039a422e Merge remote-tracking branch 'origin/weblate' 2022-06-13 21:44:02 -05:00
Cameron Gutman 22b9c9ca68 Use H.264 on Sabrina if possible for lowest latency 2022-06-13 21:40:41 -05:00
Eric 0c546e35ec Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (219 of 219 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-06-14 04:19:39 +02:00
Cameron Gutman b70370ac09 Merge remote-tracking branch 'origin/weblate' 2022-06-13 21:14:40 -05:00
Cameron Gutman aa10bb7dc5 Block HDR use on the known broken Shield TV firmware build 2022-06-13 20:23:18 -05:00
Cameron Gutman c6100a9be1 Catch potential older NVIDIA devices that use partial HEVC acceleration 2022-06-13 19:25:29 -05:00
Cameron Gutman 529a2f7bf8 Prevent PiP entry while the USB permission dialog is open 2022-06-13 19:23:03 -05:00
ㅤAbsurdUsername 9ec7e916c5 Translated using Weblate (Italian)
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-06-13 20:16:29 +02:00
Cameron Gutman 982b36cf98 Adjust app details text for new HDR behavior 2022-06-09 20:25:37 -05:00
Cameron Gutman a73eab5e92 Handle stale controller token mappings upon device removal 2022-06-09 19:43:46 -05:00
Cameron Gutman a8479ccb5f Implement support for rumble for Shield controllers on Shield devices 2022-06-09 18:51:23 -05:00
Cameron Gutman f55e4e0e01 Don't dock expanded PiP overlays when browsing PCs and apps 2022-06-09 00:05:19 -05:00
Cameron Gutman d08c32ce04 Map external keyboard keycodes to the QWERTY layout that GFE expects 2022-06-08 23:54:57 -05:00
Cameron Gutman 1d599c5e60 Target Android 13 2022-06-08 22:58:39 -05:00
Cameron Gutman e888ae59e4 Ignore 3 finger tap gesture when cancelled 2022-06-08 22:58:23 -05:00
Cameron Gutman 951d544894 Provide GameState updates to GameManager on Android 13 2022-06-08 22:41:16 -05:00
Cameron Gutman 49898b34e1 Don't export UsbEventReceiver on Android 13 2022-06-08 22:16:58 -05:00
Cameron Gutman 3854a6a42e Add predictive back support to HelpActivity 2022-06-08 21:45:00 -05:00
Cameron Gutman d4da5bc281 Disallow Game Mode downscaling on Android 12+ 2022-06-08 20:56:27 -05:00
Cameron Gutman 04954f5242 Add handling for MotionEvent.FLAG_CANCELED 2022-06-08 20:35:46 -05:00
Cameron Gutman 9fc5496526 Use VibrationAttributes to bypass interruption policy 2022-06-08 20:26:36 -05:00
Cameron Gutman e363d24b1c Add PiP title and subtilte on Android 13 2022-06-08 20:04:12 -05:00
Cameron Gutman 801f4027a2 Add preferKeepClear marks on important UI elements 2022-06-08 20:03:23 -05:00
Cameron Gutman c0dc344f76 Compile with API 33 SDK 2022-06-08 20:01:05 -05:00
TacoTheDank b5b3d81f00 Clean up flavors by using buildConfigField 2022-06-08 19:44:59 -05:00
TacoTheDank 8dd8dbc1d1 Clean up app build.gradle deprecations 2022-06-08 19:44:59 -05:00
TacoTheDank 8f31aa59a8 Update gradle wrapper 2022-06-08 19:44:59 -05:00
Cameron Gutman 5b581b6c0f Update string for HEVC auto setting 2022-06-06 17:30:18 -05:00
Cameron Gutman 297ac64fde Enable HEVC on all Shield TV devices 2022-06-06 17:29:47 -05:00
Cameron Gutman d4490f0e17 Fix performance point check for Android M - P 2022-06-06 17:26:59 -05:00
Cameron Gutman d04e7a3231 Enable HEVC on untested decoders if it's the only way to meet the performance target 2022-06-04 17:37:14 -05:00
Cameron Gutman 5b456aba27 Use a separate HandlerThread for Choreographer callbacks 2022-06-04 17:00:58 -05:00
Cameron Gutman 0c065dcc1f Print vendor parameters on Android 12 2022-06-04 15:42:06 -05:00
Cameron Gutman 531f73329d Quiet down excessive exception logging in debug builds 2022-06-04 15:33:12 -05:00
Cameron Gutman d6ba72032d Version 10.3 2022-06-03 20:56:48 -05:00
Cameron Gutman bfdc7a2609 Merge remote-tracking branch 'origin/weblate' 2022-06-03 19:20:29 -05:00
Wen-haur Chiu 031abf03da Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-06-04 02:19:58 +02:00
Cameron Gutman 6aac8e6be6 Use amazon.hardware.fire_tv feature to detect Fire TV devices 2022-06-03 19:03:56 -05:00
Wen-haur Chiu 8ff93d21c3 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-06-03 13:17:29 +02:00
weng weng 6df3d0bc44 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-06-03 13:17:29 +02:00
Cameron Gutman 0b18e8fdb4 Update decoder errata details 2022-06-03 01:39:39 -05:00
Cameron Gutman 19d8ae0f78 Revamp low latency option handling
- Introduce a tiered solution where we try progressively fewer options until one works
- Use vdec-lowlatency for all devices, since we know at least the Fire TV 3 supports it with an Amlogic SoC
- Enable HEVC on Fire TV 3 since vdec-lowlatency avoids the HEVC decoder bug
2022-06-03 01:04:11 -05:00
Cameron Gutman d7ffb5dddc Refactor decoder creation code to allow retries 2022-06-02 21:17:20 -05:00
Cameron Gutman 2859b73dfe Add Amlogic low latency vendor-defined option 2022-06-02 21:02:43 -05:00
Cameron Gutman 6f9021a5e6 Add magic performance boost for MediaTek devices 2022-06-01 22:06:11 -05:00
Cameron Gutman 3bfeaefdbd Update NDK to r23c 2022-06-01 19:24:03 -05:00
Cameron Gutman db1eace975 Add support for Android 13 themed app icons 2022-06-01 19:08:17 -05:00
Cameron Gutman cab0fa176e Version 10.2 2022-05-31 21:05:59 -05:00
Jorys Paulin 2f9ae107a2 Translated using Weblate (French)
Currently translated at 100.0% (221 of 221 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-05-31 10:14:36 +02:00
Cameron Gutman 18c93abcb3 Submit fused IDR frames on decoders that support adaptive playback even if they are blocked from using it 2022-05-29 22:21:15 -05:00
Cameron Gutman bd64dfb661 Submit codec config data with a timestamp of 0 like MediaCodec does with csd-0 2022-05-29 22:10:49 -05:00
Cameron Gutman 82619063ee Plumb frame type information into the decoder 2022-05-29 21:58:28 -05:00
Cameron Gutman 5dbf18d66e Fix miscounting IDR frames in video stats 2022-05-29 21:10:41 -05:00
Cameron Gutman 6a34ff2728 Rewrite AES pairing functions to avoid Play Store's ECB warning
ECB is safe in this context because it's encrypting one-time messages
using a one-time key. All input data going through encryptAes() is
either random or partially random and passed through a secure hashing
function (SHA-256 on modern GFE versions).

Message authentication is not a concern either, because it is performed
by the pairing process itself via RSA signature verification. Any
ciphertext tampering would cause signature verification to fail later in
the pairing process.
2022-05-29 14:38:56 -05:00
Cameron Gutman f7c7487756 Merge remote-tracking branch 'origin/weblate' 2022-05-28 18:01:30 -05:00
weng weng f966cb4ca0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (218 of 218 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-05-29 01:01:12 +02:00
Jorys Paulin 549563a3d2 Translated using Weblate (French)
Currently translated at 100.0% (218 of 218 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-05-29 01:01:12 +02:00
Cameron Gutman c5f2a3f8fe Tweak remote desktop mouse mode string 2022-05-28 18:00:42 -05:00
Cameron Gutman 81a3bbd5e8 Implement remote desktop optimized mouse mode 2022-05-28 16:38:22 -05:00
Cameron Gutman 1509a2a799 Fix default deadzone setting 2022-05-28 16:16:46 -05:00
Cameron Gutman fc547b734f Fix crashes caused by calling NvHTTP with a null address 2022-05-28 15:54:21 -05:00
Cameron Gutman b3700b5a19 Plumb LiSendMouseMoveAsMousePositionEvent() into JNI 2022-05-28 15:21:58 -05:00
Cameron Gutman 2b29682095 Update AGP 2022-05-28 15:13:10 -05:00
Cameron Gutman 286094ee33 Add dead zone configuration option
Fixes #1075
2022-05-28 15:12:58 -05:00
ToldYouThat c7a061d24e Translated using Weblate (Turkish)
Currently translated at 25.6% (56 of 218 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/tr/
2022-05-25 14:14:38 +02:00
140 changed files with 5901 additions and 1576 deletions
+26 -12
View File
@@ -1,25 +1,28 @@
apply plugin: 'com.android.application'
android {
ndkVersion "23.1.7779620"
ndkVersion "23.2.8568313"
compileSdkVersion 32
compileSdk 33
defaultConfig {
minSdkVersion 16
targetSdkVersion 32
minSdk 16
targetSdk 33
versionName "10.1.1"
versionCode = 274
versionName "10.11"
versionCode = 301
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
ndk.debugSymbolLevel = 'FULL'
}
flavorDimensions "root"
flavorDimensions.add("root")
productFlavors {
root {
// Android O has native mouse capture, so don't show the rooted
// version to devices running O on the Play Store.
maxSdkVersion 25
maxSdk 25
externalNativeBuild {
ndkBuild {
@@ -29,6 +32,7 @@ android {
applicationId "com.limelight.root"
dimension "root"
buildConfigField "boolean", "ROOT_BUILD", "true"
}
nonRoot {
@@ -40,9 +44,16 @@ android {
applicationId "com.limelight"
dimension "root"
buildConfigField "boolean", "ROOT_BUILD", "false"
}
}
compileOptions {
encoding "UTF-8"
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
lint {
disable 'MissingTranslation'
lintConfig file('lint.xml')
@@ -55,7 +66,7 @@ android {
enableSplit = false
}
density {
// FIXME: This should not be neccessary but we get
// FIXME: This should not be necessary but we get
// weird crashes due to missing drawable resources
// when this split is enabled.
enableSplit = false
@@ -65,6 +76,8 @@ android {
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "app_label", "Moonlight (Debug)"
resValue "string", "app_label_root", "Moonlight (Root Debug)"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
@@ -101,6 +114,8 @@ android {
//
// TL;DR: Leave the following line alone!
applicationIdSuffix ".unofficial"
resValue "string", "app_label", "Moonlight"
resValue "string", "app_label_root", "Moonlight (Root)"
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
@@ -112,9 +127,6 @@ android {
path "src/main/jni/Android.mk"
}
}
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
android.defaultConfig.ndk.debugSymbolLevel = 'FULL'
}
dependencies {
@@ -123,5 +135,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'
}
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_label" translatable="false">Moonlight (Debug)</string>
<string name="app_label_root" translatable="false">Moonlight (Root Debug)</string>
</resources>
+10 -3
View File
@@ -44,22 +44,31 @@
android:roundIcon="@mipmap/ic_launcher"
android:installLocation="auto"
android:gwpAsanMode="always"
android:localeConfig="@xml/locales_config"
android:enableOnBackInvokedCallback="false"
android:theme="@style/AppTheme">
<provider
android:name=".PosterContentProvider"
android:authorities="poster.${applicationId}"
android:enabled="true"
android:exported="true">
</provider>
<!-- Samsung multi-window support -->
<uses-library
android:name="com.sec.android.app.multiwindow"
android:required="false" />
<meta-data
android:name="com.sec.android.support.multiwindow"
android:value="true" />
<!-- Disable Game Mode downscaling since it can break our UI dialogs and doesn't benefit
performance much for us since we don't use GL/Vulkan for rendering anyway -->
<meta-data
android:name="com.android.graphics.intervention.wm.allowDownscale"
android:value="false"/>
<!-- Samsung DeX support requires explicit placement of android:resizeableActivity="true"
in each activity even though it is implied by targeting API 24+ -->
@@ -115,11 +124,9 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.limelight.PcView" />
</activity>
<!-- This will fall back to sensorLandscape at runtime on Android 4.2 and below -->
<activity
android:name=".Game"
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:screenOrientation="userLandscape"
android:noHistory="true"
android:supportsPictureInPicture="true"
android:resizeableActivity="true"
@@ -293,6 +293,11 @@ public class AppView extends Activity implements AdapterFragmentCallbacks {
setContentView(R.layout.activity_app_view);
// Allow floating expanded PiP overlays while browsing apps
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setShouldDockBigOverlays(false);
}
UiHelper.notifyNewRootView(this);
showHiddenApps = getIntent().getBooleanExtra(SHOW_HIDDEN_APPS_EXTRA, false);
File diff suppressed because it is too large Load Diff
@@ -2,9 +2,12 @@ package com.limelight;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import com.limelight.utils.SpinnerDialog;
@@ -13,10 +16,26 @@ public class HelpActivity extends Activity {
private SpinnerDialog loadingDialog;
private WebView webView;
private boolean backCallbackRegistered;
private OnBackInvokedCallback onBackInvokedCallback;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
onBackInvokedCallback = new OnBackInvokedCallback() {
@Override
public void onBackInvoked() {
// We should always be able to go back because we unregister our callback
// when we can't go back. Nonetheless, we will still check anyway.
if (webView.canGoBack()) {
webView.goBack();
}
}
};
}
webView = new WebView(this);
setContentView(webView);
@@ -39,6 +58,8 @@ public class HelpActivity extends Activity {
getResources().getString(R.string.help_loading_title),
getResources().getString(R.string.help_loading_msg), false);
}
refreshBackDispatchState();
}
@Override
@@ -47,6 +68,8 @@ public class HelpActivity extends Activity {
loadingDialog.dismiss();
loadingDialog = null;
}
refreshBackDispatchState();
}
@Override
@@ -59,7 +82,33 @@ public class HelpActivity extends Activity {
webView.loadUrl(getIntent().getData().toString());
}
private void refreshBackDispatchState() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (webView.canGoBack() && !backCallbackRegistered) {
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT, onBackInvokedCallback);
backCallbackRegistered = true;
}
else if (!webView.canGoBack() && backCallbackRegistered) {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(onBackInvokedCallback);
backCallbackRegistered = false;
}
}
}
@Override
protected void onDestroy() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (backCallbackRegistered) {
getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(onBackInvokedCallback);
}
}
super.onDestroy();
}
@Override
// NOTE: This will NOT be called on Android 13+ with android:enableOnBackInvokedCallback="true"
public void onBackPressed() {
// Back goes back through the WebView history
// until no more history remains
+16 -14
View File
@@ -124,6 +124,11 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
UiHelper.notifyNewRootView(this);
// Allow floating expanded PiP overlays while browsing PCs
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
setShouldDockBigOverlays(false);
}
// Set default preferences if we've never been run
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
@@ -374,15 +379,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
}
private void doPair(final ComputerDetails computer) {
if (computer.state == ComputerDetails.State.OFFLINE ||
ServerHelper.getCurrentAddressFromComputer(computer) == null) {
if (computer.state == ComputerDetails.State.OFFLINE || computer.activeAddress == null) {
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;
@@ -400,8 +400,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,12 +416,17 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
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);
@@ -512,8 +516,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
}
private void doUnpair(final ComputerDetails computer) {
if (computer.state == ComputerDetails.State.OFFLINE ||
ServerHelper.getCurrentAddressFromComputer(computer) == null) {
if (computer.state == ComputerDetails.State.OFFLINE || computer.activeAddress == null) {
Toast.makeText(PcView.this, getResources().getString(R.string.error_pc_offline), Toast.LENGTH_SHORT).show();
return;
}
@@ -530,8 +533,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();
@@ -83,7 +83,7 @@ public class ShortcutTrampoline extends Activity {
}
// Try to wake the target PC if it's offline (up to some retry limit)
if (details.state == ComputerDetails.State.OFFLINE && --wakeHostTries >= 0) {
if (details.state == ComputerDetails.State.OFFLINE && details.macAddress != null && --wakeHostTries >= 0) {
try {
// Make a best effort attempt to wake the target PC
WakeOnLanSender.sendWolPacket(computer);
@@ -8,16 +8,6 @@ import com.limelight.nvstream.av.audio.AudioRenderer;
import com.limelight.nvstream.http.LimelightCryptoProvider;
public class PlatformBinding {
public static String getDeviceName() {
String deviceName = android.os.Build.MODEL;
deviceName = deviceName.replace(" ", "");
return deviceName;
}
public static AudioRenderer getAudioRenderer() {
return new AndroidAudioRenderer();
}
public static LimelightCryptoProvider getCryptoProvider(Context c) {
return new AndroidCryptoProvider(c);
}
@@ -1,9 +1,12 @@
package com.limelight.binding.audio;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.media.audiofx.AudioEffect;
import android.os.Build;
import com.limelight.LimeLog;
@@ -12,8 +15,16 @@ import com.limelight.nvstream.jni.MoonBridge;
public class AndroidAudioRenderer implements AudioRenderer {
private final Context context;
private final boolean enableAudioFx;
private AudioTrack track;
public AndroidAudioRenderer(Context context, boolean enableAudioFx) {
this.context = context;
this.enableAudioFx = enableAudioFx;
}
private AudioTrack createAudioTrack(int channelConfig, int sampleRate, int bufferSize, boolean lowLatency) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return new AudioTrack(AudioManager.STREAM_MUSIC,
@@ -161,6 +172,12 @@ public class AndroidAudioRenderer implements AudioRenderer {
continue;
}
// Skip low latency options when using audio effects, since low latency mode
// precludes the use of the audio effect pipeline (as of Android 13).
if (enableAudioFx && lowLatency) {
continue;
}
try {
track = createAudioTrack(channelConfig, sampleRate, bufferSize, lowLatency);
track.play();
@@ -203,10 +220,27 @@ public class AndroidAudioRenderer implements AudioRenderer {
}
@Override
public void start() {}
public void start() {
if (enableAudioFx) {
// Open an audio effect control session to allow equalizers to apply audio effects
Intent i = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, track.getAudioSessionId());
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
i.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_GAME);
context.sendBroadcast(i);
}
}
@Override
public void stop() {}
public void stop() {
if (enableAudioFx) {
// Close our audio effect control session when we're stopping
Intent i = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, track.getAudioSessionId());
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
context.sendBroadcast(i);
}
}
@Override
public void cleanup() {
@@ -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
@@ -9,7 +9,9 @@ import android.hardware.usb.UsbManager;
import android.media.AudioAttributes;
import android.os.Build;
import android.os.CombinedVibration;
import android.os.SystemClock;
import android.os.Handler;
import android.os.Looper;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
@@ -31,9 +33,9 @@ import com.limelight.preferences.PreferenceConfiguration;
import com.limelight.ui.GameGestures;
import com.limelight.utils.Vector2d;
import org.cgutman.shieldcontrollerextensions.SceManager;
import java.lang.reflect.InvocationTargetException;
import java.util.Timer;
import java.util.TimerTask;
public class ControllerHandler implements InputManager.InputDeviceListener, UsbDriverListener {
@@ -46,9 +48,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private static final int EMULATING_SPECIAL = 0x1;
private static final int EMULATING_SELECT = 0x2;
private static final int EMULATED_SPECIAL_UP_DELAY_MS = 100;
private static final int EMULATED_SELECT_UP_DELAY_MS = 30;
private final Vector2d inputVector = new Vector2d();
private final SparseArray<InputDeviceContext> inputDeviceContexts = new SparseArray<>();
@@ -60,6 +59,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
private final InputDeviceContext defaultContext = new InputDeviceContext();
private final GameGestures gestures;
private final Vibrator deviceVibrator;
private final SceManager sceManager;
private final Handler handler;
private boolean hasGameController;
private final PreferenceConfiguration prefConfig;
@@ -71,10 +72,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
this.gestures = gestures;
this.prefConfig = prefConfig;
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
this.handler = new Handler(Looper.getMainLooper());
// HACK: For now we're hardcoding a 7% deadzone. Some deadzone
// is required for controller batching support to work.
int deadzonePercentage = 7;
this.sceManager = new SceManager(activityContext);
this.sceManager.start();
int deadzonePercentage = prefConfig.deadzonePercentage;
int[] ids = InputDevice.getDeviceIds();
for (int id : ids) {
@@ -201,6 +204,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
deviceContext.destroy();
}
sceManager.stop();
deviceVibrator.cancel();
}
@@ -506,6 +510,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
LimeLog.info(dev.toString());
context.inputDevice = dev;
context.name = devName;
context.id = dev.getId();
context.external = isExternal(dev);
@@ -703,9 +708,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
// SHIELD controllers will use small stick deadzones
else if (devName.contains("SHIELD") || devName.contains("NVIDIA Controller")) {
context.leftStickDeadzoneRadius = 0.07f;
context.rightStickDeadzoneRadius = 0.07f;
// The big Nvidia button on the Shield controllers acts like a Search button. It
// summons the Google Assistant on the Shield TV. On my Pixel 4, it seems to do
// nothing, so we can hijack it to act like a mode button.
@@ -1292,28 +1294,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
}
private void toggleMouseEmulation(final GenericControllerContext context) {
if (context.mouseEmulationTimer != null) {
context.mouseEmulationTimer.cancel();
context.mouseEmulationTimer = null;
}
context.mouseEmulationActive = !context.mouseEmulationActive;
Toast.makeText(activityContext, "Mouse emulation is: " + (context.mouseEmulationActive ? "ON" : "OFF"), Toast.LENGTH_SHORT).show();
if (context.mouseEmulationActive) {
context.mouseEmulationTimer = new Timer();
context.mouseEmulationTimer.schedule(new TimerTask() {
@Override
public void run() {
// Send mouse movement events from analog sticks
sendEmulatedMouseEvent(context.leftStickX, context.leftStickY);
sendEmulatedMouseEvent(context.rightStickX, context.rightStickY);
}
}, 50, 50);
}
}
@TargetApi(31)
private boolean hasDualAmplitudeControlledRumbleVibrators(VibratorManager vm) {
int[] vibratorIds = vm.getVibratorIds();
@@ -1362,7 +1342,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
}
vm.vibrate(combo.combine());
VibrationAttributes.Builder vibrationAttributes = new VibrationAttributes.Builder();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
vibrationAttributes.setUsage(VibrationAttributes.USAGE_MEDIA);
}
vm.vibrate(combo.combine(), vibrationAttributes.build());
}
private void rumbleSingleVibrator(Vibrator vibrator, short lowFreqMotor, short highFreqMotor) {
@@ -1387,10 +1373,18 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (vibrator.hasAmplitudeControl()) {
VibrationEffect effect = VibrationEffect.createOneShot(60000, simulatedAmplitude);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.build();
vibrator.vibrate(effect, audioAttributes);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder()
.setUsage(VibrationAttributes.USAGE_MEDIA)
.build();
vibrator.vibrate(effect, vibrationAttributes);
}
else {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.build();
vibrator.vibrate(effect, audioAttributes);
}
return;
}
}
@@ -1400,7 +1394,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
long pwmPeriod = 20;
long onTime = (long)((simulatedAmplitude / 255.0) * pwmPeriod);
long offTime = pwmPeriod - onTime;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder()
.setUsage(VibrationAttributes.USAGE_MEDIA)
.build();
vibrator.vibrate(VibrationEffect.createWaveform(new long[]{0, onTime, offTime}, 0), vibrationAttributes);
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_GAME)
.build();
@@ -1421,10 +1421,16 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if (deviceContext.controllerNumber == controllerNumber) {
foundMatchingDevice = true;
// Prefer the documented Android 12 rumble API which can handle dual vibrators on PS/Xbox controllers
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && deviceContext.vibratorManager != null) {
vibrated = true;
rumbleDualVibrators(deviceContext.vibratorManager, lowFreqMotor, highFreqMotor);
}
// On Shield devices, we can use their special API to rumble Shield controllers
else if (sceManager.rumble(deviceContext.inputDevice, lowFreqMotor, highFreqMotor)) {
vibrated = true;
}
// If all else fails, we have to try the old Vibrator API
else if (deviceContext.vibrator != null) {
vibrated = true;
rumbleSingleVibrator(deviceContext.vibrator, lowFreqMotor, highFreqMotor);
@@ -1476,12 +1482,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// If the button hasn't been down long enough, sleep for a bit before sending the up event
// This allows "instant" button presses (like OUYA's virtual menu button) to work. This
// path should not be triggered during normal usage.
if (SystemClock.uptimeMillis() - event.getDownTime() < ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS)
int buttonDownTime = (int)(event.getEventTime() - event.getDownTime());
if (buttonDownTime < ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS)
{
// Since our sleep time is so short (10 ms), it shouldn't cause a problem doing this in the
// UI thread.
// Since our sleep time is so short (<= 25 ms), it shouldn't cause a problem doing this
// in the UI thread.
try {
Thread.sleep(ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS);
Thread.sleep(ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS - buttonDownTime);
} catch (InterruptedException e) {
e.printStackTrace();
@@ -1502,9 +1509,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// Make sure it's real by checking that the key is actually down before taking
// any action.
if ((context.inputMap & ControllerPacket.PLAY_FLAG) != 0 &&
SystemClock.uptimeMillis() - context.startDownTime > ControllerHandler.START_DOWN_TIME_MOUSE_MODE_MS &&
event.getEventTime() - context.startDownTime > ControllerHandler.START_DOWN_TIME_MOUSE_MODE_MS &&
prefConfig.mouseEmulation) {
toggleMouseEmulation(context);
context.toggleMouseEmulation();
}
context.inputMap &= ~ControllerPacket.PLAY_FLAG;
break;
@@ -1555,11 +1562,11 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
break;
case KeyEvent.KEYCODE_BUTTON_L1:
context.inputMap &= ~ControllerPacket.LB_FLAG;
context.lastLbUpTime = SystemClock.uptimeMillis();
context.lastLbUpTime = event.getEventTime();
break;
case KeyEvent.KEYCODE_BUTTON_R1:
context.inputMap &= ~ControllerPacket.RB_FLAG;
context.lastRbUpTime = SystemClock.uptimeMillis();
context.lastRbUpTime = event.getEventTime();
break;
case KeyEvent.KEYCODE_BUTTON_THUMBL:
context.inputMap &= ~ControllerPacket.LS_CLK_FLAG;
@@ -1595,17 +1602,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
context.inputMap &= ~ControllerPacket.BACK_FLAG;
context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SELECT;
try {
Thread.sleep(EMULATED_SELECT_UP_DELAY_MS);
} catch (InterruptedException e) {
e.printStackTrace();
// InterruptedException clears the thread's interrupt status. Since we can't
// handle that here, we will re-interrupt the thread to set the interrupt
// status back to true.
Thread.currentThread().interrupt();
}
}
}
@@ -1620,17 +1616,6 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
context.inputMap &= ~ControllerPacket.SPECIAL_BUTTON_FLAG;
context.emulatingButtonFlags &= ~ControllerHandler.EMULATING_SPECIAL;
try {
Thread.sleep(EMULATED_SPECIAL_UP_DELAY_MS);
} catch (InterruptedException e) {
e.printStackTrace();
// InterruptedException clears the thread's interrupt status. Since we can't
// handle that here, we will re-interrupt the thread to set the interrupt
// status back to true.
Thread.currentThread().interrupt();
}
}
}
@@ -1668,7 +1653,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
case KeyEvent.KEYCODE_BUTTON_START:
case KeyEvent.KEYCODE_MENU:
if (event.getRepeatCount() == 0) {
context.startDownTime = SystemClock.uptimeMillis();
context.startDownTime = event.getEventTime();
}
context.inputMap |= ControllerPacket.PLAY_FLAG;
break;
@@ -1759,7 +1744,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if (!context.hasSelect) {
if (context.inputMap == (ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG) ||
(context.inputMap == ControllerPacket.PLAY_FLAG &&
SystemClock.uptimeMillis() - context.lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
event.getEventTime() - context.lastLbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
{
context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.LB_FLAG);
context.inputMap |= ControllerPacket.BACK_FLAG;
@@ -1782,7 +1767,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
else {
if (context.inputMap == (ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG) ||
(context.inputMap == ControllerPacket.PLAY_FLAG &&
SystemClock.uptimeMillis() - context.lastRbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
event.getEventTime() - context.lastRbUpTime <= MAXIMUM_BUMPER_UP_DELAY_MS))
{
context.inputMap &= ~(ControllerPacket.PLAY_FLAG | ControllerPacket.RB_FLAG);
context.inputMap |= ControllerPacket.SPECIAL_BUTTON_FLAG;
@@ -1873,7 +1858,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
usbDeviceContexts.put(controller.getControllerId(), context);
}
static class GenericControllerContext {
class GenericControllerContext {
public int id;
public boolean external;
@@ -1897,14 +1882,38 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
public short leftStickY = 0x0000;
public boolean mouseEmulationActive;
public Timer mouseEmulationTimer;
public short mouseEmulationLastInputMap;
public final int mouseEmulationReportPeriod = 50;
public final Runnable mouseEmulationRunnable = new Runnable() {
@Override
public void run() {
if (!mouseEmulationActive) {
return;
}
// Send mouse movement events from analog sticks
sendEmulatedMouseEvent(leftStickX, leftStickY);
sendEmulatedMouseEvent(rightStickX, rightStickY);
// Requeue the callback
handler.postDelayed(this, mouseEmulationReportPeriod);
}
};
public void toggleMouseEmulation() {
handler.removeCallbacks(mouseEmulationRunnable);
mouseEmulationActive = !mouseEmulationActive;
Toast.makeText(activityContext, "Mouse emulation is: " + (mouseEmulationActive ? "ON" : "OFF"), Toast.LENGTH_SHORT).show();
if (mouseEmulationActive) {
handler.postDelayed(mouseEmulationRunnable, mouseEmulationReportPeriod);
}
}
public void destroy() {
if (mouseEmulationTimer != null) {
mouseEmulationTimer.cancel();
mouseEmulationTimer = null;
}
mouseEmulationActive = false;
handler.removeCallbacks(mouseEmulationRunnable);
}
}
@@ -1912,6 +1921,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
public String name;
public VibratorManager vibratorManager;
public Vibrator vibrator;
public InputDevice inputDevice;
public int leftStickXAxis = -1;
public int leftStickYAxis = -1;
@@ -1,13 +1,20 @@
package com.limelight.binding.input;
import android.annotation.TargetApi;
import android.hardware.input.InputManager;
import android.os.Build;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.KeyEvent;
import java.util.Arrays;
/**
* Class to translate a Android key code into the codes GFE is expecting
* @author Diego Waxemberg
* @author Cameron Gutman
*/
public class KeyboardTranslator {
public class KeyboardTranslator implements InputManager.InputDeviceListener {
/**
* GFE's prefix for every key code
@@ -48,6 +55,55 @@ public class KeyboardTranslator {
public static final int VK_QUOTE = 222;
public static final int VK_PAUSE = 19;
private static class KeyboardMapping {
private final InputDevice device;
private final int[] deviceKeyCodeToQwertyKeyCode;
@TargetApi(33)
public KeyboardMapping(InputDevice device) {
int maxKeyCode = KeyEvent.getMaxKeyCode();
this.device = device;
this.deviceKeyCodeToQwertyKeyCode = new int[maxKeyCode + 1];
// Any unmatched keycodes are treated as unknown
Arrays.fill(deviceKeyCodeToQwertyKeyCode, KeyEvent.KEYCODE_UNKNOWN);
for (int i = 0; i <= maxKeyCode; i++) {
int deviceKeyCode = device.getKeyCodeForKeyLocation(i);
if (deviceKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
deviceKeyCodeToQwertyKeyCode[deviceKeyCode] = i;
}
}
}
@TargetApi(33)
public int getDeviceKeyCodeForQwertyKeyCode(int qwertyKeyCode) {
return device.getKeyCodeForKeyLocation(qwertyKeyCode);
}
public int getQwertyKeyCodeForDeviceKeyCode(int deviceKeyCode) {
if (deviceKeyCode > KeyEvent.getMaxKeyCode()) {
return KeyEvent.KEYCODE_UNKNOWN;
}
return deviceKeyCodeToQwertyKeyCode[deviceKeyCode];
}
}
private final SparseArray<KeyboardMapping> keyboardMappings = new SparseArray<>();
public KeyboardTranslator() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
for (int deviceId : InputDevice.getDeviceIds()) {
InputDevice device = InputDevice.getDevice(deviceId);
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
keyboardMappings.set(deviceId, new KeyboardMapping(device));
}
}
}
}
public static boolean needsShift(int keycode) {
switch (keycode)
{
@@ -65,10 +121,24 @@ public class KeyboardTranslator {
/**
* Translates the given keycode and returns the GFE keycode
* @param keycode the code to be translated
* @param deviceId InputDevice.getId() or -1 if unknown
* @return a GFE keycode for the given keycode
*/
public static short translate(int keycode) {
public short translate(int keycode, int deviceId) {
int translated;
// If a device ID was provided, look up the keyboard mapping
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) {
keycode = qwertyKeyCode;
}
}
}
// This is a poor man's mapping between Android key codes
// and Windows VK_* codes. For all defined VK_ codes, see:
@@ -294,4 +364,30 @@ public class KeyboardTranslator {
return (short) ((KEY_PREFIX << 8) | translated);
}
@Override
public void onInputDeviceAdded(int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
InputDevice device = InputDevice.getDevice(index);
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
keyboardMappings.put(index, new KeyboardMapping(device));
}
}
}
@Override
public void onInputDeviceRemoved(int index) {
keyboardMappings.remove(index);
}
@Override
public void onInputDeviceChanged(int index) {
keyboardMappings.remove(index);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
InputDevice device = InputDevice.getDevice(index);
if (device != null && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
keyboardMappings.set(index, new KeyboardMapping(device));
}
}
}
}
@@ -2,8 +2,8 @@ package com.limelight.binding.input.capture;
import android.app.Activity;
import com.limelight.BuildConfig;
import com.limelight.LimeLog;
import com.limelight.LimelightBuildProps;
import com.limelight.R;
import com.limelight.binding.input.evdev.EvdevCaptureProviderShim;
import com.limelight.binding.input.evdev.EvdevListener;
@@ -16,7 +16,7 @@ public class InputCaptureManager {
}
// LineageOS implemented broken NVIDIA capture extensions, so avoid using them on root builds.
// See https://github.com/LineageOS/android_frameworks_base/commit/d304f478a023430f4712dbdc3ee69d9ad02cebd3
else if (!LimelightBuildProps.ROOT_BUILD && ShieldCaptureProvider.isCaptureProviderSupported()) {
else if (!BuildConfig.ROOT_BUILD && ShieldCaptureProvider.isCaptureProviderSupported()) {
LimeLog.info("Using NVIDIA mouse capture extension");
return new ShieldCaptureProvider(activity);
}
@@ -5,9 +5,9 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.os.SystemClock;
import com.limelight.LimeLog;
import com.limelight.binding.video.MediaCodecHelper;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -58,7 +58,7 @@ public abstract class AbstractXboxController extends AbstractController {
do {
// Read the next input state packet
long lastMillis = MediaCodecHelper.getMonotonicMillis();
long lastMillis = SystemClock.uptimeMillis();
res = connection.bulkTransfer(inEndpt, buffer, buffer.length, 3000);
// If we get a zero length response, treat it as an error
@@ -66,7 +66,7 @@ public abstract class AbstractXboxController extends AbstractController {
res = -1;
}
if (res == -1 && MediaCodecHelper.getMonotonicMillis() - lastMillis < 1000) {
if (res == -1 && SystemClock.uptimeMillis() - lastMillis < 1000) {
LimeLog.warning("Detected device I/O error");
AbstractXboxController.this.stop();
break;
@@ -29,6 +29,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
private UsbManager usbManager;
private PreferenceConfiguration prefConfig;
private boolean started;
private final UsbEventReceiver receiver = new UsbEventReceiver();
private final UsbDriverBinder binder = new UsbDriverBinder();
@@ -36,6 +37,7 @@ public class UsbDriverService extends Service implements UsbDriverListener {
private final ArrayList<AbstractController> controllers = new ArrayList<>();
private UsbDriverListener listener;
private UsbDriverStateListener stateListener;
private int nextDeviceId;
@Override
@@ -93,6 +95,11 @@ public class UsbDriverService extends Service implements UsbDriverListener {
else if (action.equals(ACTION_USB_PERMISSION)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// Permission dialog is now closed
if (stateListener != null) {
stateListener.onUsbPermissionPromptCompleted();
}
// If we got this far, we've already found we're able to handle this device
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
handleUsbDeviceState(device);
@@ -112,6 +119,18 @@ public class UsbDriverService extends Service implements UsbDriverListener {
}
}
}
public void setStateListener(UsbDriverStateListener stateListener) {
UsbDriverService.this.stateListener = stateListener;
}
public void start() {
UsbDriverService.this.start();
}
public void stop() {
UsbDriverService.this.stop();
}
}
private void handleUsbDeviceState(UsbDevice device) {
@@ -121,20 +140,29 @@ public class UsbDriverService extends Service implements UsbDriverListener {
if (!usbManager.hasPermission(device)) {
// Let's ask for permission
try {
// Tell the state listener that we're about to display a permission dialog
if (stateListener != null) {
stateListener.onUsbPermissionPromptStarting();
}
int intentFlags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// This PendingIntent must be mutable to allow the framework to populate EXTRA_DEVICE and EXTRA_PERMISSION_GRANTED.
intentFlags |= PendingIntent.FLAG_MUTABLE;
}
// This function is not documented as throwing any exceptions (denying access
// is indicated by calling the PendingIntent with a false result). However,
// Samsung Knox has some policies which block this request, but rather than
// just returning a false result or returning 0 enumerated devices,
// they throw an undocumented SecurityException from this call, crashing
// the whole app. :(
int intentFlags = 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// This PendingIntent must be mutable to allow the framework to populate EXTRA_DEVICE and EXTRA_PERMISSION_GRANTED.
intentFlags |= PendingIntent.FLAG_MUTABLE;
}
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), intentFlags));
} catch (SecurityException e) {
Toast.makeText(this, this.getText(R.string.error_usb_prohibited), Toast.LENGTH_LONG).show();
if (stateListener != null) {
stateListener.onUsbPermissionPromptCompleted();
}
}
return;
}
@@ -225,16 +253,23 @@ public class UsbDriverService extends Service implements UsbDriverListener {
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device));
}
@Override
public void onCreate() {
this.usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
this.prefConfig = PreferenceConfiguration.readPreferences(this);
private void start() {
if (started) {
return;
}
started = true;
// Register for USB attach broadcasts and permission completions
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(ACTION_USB_PERMISSION);
registerReceiver(receiver, filter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
registerReceiver(receiver, filter, RECEIVER_NOT_EXPORTED);
}
else {
registerReceiver(receiver, filter);
}
// Enumerate existing devices
for (UsbDevice dev : usbManager.getDeviceList().values()) {
@@ -245,14 +280,16 @@ public class UsbDriverService extends Service implements UsbDriverListener {
}
}
@Override
public void onDestroy() {
private void stop() {
if (!started) {
return;
}
started = false;
// Stop the attachment receiver
unregisterReceiver(receiver);
// Remove listeners
listener = null;
// Stop all controllers
while (controllers.size() > 0) {
// Stop and remove the controller
@@ -260,8 +297,28 @@ public class UsbDriverService extends Service implements UsbDriverListener {
}
}
@Override
public void onCreate() {
this.usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
this.prefConfig = PreferenceConfiguration.readPreferences(this);
}
@Override
public void onDestroy() {
stop();
// Remove listeners
listener = null;
stateListener = null;
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public interface UsbDriverStateListener {
void onUsbPermissionPromptStarting();
void onUsbPermissionPromptCompleted();
}
}
@@ -3,12 +3,12 @@ package com.limelight.binding.input.evdev;
import android.app.Activity;
import com.limelight.LimelightBuildProps;
import com.limelight.BuildConfig;
import com.limelight.binding.input.capture.InputCaptureProvider;
public class EvdevCaptureProviderShim {
public static boolean isCaptureProviderSupported() {
return LimelightBuildProps.ROOT_BUILD;
return BuildConfig.ROOT_BUILD;
}
// We need to construct our capture provider using reflection because it isn't included in non-root builds
@@ -1,14 +1,12 @@
package com.limelight.binding.input.touch;
import android.os.SystemClock;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.MouseButtonPacket;
import java.util.Timer;
import java.util.TimerTask;
public class AbsoluteTouchContext implements TouchContext {
private int lastTouchDownX = 0;
private int lastTouchDownY = 0;
@@ -21,12 +19,41 @@ public class AbsoluteTouchContext implements TouchContext {
private boolean cancelled;
private boolean confirmedLongPress;
private boolean confirmedTap;
private Timer longPressTimer;
private Timer tapDownTimer;
private final Runnable longPressRunnable = new Runnable() {
@Override
public void run() {
// This timer should have already expired, but cancel it just in case
cancelTapDownTimer();
// Switch from a left click to a right click after a long press
confirmedLongPress = true;
if (confirmedTap) {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
}
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT);
}
};
private final Runnable tapDownRunnable = new Runnable() {
@Override
public void run() {
// Start our tap
tapConfirmed();
}
};
private final NvConnection conn;
private final int actionIndex;
private final View targetView;
private final Handler handler;
private final Runnable leftButtonUpRunnable = new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
}
};
private static final int SCROLL_SPEED_FACTOR = 3;
@@ -44,6 +71,7 @@ public class AbsoluteTouchContext implements TouchContext {
this.conn = conn;
this.actionIndex = actionIndex;
this.targetView = view;
this.handler = new Handler(Looper.getMainLooper());
}
@Override
@@ -53,7 +81,7 @@ public class AbsoluteTouchContext implements TouchContext {
}
@Override
public boolean touchDownEvent(int eventX, int eventY, boolean isNewFinger)
public boolean touchDownEvent(int eventX, int eventY, long eventTime, boolean isNewFinger)
{
if (!isNewFinger) {
// We don't handle finger transitions for absolute mode
@@ -62,7 +90,7 @@ public class AbsoluteTouchContext implements TouchContext {
lastTouchLocationX = lastTouchDownX = eventX;
lastTouchLocationY = lastTouchDownY = eventY;
lastTouchDownTime = SystemClock.uptimeMillis();
lastTouchDownTime = eventTime;
cancelled = confirmedTap = confirmedLongPress = false;
if (actionIndex == 0) {
@@ -90,7 +118,7 @@ public class AbsoluteTouchContext implements TouchContext {
}
@Override
public void touchUpEvent(int eventX, int eventY)
public void touchUpEvent(int eventX, int eventY, long eventTime)
{
if (cancelled) {
return;
@@ -113,87 +141,35 @@ public class AbsoluteTouchContext implements TouchContext {
// deadzone time. We'll need to send the touch down and up events now at the
// original touch down position.
tapConfirmed();
try {
// FIXME: Sleeping on the main thread sucks
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
// InterruptedException clears the thread's interrupt status. Since we can't
// handle that here, we will re-interrupt the thread to set the interrupt
// status back to true.
Thread.currentThread().interrupt();
}
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
// Release the left mouse button in 100ms to allow for apps that use polling
// to detect mouse button presses.
handler.removeCallbacks(leftButtonUpRunnable);
handler.postDelayed(leftButtonUpRunnable, 100);
}
}
lastTouchLocationX = lastTouchUpX = eventX;
lastTouchLocationY = lastTouchUpY = eventY;
lastTouchUpTime = SystemClock.uptimeMillis();
lastTouchUpTime = eventTime;
}
private synchronized void startLongPressTimer() {
longPressTimer = new Timer(true);
longPressTimer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (AbsoluteTouchContext.this) {
// Check if someone cancelled us
if (longPressTimer == null) {
return;
}
// Uncancellable now
longPressTimer = null;
// This timer should have already expired, but cancel it just in case
cancelTapDownTimer();
// Switch from a left click to a right click after a long press
confirmedLongPress = true;
if (confirmedTap) {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
}
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_RIGHT);
}
}
}, LONG_PRESS_TIME_THRESHOLD);
private void startLongPressTimer() {
cancelLongPressTimer();
handler.postDelayed(longPressRunnable, LONG_PRESS_TIME_THRESHOLD);
}
private synchronized void cancelLongPressTimer() {
if (longPressTimer != null) {
longPressTimer.cancel();
longPressTimer = null;
}
private void cancelLongPressTimer() {
handler.removeCallbacks(longPressRunnable);
}
private synchronized void startTapDownTimer() {
tapDownTimer = new Timer(true);
tapDownTimer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (AbsoluteTouchContext.this) {
// Check if someone cancelled us
if (tapDownTimer == null) {
return;
}
// Uncancellable now
tapDownTimer = null;
// Start our tap
tapConfirmed();
}
}
}, TOUCH_DOWN_DEAD_ZONE_TIME_THRESHOLD);
private void startTapDownTimer() {
cancelTapDownTimer();
handler.postDelayed(tapDownRunnable, TOUCH_DOWN_DEAD_ZONE_TIME_THRESHOLD);
}
private synchronized void cancelTapDownTimer() {
if (tapDownTimer != null) {
tapDownTimer.cancel();
tapDownTimer = null;
}
private void cancelTapDownTimer() {
handler.removeCallbacks(tapDownRunnable);
}
private void tapConfirmed() {
@@ -214,7 +190,7 @@ public class AbsoluteTouchContext implements TouchContext {
}
@Override
public boolean touchMoveEvent(int eventX, int eventY)
public boolean touchMoveEvent(int eventX, int eventY, long eventTime)
{
if (cancelled) {
return true;
@@ -1,13 +1,12 @@
package com.limelight.binding.input.touch;
import android.os.SystemClock;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import com.limelight.nvstream.NvConnection;
import com.limelight.nvstream.input.MouseButtonPacket;
import java.util.Timer;
import java.util.TimerTask;
import com.limelight.preferences.PreferenceConfiguration;
public class RelativeTouchContext implements TouchContext {
private int lastTouchX = 0;
@@ -19,7 +18,6 @@ public class RelativeTouchContext implements TouchContext {
private boolean confirmedMove;
private boolean confirmedDrag;
private boolean confirmedScroll;
private Timer dragTimer;
private double distanceMoved;
private double xFactor, yFactor;
private int pointerCount;
@@ -30,6 +28,61 @@ public class RelativeTouchContext implements TouchContext {
private final int referenceWidth;
private final int referenceHeight;
private final View targetView;
private final PreferenceConfiguration prefConfig;
private final Handler handler;
private final Runnable dragTimerRunnable = new Runnable() {
@Override
public void run() {
// Check if someone already set move
if (confirmedMove) {
return;
}
// The drag should only be processed for the primary finger
if (actionIndex != maxPointerCountInGesture - 1) {
return;
}
// We haven't been cancelled before the timer expired so begin dragging
confirmedDrag = true;
conn.sendMouseButtonDown(getMouseButtonIndex());
}
};
// Indexed by MouseButtonPacket.BUTTON_XXX - 1
private final Runnable[] buttonUpRunnables = new Runnable[] {
new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
}
},
new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_MIDDLE);
}
},
new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_RIGHT);
}
},
new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_X1);
}
},
new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_X2);
}
}
};
private static final int TAP_MOVEMENT_THRESHOLD = 20;
private static final int TAP_DISTANCE_THRESHOLD = 25;
@@ -39,13 +92,16 @@ public class RelativeTouchContext implements TouchContext {
private static final int SCROLL_SPEED_FACTOR = 5;
public RelativeTouchContext(NvConnection conn, int actionIndex,
int referenceWidth, int referenceHeight, View view)
int referenceWidth, int referenceHeight,
View view, PreferenceConfiguration prefConfig)
{
this.conn = conn;
this.actionIndex = actionIndex;
this.referenceWidth = referenceWidth;
this.referenceHeight = referenceHeight;
this.targetView = view;
this.prefConfig = prefConfig;
this.handler = new Handler(Looper.getMainLooper());
}
@Override
@@ -62,7 +118,7 @@ public class RelativeTouchContext implements TouchContext {
yDelta <= TAP_MOVEMENT_THRESHOLD;
}
private boolean isTap()
private boolean isTap(long eventTime)
{
if (confirmedDrag || confirmedMove || confirmedScroll) {
return false;
@@ -75,7 +131,7 @@ public class RelativeTouchContext implements TouchContext {
return false;
}
long timeDelta = SystemClock.uptimeMillis() - originalTouchTime;
long timeDelta = eventTime - originalTouchTime;
return isWithinTapBounds(lastTouchX, lastTouchY) && timeDelta <= TAP_TIME_THRESHOLD;
}
@@ -90,7 +146,7 @@ public class RelativeTouchContext implements TouchContext {
}
@Override
public boolean touchDownEvent(int eventX, int eventY, boolean isNewFinger)
public boolean touchDownEvent(int eventX, int eventY, long eventTime, boolean isNewFinger)
{
// Get the view dimensions to scale inputs on this touch
xFactor = referenceWidth / (double)targetView.getWidth();
@@ -101,7 +157,7 @@ public class RelativeTouchContext implements TouchContext {
if (isNewFinger) {
maxPointerCountInGesture = pointerCount;
originalTouchTime = SystemClock.uptimeMillis();
originalTouchTime = eventTime;
cancelled = confirmedDrag = confirmedMove = confirmedScroll = false;
distanceMoved = 0;
@@ -115,7 +171,7 @@ public class RelativeTouchContext implements TouchContext {
}
@Override
public void touchUpEvent(int eventX, int eventY)
public void touchUpEvent(int eventX, int eventY, long eventTime)
{
if (cancelled) {
return;
@@ -130,72 +186,29 @@ public class RelativeTouchContext implements TouchContext {
// Raise the button after a drag
conn.sendMouseButtonUp(buttonIndex);
}
else if (isTap())
else if (isTap(eventTime))
{
// Lower the mouse button
conn.sendMouseButtonDown(buttonIndex);
// We need to sleep a bit here because some games
// do input detection by polling
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
// InterruptedException clears the thread's interrupt status. Since we can't
// handle that here, we will re-interrupt the thread to set the interrupt
// status back to true.
Thread.currentThread().interrupt();
}
// Raise the mouse button
conn.sendMouseButtonUp(buttonIndex);
// Release the mouse button in 100ms to allow for apps that use polling
// to detect mouse button presses.
Runnable buttonUpRunnable = buttonUpRunnables[buttonIndex - 1];
handler.removeCallbacks(buttonUpRunnable);
handler.postDelayed(buttonUpRunnable, 100);
}
}
private synchronized void startDragTimer() {
// Cancel any existing drag timers
private void startDragTimer() {
cancelDragTimer();
dragTimer = new Timer(true);
dragTimer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (RelativeTouchContext.this) {
// Check if someone already set move
if (confirmedMove) {
return;
}
// The drag should only be processed for the primary finger
if (actionIndex != maxPointerCountInGesture - 1) {
return;
}
// Check if someone cancelled us
if (dragTimer == null) {
return;
}
// Uncancellable now
dragTimer = null;
// We haven't been cancelled before the timer expired so begin dragging
confirmedDrag = true;
conn.sendMouseButtonDown(getMouseButtonIndex());
}
}
}, DRAG_TIME_THRESHOLD);
handler.postDelayed(dragTimerRunnable, DRAG_TIME_THRESHOLD);
}
private synchronized void cancelDragTimer() {
if (dragTimer != null) {
dragTimer.cancel();
dragTimer = null;
}
private void cancelDragTimer() {
handler.removeCallbacks(dragTimerRunnable);
}
private synchronized void checkForConfirmedMove(int eventX, int eventY) {
private void checkForConfirmedMove(int eventX, int eventY) {
// If we've already confirmed something, get out now
if (confirmedMove || confirmedDrag) {
return;
@@ -225,7 +238,7 @@ public class RelativeTouchContext implements TouchContext {
}
@Override
public boolean touchMoveEvent(int eventX, int eventY)
public boolean touchMoveEvent(int eventX, int eventY, long eventTime)
{
if (cancelled) {
return true;
@@ -258,7 +271,16 @@ public class RelativeTouchContext implements TouchContext {
conn.sendMouseHighResScroll((short)(deltaY * SCROLL_SPEED_FACTOR));
}
} else {
conn.sendMouseMove((short) deltaX, (short) deltaY);
if (prefConfig.absoluteMouseMode) {
conn.sendMouseMoveAsMousePosition(
(short) deltaX,
(short) deltaY,
(short) targetView.getWidth(),
(short) targetView.getHeight());
}
else {
conn.sendMouseMove((short) deltaX, (short) deltaY);
}
}
// If the scaling factor ended up rounding deltas to zero, wait until they are
@@ -3,9 +3,9 @@ package com.limelight.binding.input.touch;
public interface TouchContext {
int getActionIndex();
void setPointerCount(int pointerCount);
boolean touchDownEvent(int eventX, int eventY, boolean isNewFinger);
boolean touchMoveEvent(int eventX, int eventY);
void touchUpEvent(int eventX, int eventY);
boolean touchDownEvent(int eventX, int eventY, long eventTime, boolean isNewFinger);
boolean touchMoveEvent(int eventX, int eventY, long eventTime);
void touchUpEvent(int eventX, int eventY, long eventTime);
void cancelTouch();
boolean isCancelled();
}
@@ -8,7 +8,6 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.SystemClock;
import android.view.MotionEvent;
import java.util.ArrayList;
@@ -254,7 +253,7 @@ public class AnalogStick extends VirtualControllerElement {
}
}
private void updatePosition() {
private void updatePosition(long eventTime) {
// get 100% way
float complete = radius_complete - radius_analog_stick;
@@ -271,7 +270,7 @@ public class AnalogStick extends VirtualControllerElement {
// We also release the deadzone if the user keeps the stick pressed for a bit to allow
// them to make precise movements.
stick_state = (stick_state == STICK_STATE.MOVED_ACTIVE ||
SystemClock.uptimeMillis() - timeLastClick > timeoutDeadzone ||
eventTime - timeLastClick > timeoutDeadzone ||
movement_radius > radius_dead_zone) ?
STICK_STATE.MOVED_ACTIVE : STICK_STATE.MOVED_IN_DEAD_ZONE;
@@ -306,13 +305,12 @@ public class AnalogStick extends VirtualControllerElement {
// handle event depending on action
switch (event.getActionMasked()) {
// down event (touch event)
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
case MotionEvent.ACTION_DOWN: {
// set to dead zoned, will be corrected in update position if necessary
stick_state = STICK_STATE.MOVED_IN_DEAD_ZONE;
// check for double click
if (lastClickState == CLICK_STATE.SINGLE &&
timeLastClick + timeoutDoubleClick > SystemClock.uptimeMillis()) {
event.getEventTime() - timeLastClick <= timeoutDoubleClick) {
click_state = CLICK_STATE.DOUBLE;
notifyOnDoubleClick();
} else {
@@ -320,14 +318,14 @@ public class AnalogStick extends VirtualControllerElement {
notifyOnClick();
}
// reset last click timestamp
timeLastClick = SystemClock.uptimeMillis();
timeLastClick = event.getEventTime();
// set item pressed and update
setPressed(true);
break;
}
// up event (revoke touch)
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
setPressed(false);
break;
}
@@ -335,7 +333,7 @@ public class AnalogStick extends VirtualControllerElement {
if (isPressed()) {
// when is pressed calculate new positions (will trigger movement if necessary)
updatePosition();
updatePosition(event.getEventTime());
} else {
stick_state = STICK_STATE.NO_MOVEMENT;
notifyOnRevoke();
@@ -14,8 +14,6 @@ import android.view.MotionEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* This is a digital button on screen element. It is used to get click and double click user input.
@@ -43,22 +41,16 @@ public class DigitalButton extends VirtualControllerElement {
void onRelease();
}
/**
*
*/
private class TimerLongClickTimerTask extends TimerTask {
@Override
public void run() {
onLongClickCallback();
}
}
private List<DigitalButtonListener> listeners = new ArrayList<>();
private String text = "";
private int icon = -1;
private long timerLongClickTimeout = 3000;
private Timer timerLongClick = null;
private TimerLongClickTimerTask longClickTimerTask = null;
private final Runnable longClickRunnable = new Runnable() {
@Override
public void run() {
onLongClickCallback();
}
};
private final Paint paint = new Paint();
private final RectF rect = new RectF();
@@ -177,18 +169,8 @@ public class DigitalButton extends VirtualControllerElement {
listener.onClick();
}
if (timerLongClick != null) {
timerLongClick.cancel();
timerLongClick = null;
}
if (longClickTimerTask != null) {
longClickTimerTask.cancel();
longClickTimerTask = null;
}
timerLongClick = new Timer();
longClickTimerTask = new TimerLongClickTimerTask();
timerLongClick.schedule(longClickTimerTask, timerLongClickTimeout);
virtualController.getHandler().removeCallbacks(longClickRunnable);
virtualController.getHandler().postDelayed(longClickRunnable, timerLongClickTimeout);
}
private void onLongClickCallback() {
@@ -207,14 +189,7 @@ public class DigitalButton extends VirtualControllerElement {
}
// We may be called for a release without a prior click
if (timerLongClick != null) {
timerLongClick.cancel();
timerLongClick = null;
}
if (longClickTimerTask != null) {
longClickTimerTask.cancel();
longClickTimerTask = null;
}
virtualController.getHandler().removeCallbacks(longClickRunnable);
}
@Override
@@ -225,8 +200,7 @@ public class DigitalButton extends VirtualControllerElement {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
case MotionEvent.ACTION_DOWN: {
movingButton = null;
setPressed(true);
onClickCallback();
@@ -241,8 +215,7 @@ public class DigitalButton extends VirtualControllerElement {
return true;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
case MotionEvent.ACTION_UP: {
setPressed(false);
onReleaseCallback();
@@ -162,7 +162,6 @@ public class DigitalPad extends VirtualControllerElement {
// get masked (not specific to a pointer) action
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_MOVE: {
direction = 0;
@@ -184,8 +183,7 @@ public class DigitalPad extends VirtualControllerElement {
return true;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
case MotionEvent.ACTION_UP: {
direction = 0;
newDirectionCallback(direction);
invalidate();
@@ -5,6 +5,8 @@
package com.limelight.binding.input.virtual_controller;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
@@ -17,8 +19,6 @@ import com.limelight.binding.input.ControllerHandler;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class VirtualController {
public static class ControllerInputContext {
@@ -41,11 +41,17 @@ public class VirtualController {
private final ControllerHandler controllerHandler;
private final Context context;
private final Handler handler;
private final Runnable delayedRetransmitRunnable = new Runnable() {
@Override
public void run() {
sendControllerInputContextInternal();
}
};
private FrameLayout frame_layout = null;
private Timer retransmitTimer;
ControllerMode currentMode = ControllerMode.Active;
ControllerInputContext inputContext = new ControllerInputContext();
@@ -57,6 +63,7 @@ public class VirtualController {
this.controllerHandler = controllerHandler;
this.frame_layout = layout;
this.context = context;
this.handler = new Handler(Looper.getMainLooper());
buttonConfigure = new Button(context);
buttonConfigure.setAlpha(0.25f);
@@ -91,9 +98,11 @@ public class VirtualController {
}
public void hide() {
retransmitTimer.cancel();
Handler getHandler() {
return handler;
}
public void hide() {
for (VirtualControllerElement element : elements) {
element.setVisibility(View.INVISIBLE);
}
@@ -107,18 +116,6 @@ public class VirtualController {
}
buttonConfigure.setVisibility(View.VISIBLE);
// HACK: GFE sometimes discards gamepad packets when they are received
// very shortly after another. This can be critical if an axis zeroing packet
// is lost and causes an analog stick to get stuck. To avoid this, we send
// a gamepad input packet every 100 ms to ensure any loss can be recovered.
retransmitTimer = new Timer("OSC timer", true);
retransmitTimer.schedule(new TimerTask() {
@Override
public void run() {
sendControllerInputContext();
}
}, 100, 100);
}
public void removeElements() {
@@ -181,7 +178,7 @@ public class VirtualController {
return inputContext;
}
void sendControllerInputContext() {
private void sendControllerInputContextInternal() {
_DBG("INPUT_MAP + " + inputContext.inputMap);
_DBG("LEFT_TRIGGER " + inputContext.leftTrigger);
_DBG("RIGHT_TRIGGER " + inputContext.rightTrigger);
@@ -200,4 +197,19 @@ public class VirtualController {
);
}
}
void sendControllerInputContext() {
// Cancel retransmissions of prior gamepad inputs
handler.removeCallbacks(delayedRetransmitRunnable);
sendControllerInputContextInternal();
// HACK: GFE sometimes discards gamepad packets when they are received
// very shortly after another. This can be critical if an axis zeroing packet
// is lost and causes an analog stick to get stuck. To avoid this, we retransmit
// the gamepad state a few times unless another input event happens before then.
handler.postDelayed(delayedRetransmitRunnable, 25);
handler.postDelayed(delayedRetransmitRunnable, 50);
handler.postDelayed(delayedRetransmitRunnable, 75);
}
}
@@ -40,27 +40,31 @@ public class VirtualControllerConfigurationLoader {
VirtualController.ControllerInputContext inputContext =
controller.getControllerInputContext();
if (direction == DigitalPad.DIGITAL_PAD_DIRECTION_NO_DIRECTION) {
inputContext.inputMap &= ~ControllerPacket.LEFT_FLAG;
inputContext.inputMap &= ~ControllerPacket.RIGHT_FLAG;
inputContext.inputMap &= ~ControllerPacket.UP_FLAG;
inputContext.inputMap &= ~ControllerPacket.DOWN_FLAG;
controller.sendControllerInputContext();
return;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) > 0) {
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_LEFT) != 0) {
inputContext.inputMap |= ControllerPacket.LEFT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) > 0) {
else {
inputContext.inputMap &= ~ControllerPacket.LEFT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_RIGHT) != 0) {
inputContext.inputMap |= ControllerPacket.RIGHT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) > 0) {
else {
inputContext.inputMap &= ~ControllerPacket.RIGHT_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_UP) != 0) {
inputContext.inputMap |= ControllerPacket.UP_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) > 0) {
else {
inputContext.inputMap &= ~ControllerPacket.UP_FLAG;
}
if ((direction & DigitalPad.DIGITAL_PAD_DIRECTION_DOWN) != 0) {
inputContext.inputMap |= ControllerPacket.DOWN_FLAG;
}
else {
inputContext.inputMap &= ~ControllerPacket.DOWN_FLAG;
}
controller.sendControllerInputContext();
}
});
@@ -223,13 +223,21 @@ public abstract class VirtualControllerElement extends View {
@Override
public boolean onTouchEvent(MotionEvent event) {
// Ignore secondary touches on controls
//
// NB: We can get an additional pointer down if the user touches a non-StreamView area
// while also touching an OSC control, even if that pointer down doesn't correspond to
// an area of the OSC control.
if (event.getActionIndex() != 0) {
return true;
}
if (virtualController.getControllerMode() == VirtualController.ControllerMode.Active) {
return onElementTouchEvent(event);
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: {
case MotionEvent.ACTION_DOWN: {
position_pressed_x = event.getX();
position_pressed_y = event.getY();
startSize_x = getWidth();
@@ -267,8 +275,7 @@ public abstract class VirtualControllerElement extends View {
return true;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: {
case MotionEvent.ACTION_UP: {
actionCancel();
return true;
}
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,18 +32,21 @@ 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;
private static final List<String> whitelistedHevcDecoders;
private static final List<String> refFrameInvalidationAvcPrefixes;
private static final List<String> refFrameInvalidationHevcPrefixes;
private static final List<String> useFourSlicesPrefixes;
private static final List<String> qualcommDecoderPrefixes;
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 IS_EMULATOR = Build.HARDWARE.equals("ranchu") || Build.HARDWARE.equals("cheets");
public static final boolean SHOULD_BYPASS_SOFTWARE_BLOCK =
Build.HARDWARE.equals("ranchu") || Build.HARDWARE.equals("cheets") || Build.BRAND.equals("Android-x86");
private static boolean isLowEndSnapdragon = false;
private static boolean isAdreno620 = false;
@@ -68,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
}
@@ -80,18 +87,18 @@ public class MediaCodecHelper {
static {
blacklistedDecoderPrefixes = new LinkedList<>();
// Blacklist software decoders that don't support H264 high profile,
// but exclude the official AOSP and CrOS emulator from this restriction.
if (!IS_EMULATOR) {
// Blacklist software decoders that don't support H264 high profile except on systems
// that are expected to only have software decoders (like emulators).
if (!SHOULD_BYPASS_SOFTWARE_BLOCK) {
blacklistedDecoderPrefixes.add("omx.google");
blacklistedDecoderPrefixes.add("AVCDecoder");
}
// We want to avoid ffmpeg decoders since they're software decoders,
// but on Android-x86 they might be all we have (and also relatively
// performant on a modern x86 processor).
if (!Build.BRAND.equals("Android-x86")) {
blacklistedDecoderPrefixes.add("OMX.ffmpeg");
// We want to avoid ffmpeg decoders since they're usually software decoders,
// but we'll defer to the Android 10 isSoftwareOnly() API on newer devices
// to determine if we should use these or not.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
blacklistedDecoderPrefixes.add("OMX.ffmpeg");
}
}
// Force these decoders disabled because:
@@ -135,24 +142,26 @@ public class MediaCodecHelper {
// Exynos seems to be the only HEVC decoder that works reliably
whitelistedHevcDecoders.add("omx.exynos");
// On Darcy (Shield 2017), HEVC runs fine with no fixups required.
// For some reason, other X1 implementations require bitstream fixups.
if (Build.DEVICE.equalsIgnoreCase("darcy")) {
// On Darcy (Shield 2017), HEVC runs fine with no fixups required. For some reason,
// other X1 implementations require bitstream fixups. However, since numReferenceFrames
// has been supported in GFE since late 2017, we'll go ahead and enable HEVC for all
// device models.
//
// NVIDIA does partial HEVC acceleration on the Shield Tablet. I don't know
// whether the performance is good enough to use for streaming, but they're
// using the same omx.nvidia.h265.decode name as the Shield TV which has a
// fully accelerated HEVC pipeline. AFAIK, the only K1 devices with this
// partially accelerated HEVC decoder are the Shield Tablet and Xiaomi MiPad,
// so I'll check for those here.
//
// In case there are some that I missed, I will also exclude pre-Oreo OSes since
// only Shield ATV got an Oreo update and any newer Tegra devices will not ship
// with an old OS like Nougat.
if (!Build.DEVICE.equalsIgnoreCase("shieldtablet") &&
!Build.DEVICE.equalsIgnoreCase("mocha") &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
whitelistedHevcDecoders.add("omx.nvidia");
}
else {
// TODO: This needs a similar fixup to the Tegra 3 otherwise it buffers 16 frames
}
// Older Sony ATVs (SVP-DTV15) have broken MediaTek codecs (decoder hangs after rendering the first frame).
// I know the Fire TV 2 and 3 works, so I'll whitelist Amazon devices which seem to actually be tested.
if (Build.MANUFACTURER.equalsIgnoreCase("Amazon")) {
whitelistedHevcDecoders.add("omx.mtk");
// This broke at some point on the Fire TV 3 and now the decoder
// never produces any output frames.
//whitelistedHevcDecoders.add("omx.amlogic");
}
// Plot twist: On newer Sony devices (BRAVIA_ATV2, BRAVIA_ATV3_4K, BRAVIA_UR1_4K) the H.264 decoder crashes
// on several configurations (> 60 FPS and 1440p) that work with HEVC, so we'll whitelist those devices for HEVC.
@@ -162,8 +171,17 @@ public class MediaCodecHelper {
// Amlogic requires 1 reference frame for HEVC to avoid hanging. Since it's been years
// since GFE added support for maxNumReferenceFrames, we'll just enable all Amlogic SoCs
// running Android 9 or later. HEVC is much lower latency than H.264 on Sabrina (S905X2).
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// running Android 9 or later.
//
// NB: We don't do this on Sabrina (GCWGTV) because H.264 is lower latency when we use
// 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");
}
@@ -185,11 +203,24 @@ public class MediaCodecHelper {
}
static {
deprioritizedHevcDecoders = new LinkedList<>();
useFourSlicesPrefixes = new LinkedList<>();
// These are decoders that work but aren't used by default for various reasons.
// Software decoders will use 4 slices per frame to allow for slice multithreading
useFourSlicesPrefixes.add("omx.google");
useFourSlicesPrefixes.add("AVCDecoder");
useFourSlicesPrefixes.add("omx.ffmpeg");
useFourSlicesPrefixes.add("c2.android");
// Qualcomm is currently the only decoders in this group.
// 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 {
@@ -203,12 +234,21 @@ public class MediaCodecHelper {
kirinDecoderPrefixes = new LinkedList<>();
kirinDecoderPrefixes.add("omx.hisi");
kirinDecoderPrefixes.add("c2.hisi"); // Unconfirmed
}
static {
exynosDecoderPrefixes = new LinkedList<>();
exynosDecoderPrefixes.add("omx.exynos");
exynosDecoderPrefixes.add("c2.exynos");
}
static {
amlogicDecoderPrefixes = new LinkedList<>();
amlogicDecoderPrefixes.add("omx.amlogic");
amlogicDecoderPrefixes.add("c2.amlogic"); // Unconfirmed
}
private static boolean isPowerVR(String glRenderer) {
@@ -269,6 +309,40 @@ public class MediaCodecHelper {
return;
}
// Older Sony ATVs (SVP-DTV15) have broken MediaTek codecs (decoder hangs after rendering the first frame).
// I know the Fire TV 2 and 3 works, so I'll whitelist Amazon devices which seem to actually be tested.
// 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 =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
@@ -280,19 +354,17 @@ 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");
refFrameInvalidationHevcPrefixes.add("omx.nvidia");
refFrameInvalidationAvcPrefixes.add("c2.nvidia"); // Unconfirmed
refFrameInvalidationHevcPrefixes.add("c2.nvidia"); // Unconfirmed
LimeLog.info("Added omx.qcom/c2.qti to AVC reference frame invalidation support list");
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");
// 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");
}
refFrameInvalidationHevcPrefixes.add("c2.qti");
}
// Qualcomm's early HEVC decoders break hard on our HEVC stream. The best check to
@@ -304,16 +376,15 @@ 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");
// These older decoders need 4 slices per frame for best performance
useFourSlicesPrefixes.add("omx.qcom");
}
// Older MediaTek SoCs have issues with HEVC rendering but the newer chips with
@@ -327,8 +398,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");
}
}
}
@@ -353,10 +425,6 @@ public class MediaCodecHelper {
return false;
}
public static long getMonotonicMillis() {
return System.nanoTime() / 1000000L;
}
private static boolean decoderSupportsAndroidRLowLatency(MediaCodecInfo decoderInfo, String mimeType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
@@ -373,6 +441,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)
@@ -388,41 +485,119 @@ public class MediaCodecHelper {
!isAdreno620;
}
public static void setDecoderLowLatencyOptions(MediaFormat videoFormat, MediaCodecInfo decoderInfo, String mimeType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && decoderSupportsAndroidRLowLatency(decoderInfo, mimeType)) {
videoFormat.setInteger(MediaFormat.KEY_LOW_LATENCY, 1);
public static boolean setDecoderLowLatencyOptions(MediaFormat videoFormat, MediaCodecInfo decoderInfo, int tryNumber) {
// Options here should be tried in the order of most to least risky. The decoder will use
// the first MediaFormat that doesn't fail in configure().
boolean setNewOption = false;
if (tryNumber < 1) {
// Official Android 11+ low latency option (KEY_LOW_LATENCY).
videoFormat.setInteger("low-latency", 1);
setNewOption = true;
// If this decoder officially supports FEATURE_LowLatency, we will just use that alone
// for try 0. Otherwise, we'll include it as best effort with other options.
if (decoderSupportsAndroidRLowLatency(decoderInfo, videoFormat.getString(MediaFormat.KEY_MIME))) {
return true;
}
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// 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
if (tryNumber < 2 &&
(!Build.MANUFACTURER.equalsIgnoreCase("xiaomi") || Build.VERSION.SDK_INT > Build.VERSION_CODES.M)) {
// MediaTek decoders don't use vendor-defined keys for low latency mode. Instead, they have a modified
// version of AOSP's ACodec.cpp which supports the "vdec-lowlatency" option. This option is passed down
// to the decoder as OMX.MTK.index.param.video.LowLatencyDecode.
//
// MediaCodec vendor extension support was introduced in Android 8.0:
// 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
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
videoFormat.setInteger("vendor.qti-ext-dec-low-latency.enable", 1);
// This option is also plumbed for Amazon Amlogic-based devices like the Fire TV 3. Not only does it
// reduce latency on Amlogic, it fixes the HEVC bug that causes the decoder to not output any frames.
// Unfortunately, it does the exact opposite for the Xiaomi MITV4-ANSM0, breaking it in the way that
// Fire TV was broken prior to vdec-lowlatency :(
//
// On Fire TV 3, vdec-lowlatency is translated to OMX.amazon.fireos.index.video.lowLatencyDecode.
//
// https://github.com/yuan1617/Framwork/blob/master/frameworks/av/media/libstagefright/ACodec.cpp
// https://github.com/iykex/vendor_mediatek_proprietary_hardware/blob/master/libomx/video/MtkOmxVdecEx/MtkOmxVdecEx.h
videoFormat.setInteger("vdec-lowlatency", 1);
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
//
// MediaCodec vendor extension support was introduced in Android 8.0:
// 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) {
videoFormat.setInteger("vendor.qti-ext-dec-picture-order.enable", 1);
setNewOption = true;
}
else if (isDecoderInList(kirinDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 4) {
videoFormat.setInteger("vendor.qti-ext-dec-low-latency.enable", 1);
setNewOption = true;
}
}
else if (isDecoderInList(kirinDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
// 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);
videoFormat.setInteger("vendor.hisi-ext-low-latency-video-dec.video-scene-for-low-latency-rdy", -1);
setNewOption = true;
}
else if (isDecoderInList(exynosDecoderPrefixes, decoderInfo.getName())) {
}
else if (isDecoderInList(exynosDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
// Exynos low latency option for H.264 decoder
videoFormat.setInteger("vendor.rtc-ext-dec-low-latency.enable", 1);
setNewOption = true;
}
}
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(decoderInfo.getName())) {
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
else if (isDecoderInList(amlogicDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
// Amlogic low latency vendor extension
// https://github.com/codewalkerster/android_vendor_amlogic_common_prebuilt_libstagefrighthw/commit/41fefc4e035c476d58491324a5fe7666bfc2989e
videoFormat.setInteger("vendor.low-latency.enable", 1);
setNewOption = true;
}
}
}
// 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;
}
public static boolean decoderSupportsFusedIdrFrame(MediaCodecInfo decoderInfo, String mimeType) {
// If adaptive playback is supported, we can submit new CSD together with a keyframe
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
try {
if (decoderInfo.getCapabilitiesForType(mimeType).
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
{
LimeLog.info("Decoder supports fused IDR frames (FEATURE_AdaptivePlayback)");
return true;
}
} catch (Exception e) {
// Tolerate buggy codecs
e.printStackTrace();
}
}
return false;
}
public static boolean decoderSupportsAdaptivePlayback(MediaCodecInfo decoderInfo, String mimeType) {
@@ -466,6 +641,17 @@ public class MediaCodecHelper {
return isDecoderInList(baselineProfileHackPrefixes, decoderName);
}
public static byte getDecoderOptimalSlicesPerFrame(String decoderName) {
if (isDecoderInList(useFourSlicesPrefixes, decoderName)) {
// 4 slices per frame reduces decoding latency on older Qualcomm devices
return 4;
}
else {
// 1 slice per frame produces the optimal encoding efficiency
return 1;
}
}
public static boolean decoderSupportsRefFrameInvalidationAvc(String decoderName, int videoHeight) {
// Reference frame invalidation is broken on low-end Snapdragon SoCs at 1080p.
if (videoHeight > 720 && isLowEndSnapdragon) {
@@ -481,25 +667,24 @@ 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) {
// TODO: Shield Tablet K1/LTE?
//
// NVIDIA does partial HEVC acceleration on the Shield Tablet. I don't know
// whether the performance is good enough to use for streaming, but they're
// using the same omx.nvidia.h265.decode name as the Shield TV which has a
// fully accelerated HEVC pipeline. AFAIK, the only K1 device with this
// partially accelerated HEVC decoder is the Shield Tablet, so I'll
// check for it here.
//
// TODO: Temporarily disabled with NVIDIA HEVC support
/*if (Build.DEVICE.equalsIgnoreCase("shieldtablet")) {
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.
@@ -513,26 +698,36 @@ 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());
}
@SuppressWarnings("deprecation")
@@ -605,7 +800,7 @@ public class MediaCodecHelper {
private static boolean isCodecBlacklisted(MediaCodecInfo codecInfo) {
// Use the new isSoftwareOnly() function on Android Q
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (!IS_EMULATOR && codecInfo.isSoftwareOnly()) {
if (!SHOULD_BYPASS_SOFTWARE_BLOCK && codecInfo.isSoftwareOnly()) {
LimeLog.info("Skipping software-only decoder: "+codecInfo.getName());
return true;
}
@@ -736,8 +931,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)
@@ -746,8 +940,6 @@ public class MediaCodecHelper {
}
return cpuInfo.toString();
} finally {
br.close();
}
}
@@ -10,6 +10,7 @@ import java.util.List;
import java.util.Locale;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvHTTP;
import android.content.ContentValues;
import android.content.Context;
@@ -27,6 +28,7 @@ public class ComputerDatabaseManager {
private static final String SERVER_CERT_COLUMN_NAME = "ServerCert";
private static final char ADDRESS_DELIMITER = ';';
private static final char PORT_DELIMITER = '_';
private SQLiteDatabase computerDb;
@@ -74,10 +76,10 @@ public class ComputerDatabaseManager {
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 : "");
addresses.append(details.localAddress != null ? splitTupleToAddress(details.localAddress) : "");
addresses.append(ADDRESS_DELIMITER).append(details.remoteAddress != null ? splitTupleToAddress(details.remoteAddress) : "");
addresses.append(ADDRESS_DELIMITER).append(details.manualAddress != null ? splitTupleToAddress(details.manualAddress) : "");
addresses.append(ADDRESS_DELIMITER).append(details.ipv6Address != null ? splitTupleToAddress(details.ipv6Address) : "");
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
values.put(MAC_ADDRESS_COLUMN_NAME, details.macAddress);
@@ -103,6 +105,24 @@ public class ComputerDatabaseManager {
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 ComputerDetails getComputerFromCursor(Cursor c) {
ComputerDetails details = new ComputerDetails();
@@ -111,10 +131,18 @@ public class ComputerDatabaseManager {
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]);
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);
@@ -136,28 +164,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 {
@@ -543,12 +550,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 +588,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 +607,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 +641,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 +746,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 +876,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 +904,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);
}
}
@@ -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,14 @@
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 X509Certificate serverCert;
public StreamConfiguration streamConfig;
public NvConnectionListener connListener;
@@ -22,5 +25,8 @@ public class ConnectionContext {
public int negotiatedWidth, negotiatedHeight;
public boolean negotiatedHdr;
public int negotiatedRemoteStreaming;
public int negotiatedPacketSize;
public int videoCapabilities;
}
@@ -1,12 +1,27 @@
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.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Semaphore;
import javax.crypto.KeyGenerator;
@@ -17,6 +32,7 @@ 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.ComputerDetails;
import com.limelight.nvstream.http.GfeHttpResponseException;
import com.limelight.nvstream.http.LimelightCryptoProvider;
import com.limelight.nvstream.http.NvApp;
@@ -27,26 +43,36 @@ 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;
public NvConnection(String host, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert)
{
this.host = host;
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(Context appContext, ComputerDetails.AddressTuple host, int httpsPort, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert, boolean batchMouseInput)
{
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();
}
@@ -70,6 +96,11 @@ public class NvConnection {
}
public void stop() {
// Stop sending additional input
if (mouseInputTimer != null) {
mouseInputTimer.cancel();
}
// Interrupt any pending connection. This is thread-safe.
MoonBridge.interruptConnection();
@@ -83,12 +114,148 @@ public class NvConnection {
// Now a pending connection can be processed
connectionAllowed.release();
}
private void flushMousePosition() {
synchronized (mouseInputLock) {
if (relMouseX != 0 || relMouseY != 0) {
if (relMouseWidth != 0 || relMouseHeight != 0) {
MoonBridge.sendMouseMoveAsMousePosition(relMouseX, relMouseY, relMouseWidth, relMouseHeight);
}
else {
MoonBridge.sendMouseMove(relMouseX, relMouseY);
}
relMouseX = relMouseY = relMouseWidth = relMouseHeight = 0;
}
if (absMouseX != 0 || absMouseY != 0 || absMouseWidth != 0 || absMouseHeight != 0) {
MoonBridge.sendMousePosition(absMouseX, absMouseY, absMouseWidth, absMouseHeight);
absMouseX = absMouseY = absMouseWidth = absMouseHeight = 0;
}
}
}
private 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) {
@@ -138,6 +305,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
@@ -236,7 +415,6 @@ public class NvConnection {
String appName = context.streamConfig.getApp().getAppName();
context.serverAddress = host;
context.connListener.stageStarting(appName);
try {
@@ -274,24 +452,41 @@ 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.negotiatedWidth, context.negotiatedHeight,
context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(),
context.streamConfig.getMaxPacketSize(),
context.streamConfig.getRemote(), context.streamConfig.getAudioConfiguration().toInt(),
context.negotiatedPacketSize, context.negotiatedRemoteStreaming,
context.streamConfig.getAudioConfiguration().toInt(),
context.streamConfig.getHevcSupported(),
context.negotiatedHdr,
context.streamConfig.getHevcBitratePercentageMultiplier(),
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
// semaphore count for them.
connectionAllowed.release();
return;
}
if (batchMouseInput) {
// High polling rate mice can cause GeForce Experience's input queue to get backed up,
// causing massive input latency. We counter this by limiting our mouse events to 200 Hz
// which appears to avoid triggering the issue on all known configurations.
mouseInputTimer = new Timer("MouseInput", true);
mouseInputTimer.schedule(new TimerTask() {
@Override
public void run() {
// Flush the mouse position every 5 ms
flushMousePosition();
}
}, MOUSE_BATCH_PERIOD_MS, MOUSE_BATCH_PERIOD_MS);
}
}
}
@@ -301,20 +496,65 @@ public class NvConnection {
public void sendMouseMove(final short deltaX, final short deltaY)
{
if (!isMonkey) {
MoonBridge.sendMouseMove(deltaX, deltaY);
synchronized (mouseInputLock) {
relMouseX += deltaX;
relMouseY += deltaY;
// Reset these to ensure we don't send this as a position update
relMouseWidth = 0;
relMouseHeight = 0;
}
if (!batchMouseInput) {
flushMousePosition();
}
}
}
public void sendMousePosition(short x, short y, short referenceWidth, short referenceHeight)
{
if (!isMonkey) {
MoonBridge.sendMousePosition(x, y, referenceWidth, referenceHeight);
synchronized (mouseInputLock) {
absMouseX = x;
absMouseY = y;
absMouseWidth = referenceWidth;
absMouseHeight = referenceHeight;
}
if (!batchMouseInput) {
flushMousePosition();
}
}
}
public void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight)
{
if (!isMonkey) {
synchronized (mouseInputLock) {
// Only accumulate the delta if the reference size is the same
if (relMouseWidth == referenceWidth && relMouseHeight == referenceHeight) {
relMouseX += deltaX;
relMouseY += deltaY;
}
else {
relMouseX = deltaX;
relMouseY = deltaY;
}
relMouseWidth = referenceWidth;
relMouseHeight = referenceHeight;
}
if (!batchMouseInput) {
flushMousePosition();
}
}
}
public void sendMouseButtonDown(final byte mouseButton)
{
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseButton(MouseButtonPacket.PRESS_EVENT, mouseButton);
}
}
@@ -322,6 +562,7 @@ public class NvConnection {
public void sendMouseButtonUp(final byte mouseButton)
{
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseButton(MouseButtonPacket.RELEASE_EVENT, mouseButton);
}
}
@@ -357,12 +598,14 @@ public class NvConnection {
public void sendMouseScroll(final byte scrollClicks) {
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseScroll(scrollClicks);
}
}
public void sendMouseHighResScroll(final short scrollAmount) {
if (!isMonkey) {
flushMousePosition();
MoonBridge.sendMouseHighResScroll(scrollAmount);
}
}
@@ -27,6 +27,8 @@ public class StreamConfiguration {
private boolean enableHdr;
private int attachedGamepadMask;
private int encryptionFlags;
private int colorRange;
private int colorSpace;
public static class Builder {
private StreamConfiguration config = new StreamConfiguration();
@@ -131,7 +133,17 @@ public class StreamConfiguration {
config.supportsHevc = supportsHevc;
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;
}
@@ -226,4 +238,12 @@ public class StreamConfiguration {
public int getEncryptionFlags() {
return encryptionFlags;
}
public int getColorRange() {
return colorRange;
}
public int getColorSpace() {
return colorSpace;
}
}
@@ -10,7 +10,7 @@ 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, long receiveTimeMs, long enqueueTimeMs);
int frameNumber, int frameType, long receiveTimeMs, long enqueueTimeMs);
public abstract void cleanup();
@@ -8,19 +8,69 @@ 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 address.hashCode();
}
@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;
@@ -35,6 +85,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 +114,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,6 +138,8 @@ 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.rawAppList = details.rawAppList;
@@ -80,6 +159,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();
}
}
@@ -63,7 +63,7 @@ public class NvApp {
public String toString() {
StringBuilder str = new StringBuilder();
str.append("Name: ").append(appName).append("\n");
str.append("HDR: ").append(hdrSupported ? "Yes" : "No").append("\n");
str.append("HDR Supported: ").append(hdrSupported ? "Yes" : "Unknown").append("\n");
str.append("ID: ").append(appId).append("\n");
return str.toString();
}
@@ -9,6 +9,7 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.KeyStore;
@@ -61,19 +62,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;
@@ -166,19 +170,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)
.build();
httpClientWithReadTimeout = httpClient.newBuilder()
.readTimeout(READ_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(LONG_CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.proxy(Proxy.NO_PROXY)
.build();
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";
@@ -187,17 +206,13 @@ public class NvHTTP {
initializeHttpState(cryptoProvider);
this.httpsPort = httpsPort;
try {
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(address.address)
.port(address.port)
.build();
} catch (IllegalArgumentException e) {
// Encapsulate IllegalArgumentException into IOException for callers to handle more easily
@@ -269,8 +284,11 @@ public class NvHTTP {
}
}
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.
@@ -282,7 +300,7 @@ 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) {
@@ -302,7 +320,7 @@ public class NvHTTP {
catch (GfeHttpResponseException 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
@@ -313,13 +331,21 @@ public class NvHTTP {
}
else {
// No pinned cert, so use HTTP
return openHttpConnectionToString(baseUrlHttp , "serverinfo", true);
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
}
}
private static ComputerDetails.AddressTuple makeTuple(String address, int port) {
if (address == null) {
return null;
}
return new ComputerDetails.AddressTuple(address, port);
}
public ComputerDetails getComputerDetails() throws IOException, XmlPullParserException {
public ComputerDetails getComputerDetails(boolean likelyOnline) throws IOException, XmlPullParserException {
ComputerDetails details = new ComputerDetails();
String serverInfo = getServerInfo();
String serverInfo = getServerInfo(likelyOnline);
details.name = getXmlString(serverInfo, "hostname", false);
if (details.name == null || details.name.isEmpty()) {
@@ -329,11 +355,16 @@ 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);
@@ -376,25 +407,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();
@@ -415,27 +439,24 @@ public class NvHTTP {
}
}
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 {
if (verbose) {
LimeLog.info("Requesting URL: "+getCompleteUrl(baseUrl, path, query));
}
ResponseBody resp = openHttpConnection(baseUrl, path, query, enableReadTimeout);
ResponseBody resp = openHttpConnection(client, baseUrl, path, query);
String respString = resp.string();
resp.close();
if (verbose) {
if (verbose && !path.equals("serverinfo")) {
LimeLog.info(getCompleteUrl(baseUrl, path, query)+" -> "+respString);
}
return respString;
} catch (IOException e) {
if (verbose) {
if (verbose && !path.equals("serverinfo")) {
LimeLog.warning(getCompleteUrl(baseUrl, path, query)+" -> "+e.getMessage());
e.printStackTrace();
}
@@ -449,7 +470,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 {
@@ -528,6 +549,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) {
@@ -619,7 +666,7 @@ 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 {
@@ -628,31 +675,28 @@ public class NvHTTP {
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);
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);
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();
}
@@ -707,7 +751,7 @@ public class NvHTTP {
enableSops = false;
}
String xmlStr = openHttpConnectionToString(baseUrlHttps, "launch",
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "launch",
"appid=" + appId +
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
@@ -717,8 +761,7 @@ public class NvHTTP {
"&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);
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""));
if (!getXmlString(xmlStr, "gamesession", true).equals("0")) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
@@ -730,11 +773,10 @@ public class NvHTTP {
}
public boolean resumeApp(ConnectionContext context) throws IOException, XmlPullParserException {
String xmlStr = openHttpConnectionToString(baseUrlHttps, "resume",
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "resume",
"rikey="+bytesToHex(context.riKey.getEncoded()) +
"&rikeyid="+context.riKeyId +
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo(),
false);
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo());
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
@@ -746,14 +788,14 @@ 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, "");
@@ -1,8 +1,8 @@
package com.limelight.nvstream.http;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.engines.AESLightEngine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.xmlpull.v1.XmlPullParserException;
@@ -21,7 +21,6 @@ public class PairingManager {
private PrivateKey pk;
private X509Certificate cert;
private SecretKey aesKey;
private byte[] pemCertBytes;
private X509Certificate serverCert;
@@ -125,43 +124,35 @@ public class PairingManager {
throw new RuntimeException(e);
}
}
private static byte[] decryptAes(byte[] encryptedData, SecretKey secretKey) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
int blockRoundedSize = ((encryptedData.length + 15) / 16) * 16;
byte[] blockRoundedEncrypted = Arrays.copyOf(encryptedData, blockRoundedSize);
byte[] fullDecrypted = new byte[blockRoundedSize];
cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipher.doFinal(blockRoundedEncrypted, 0,
blockRoundedSize, fullDecrypted);
return fullDecrypted;
} catch (GeneralSecurityException e) {
e.printStackTrace();
throw new RuntimeException(e);
private static byte[] performBlockCipher(BlockCipher blockCipher, byte[] input) {
int blockSize = blockCipher.getBlockSize();
int blockRoundedSize = (input.length + (blockSize - 1)) & ~(blockSize - 1);
byte[] blockRoundedInputData = Arrays.copyOf(input, blockRoundedSize);
byte[] blockRoundedOutputData = new byte[blockRoundedSize];
for (int offset = 0; offset < blockRoundedSize; offset += blockSize) {
blockCipher.processBlock(blockRoundedInputData, offset, blockRoundedOutputData, offset);
}
return blockRoundedOutputData;
}
private static byte[] encryptAes(byte[] data, SecretKey secretKey) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
int blockRoundedSize = ((data.length + 15) / 16) * 16;
byte[] blockRoundedData = Arrays.copyOf(data, blockRoundedSize);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(blockRoundedData);
} catch (GeneralSecurityException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
private static byte[] decryptAes(byte[] encryptedData, byte[] aesKey) {
BlockCipher aesEngine = new AESLightEngine();
aesEngine.init(false, new KeyParameter(aesKey));
return performBlockCipher(aesEngine, encryptedData);
}
private static SecretKey generateAesKey(PairingHashAlgorithm hashAlgo, byte[] keyData) {
byte[] aesTruncated = Arrays.copyOf(hashAlgo.hashData(keyData), 16);
return new SecretKeySpec(aesTruncated, "AES");
private static byte[] encryptAes(byte[] plaintextData, byte[] aesKey) {
BlockCipher aesEngine = new AESLightEngine();
aesEngine.init(true, new KeyParameter(aesKey));
return performBlockCipher(aesEngine, plaintextData);
}
private static byte[] generateAesKey(PairingHashAlgorithm hashAlgo, byte[] keyData) {
return Arrays.copyOf(hashAlgo.hashData(keyData), 16);
}
private static byte[] concatBytes(byte[] a, byte[] b) {
@@ -200,8 +191,7 @@ public class PairingManager {
byte[] salt = generateRandomBytes(16);
// Combine the salt and pin, then create an AES key from them
byte[] saltAndPin = saltPin(salt, pin);
aesKey = generateAesKey(hashAlgo, saltAndPin);
byte[] aesKey = generateAesKey(hashAlgo, saltPin(salt, pin));
// Send the salt and get the server cert. This doesn't have a read timeout
// because the user must enter the PIN before the server responds
@@ -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;
}
@@ -27,6 +27,16 @@ public class MoonBridge {
public static final int BUFFER_TYPE_PPS = 2;
public static final int BUFFER_TYPE_VPS = 3;
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;
@@ -42,6 +52,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;
@@ -153,12 +164,12 @@ public class MoonBridge {
}
}
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength,
int decodeUnitType, int frameNumber,
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
int frameNumber, int frameType,
long receiveTimeMs, long enqueueTimeMs) {
if (videoRenderer != null) {
return videoRenderer.submitDecodeUnit(decodeUnitData, decodeUnitLength,
decodeUnitType, frameNumber, receiveTimeMs, enqueueTimeMs);
decodeUnitType, frameNumber, frameType, receiveTimeMs, enqueueTimeMs);
}
else {
return DR_OK;
@@ -268,7 +279,8 @@ public class MoonBridge {
int clientRefreshRateX100,
int encryptionFlags,
byte[] riAesKey, byte[] riAesIv,
int videoCapabilities);
int videoCapabilities,
int colorSpace, int colorRange);
public static native void stopConnection();
@@ -278,6 +290,8 @@ public class MoonBridge {
public static native void sendMousePosition(short x, short y, short referenceWidth, short referenceHeight);
public static native void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight);
public static native void sendMouseButton(byte buttonEvent, byte mouseButton);
public static native void sendMultiControllerInput(short controllerNumber,
@@ -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;
}
@@ -260,7 +260,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
// 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);
MdnsComputer computer = new MdnsComputer(info.getName(), v4Addr, v6GlobalAddr, info.getPort());
if (computers.put(computer.getLocalAddress(), computer) == null) {
// This was a new entry
listener.notifyComputerAdded(computer);
@@ -273,7 +273,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
Inet6Address v6LocalAddr = getLocalAddress(v6Addrs);
if (v6LocalAddr != null || v6GlobalAddr != null) {
MdnsComputer computer = new MdnsComputer(info.getName(), v6LocalAddr, v6GlobalAddr);
MdnsComputer computer = new MdnsComputer(info.getName(), v6LocalAddr, v6GlobalAddr, info.getPort());
if (computers.put(v6LocalAddr != null ?
computer.getLocalAddress() : computer.getIpv6Address(), computer) == null) {
// This was a new entry
@@ -10,39 +10,75 @@ 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);
sentWolPacket = true;
}
sendPacketsForAddress(InetAddress.getByName("255.255.255.255"), address.port, sock, payload);
for (InetAddress resolvedAddress : InetAddress.getAllByName(address.address)) {
sendPacketsForAddress(resolvedAddress, address.port, sock, payload);
}
} catch (IOException e) {
// We may have addresses that don't resolve on this subnet,
@@ -52,8 +88,6 @@ public class WakeOnLanSender {
lastException = e;
}
}
} finally {
sock.close();
}
// Propagate the DNS resolution exception if we didn't
@@ -65,18 +99,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) {
@@ -0,0 +1,51 @@
package com.limelight.preferences;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.preference.ListPreference;
import android.provider.Settings;
import android.util.AttributeSet;
public class LanguagePreference extends ListPreference {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public LanguagePreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LanguagePreference(Context context) {
super(context);
}
@Override
protected void onClick() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
try {
// Launch the Android native app locale settings page
Intent intent = new Intent(Settings.ACTION_APP_LOCALE_SETTINGS);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setData(Uri.parse("package:" + getContext().getPackageName()));
getContext().startActivity(intent, null);
return;
} catch (ActivityNotFoundException e) {
// App locale settings should be present on all Android 13 devices,
// but if not, we'll launch the old language chooser.
}
}
// If we don't have native app locale settings, launch the normal dialog
super.onClick();
}
}
@@ -5,6 +5,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.preference.PreferenceManager;
import android.view.Display;
import com.limelight.nvstream.jni.MoonBridge;
@@ -44,6 +45,10 @@ public class PreferenceConfiguration {
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast";
private static final String FRAME_PACING_PREF_STRING = "frame_pacing";
private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode";
private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx";
private static final String REDUCE_REFRESH_RATE_PREF_STRING = "checkbox_reduce_refresh_rate";
private static final String FULL_RANGE_PREF_STRING = "checkbox_full_range";
static final String DEFAULT_RESOLUTION = "1280x720";
static final String DEFAULT_FPS = "60";
@@ -51,7 +56,7 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_SOPS = true;
private static final boolean DEFAULT_DISABLE_TOASTS = false;
private static final boolean DEFAULT_HOST_AUDIO = false;
private static final int DEFAULT_DEADZONE = 15;
private static final int DEFAULT_DEADZONE = 7;
private static final int DEFAULT_OPACITY = 90;
public static final String DEFAULT_LANGUAGE = "default";
private static final boolean DEFAULT_MULTI_CONTROLLER = true;
@@ -73,6 +78,10 @@ public class PreferenceConfiguration {
private static final String DEFAULT_AUDIO_CONFIG = "2"; // Stereo
private static final boolean DEFAULT_LATENCY_TOAST = false;
private static final String DEFAULT_FRAME_PACING = "latency";
private static final boolean DEFAULT_ABSOLUTE_MOUSE_MODE = false;
private static final boolean DEFAULT_ENABLE_AUDIO_FX = false;
private static final boolean DEFAULT_REDUCE_REFRESH_RATE = false;
private static final boolean DEFAULT_FULL_RANGE = false;
public static final int FORCE_H265_ON = -1;
public static final int AUTOSELECT_H265 = 0;
@@ -114,6 +123,10 @@ public class PreferenceConfiguration {
public boolean touchscreenTrackpad;
public MoonBridge.AudioConfiguration audioConfiguration;
public int framePacing;
public boolean absoluteMouseMode;
public boolean enableAudioFx;
public boolean reduceRefreshRate;
public boolean fullRange;
public static boolean isNativeResolution(int width, int height) {
// It's not a native resolution if it matches an existing resolution option
@@ -139,6 +152,31 @@ public class PreferenceConfiguration {
return true;
}
// If we have a screen that has semi-square dimensions, we may want to change our behavior
// to allow any orientation and vertical+horizontal resolutions.
public static boolean isSquarishScreen(int width, int height) {
float longDim = Math.max(width, height);
float shortDim = Math.min(width, height);
// We just put the arbitrary cutoff for a square-ish screen at 1.3
return longDim / shortDim < 1.3f;
}
public static boolean isSquarishScreen(Display display) {
int width, height;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
width = display.getMode().getPhysicalWidth();
height = display.getMode().getPhysicalHeight();
}
else {
width = display.getWidth();
height = display.getHeight();
}
return isSquarishScreen(width, height);
}
private static String convertFromLegacyResolutionString(String resString) {
if (resString.equalsIgnoreCase("360p")) {
return RES_360P;
@@ -313,9 +351,23 @@ public class PreferenceConfiguration {
.remove(VIDEO_FORMAT_PREF_STRING)
.remove(ENABLE_HDR_PREF_STRING)
.remove(UNLOCK_FPS_STRING)
.remove(FULL_RANGE_PREF_STRING)
.apply();
}
public static void completeLanguagePreferenceMigration(Context context) {
// Put our language option back to default which tells us that we've already migrated it
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString(LANGUAGE_PREF_STRING, DEFAULT_LANGUAGE).apply();
}
public static boolean isShieldAtvFirmwareWithBrokenHdr() {
// This particular Shield TV firmware crashes when using HDR
// https://www.nvidia.com/en-us/geforce/forums/notifications/comment/155192/
return Build.MANUFACTURER.equalsIgnoreCase("NVIDIA") &&
Build.FINGERPRINT.contains("PPR1.180610.011/4079208_2235.1395");
}
public static PreferenceConfiguration readPreferences(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
PreferenceConfiguration config = new PreferenceConfiguration();
@@ -442,7 +494,7 @@ public class PreferenceConfiguration {
config.usbDriver = prefs.getBoolean(USB_DRIVER_PREF_SRING, DEFAULT_USB_DRIVER);
config.onscreenController = prefs.getBoolean(ONSCREEN_CONTROLLER_PREF_STRING, ONSCREEN_CONTROLLER_DEFAULT);
config.onlyL3R3 = prefs.getBoolean(ONLY_L3_R3_PREF_STRING, ONLY_L3_R3_DEFAULT);
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR);
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
config.bindAllUsb = prefs.getBoolean(BIND_ALL_USB_STRING, DEFAULT_BIND_ALL_USB);
@@ -454,6 +506,10 @@ public class PreferenceConfiguration {
config.flipFaceButtons = prefs.getBoolean(FLIP_FACE_BUTTONS_PREF_STRING, DEFAULT_FLIP_FACE_BUTTONS);
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
config.reduceRefreshRate = prefs.getBoolean(REDUCE_REFRESH_RATE_PREF_STRING, DEFAULT_REDUCE_REFRESH_RATE);
config.fullRange = prefs.getBoolean(FULL_RANGE_PREF_STRING, DEFAULT_FULL_RANGE);
return config;
}
@@ -4,12 +4,14 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.MediaCodecInfo;
import android.os.Build;
import android.os.Bundle;
import android.app.Activity;
import android.os.Handler;
import android.os.Vibrator;
import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceCategory;
@@ -37,11 +39,16 @@ import java.util.Arrays;
public class StreamSettings extends Activity {
private PreferenceConfiguration previousPrefs;
private int previousDisplayPixelCount;
// HACK for Android 9
static DisplayCutout displayCutoutP;
void reloadSettings() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Display.Mode mode = getWindowManager().getDefaultDisplay().getMode();
previousDisplayPixelCount = mode.getPhysicalWidth() * mode.getPhysicalHeight();
}
getFragmentManager().beginTransaction().replace(
R.id.stream_settings, new SettingsFragment()
).commitAllowingStateLoss();
@@ -79,16 +86,38 @@ public class StreamSettings extends Activity {
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Display.Mode mode = getWindowManager().getDefaultDisplay().getMode();
// If the display's physical pixel count has changed, we consider that it's a new display
// and we should reload our settings (which include display-dependent values).
//
// NB: We aren't using displayId here because that stays the same (DEFAULT_DISPLAY) when
// switching between screens on a foldable device.
if (mode.getPhysicalWidth() * mode.getPhysicalHeight() != previousDisplayPixelCount) {
reloadSettings();
}
}
}
@Override
// NOTE: This will NOT be called on Android 13+ with android:enableOnBackInvokedCallback="true"
public void onBackPressed() {
finish();
// Check for changes that require a UI reload to take effect
PreferenceConfiguration newPrefs = PreferenceConfiguration.readPreferences(this);
if (!newPrefs.language.equals(previousPrefs.language)) {
// Restart the PC view to apply UI changes
Intent intent = new Intent(this, PcView.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent, null);
// Language changes are handled via configuration changes in Android 13+,
// so manual activity relaunching is no longer required.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
PreferenceConfiguration newPrefs = PreferenceConfiguration.readPreferences(this);
if (!newPrefs.language.equals(previousPrefs.language)) {
// Restart the PC view to apply UI changes
Intent intent = new Intent(this, PcView.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent, null);
}
}
}
@@ -101,7 +130,7 @@ public class StreamSettings extends Activity {
pref.setValue(value);
}
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved, boolean portrait) {
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
String newName;
@@ -113,6 +142,15 @@ public class StreamSettings extends Activity {
newName = getResources().getString(R.string.resolution_prefix_native);
}
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
if (portrait) {
newName += " " + getResources().getString(R.string.resolution_prefix_native_portrait);
}
else {
newName += " " + getResources().getString(R.string.resolution_prefix_native_landscape);
}
}
newName += " ("+nativeWidth+"x"+nativeHeight+")";
String newValue = nativeWidth+"x"+nativeHeight;
@@ -142,6 +180,13 @@ public class StreamSettings extends Activity {
}
}
private void addNativeResolutionEntries(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
addNativeResolutionEntry(nativeHeight, nativeWidth, insetsRemoved, true);
}
addNativeResolutionEntry(nativeWidth, nativeHeight, insetsRemoved, false);
}
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
int matchingCount = 0;
@@ -222,6 +267,15 @@ public class StreamSettings extends Activity {
}
}
// Hide remote desktop mouse mode on pre-Oreo (which doesn't have pointer capture)
// and NVIDIA SHIELD devices (which support raw mouse input in pointer capture mode)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
getActivity().getPackageManager().hasSystemFeature("com.nvidia.feature.shield")) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_input_settings");
category.removePreference(findPreference("checkbox_absolute_mouse_mode"));
}
// 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 ||
@@ -286,7 +340,7 @@ public class StreamSettings extends Activity {
int width = Math.max(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
int height = Math.min(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
addNativeResolutionEntry(width, height, false);
addNativeResolutionEntries(width, height, false);
hasInsets = true;
}
}
@@ -311,7 +365,7 @@ public class StreamSettings extends Activity {
// unless they report greater than 4K resolutions.
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION) ||
(width > 3840 || height > 2160)) {
addNativeResolutionEntry(width, height, hasInsets);
addNativeResolutionEntries(width, height, hasInsets);
}
if ((width >= 3840 || height >= 2160) && maxSupportedResW < 3840) {
@@ -421,7 +475,7 @@ public class StreamSettings extends Activity {
getActivity().getWindowManager().getDefaultDisplay().getRealMetrics(metrics);
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
addNativeResolutionEntry(width, height, false);
addNativeResolutionEntries(width, height, false);
}
else {
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
@@ -432,7 +486,7 @@ public class StreamSettings extends Activity {
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
int width = (Integer) getRawWidthFunc.invoke(display);
int height = (Integer) getRawHeightFunc.invoke(display);
addNativeResolutionEntry(Math.max(width, height), Math.min(width, height), false);
addNativeResolutionEntries(Math.max(width, height), Math.min(width, height), false);
} catch (Exception e) {
e.printStackTrace();
}
@@ -536,6 +590,15 @@ public class StreamSettings extends Activity {
(PreferenceCategory) findPreference("category_advanced_settings");
category.removePreference(findPreference("checkbox_enable_hdr"));
}
else if (PreferenceConfiguration.isShieldAtvFirmwareWithBrokenHdr()) {
LimeLog.info("Disabling HDR toggle on old broken SHIELD TV firmware");
PreferenceCategory category =
(PreferenceCategory) findPreference("category_advanced_settings");
CheckBoxPreference hdrPref = (CheckBoxPreference) category.findPreference("checkbox_enable_hdr");
hdrPref.setEnabled(false);
hdrPref.setChecked(false);
hdrPref.setSummary("Update the firmware on your NVIDIA SHIELD Android TV to enable HDR");
}
}
// Add a listener to the FPS and resolution preference
@@ -1,5 +1,5 @@
package com.limelight.ui;
public interface GameGestures {
void showKeyboard();
void toggleKeyboard();
}
@@ -27,7 +27,10 @@ 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) {
public static ComputerDetails.AddressTuple getCurrentAddressFromComputer(ComputerDetails computer) throws IOException {
if (computer.activeAddress == null) {
throw new IOException("No active address for "+computer.name);
}
return computer.activeAddress;
}
@@ -53,7 +56,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, getCurrentAddressFromComputer(computer));
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());
@@ -72,8 +77,7 @@ public class ServerHelper {
public static void doStart(Activity parent, NvApp app, ComputerDetails computer,
ComputerManagerService.ComputerManagerBinder managerBinder) {
if (computer.state == ComputerDetails.State.OFFLINE ||
ServerHelper.getCurrentAddressFromComputer(computer) == null) {
if (computer.state == ComputerDetails.State.OFFLINE || computer.activeAddress == null) {
Toast.makeText(parent, parent.getResources().getString(R.string.pair_pc_offline), Toast.LENGTH_SHORT).show();
return;
}
@@ -124,7 +128,7 @@ 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();
@@ -2,6 +2,9 @@ package com.limelight.utils;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.GameManager;
import android.app.GameState;
import android.app.LocaleManager;
import android.app.UiModeManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -9,10 +12,12 @@ import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Insets;
import android.os.Build;
import android.os.LocaleList;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import com.limelight.Game;
import com.limelight.R;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.preferences.PreferenceConfiguration;
@@ -24,25 +29,66 @@ 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) {
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));
}
else {
gameManager.setGameState(new GameState(loading, GameState.MODE_NONE));
}
}
}
public static void notifyStreamConnecting(Context context) {
setGameModeStatus(context, true, true, true);
}
public static void notifyStreamConnected(Context context) {
setGameModeStatus(context, true, false, false);
}
public static void notifyStreamEnteringPiP(Context context) {
setGameModeStatus(context, true, false, true);
}
public static void notifyStreamExitingPiP(Context context) {
setGameModeStatus(context, true, false, false);
}
public static void notifyStreamEnded(Context context) {
setGameModeStatus(context, false, false, false);
}
public static void setLocale(Activity activity)
{
String locale = PreferenceConfiguration.readPreferences(activity).language;
if (!locale.equals(PreferenceConfiguration.DEFAULT_LANGUAGE)) {
Configuration config = new Configuration(activity.getResources().getConfiguration());
// Some locales include both language and country which must be separated
// before calling the Locale constructor.
if (locale.contains("-"))
{
config.locale = new Locale(locale.substring(0, locale.indexOf('-')),
locale.substring(locale.indexOf('-') + 1));
}
else
{
config.locale = new Locale(locale);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// On Android 13, migrate this non-default language setting into the OS native API
LocaleManager localeManager = activity.getSystemService(LocaleManager.class);
localeManager.setApplicationLocales(LocaleList.forLanguageTags(locale));
PreferenceConfiguration.completeLanguagePreferenceMigration(activity);
}
else {
Configuration config = new Configuration(activity.getResources().getConfiguration());
activity.getResources().updateConfiguration(config, activity.getResources().getDisplayMetrics());
// Some locales include both language and country which must be separated
// before calling the Locale constructor.
if (locale.contains("-"))
{
config.locale = new Locale(locale.substring(0, locale.indexOf('-')),
locale.substring(locale.indexOf('-') + 1));
}
else
{
config.locale = new Locale(locale);
}
activity.getResources().updateConfiguration(config, activity.getResources().getDisplayMetrics());
}
}
}
@@ -68,6 +114,9 @@ public class UiHelper {
View rootView = activity.findViewById(android.R.id.content);
UiModeManager modeMgr = (UiModeManager) activity.getSystemService(Context.UI_MODE_SERVICE);
// Set GameState.MODE_NONE initially for all activities
setGameModeStatus(activity, false, false, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// Allow this non-streaming activity to layout under notches.
//
@@ -1,4 +1,4 @@
PATH=$ANDROID_NDK_ROOT/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
OUTPUT_DIR=~/openssl
BASE_ARGS="no-shared no-ssl3 no-stdio no-engine no-hw"
+8 -5
View File
@@ -80,7 +80,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", "([BIIIJJ)I");
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIIJJ)I");
BridgeArInitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArInit", "(III)I");
BridgeArStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStart", "()V");
BridgeArStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStop", "()V");
@@ -159,8 +159,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, currentEntry->length, currentEntry->bufferType,
decodeUnit->frameNumber, (jlong)decodeUnit->receiveTimeMs,
(jlong)decodeUnit->enqueueTimeMs);
decodeUnit->frameNumber, decodeUnit->frameType,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
@@ -180,7 +180,7 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, offset, BUFFER_TYPE_PICDATA,
decodeUnit->frameNumber,
decodeUnit->frameNumber, decodeUnit->frameType,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
@@ -386,7 +386,8 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
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),
@@ -406,6 +407,8 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
.hevcBitratePercentageMultiplier = hevcBitratePercentageMultiplier,
.clientRefreshRateX100 = clientRefreshRateX100,
.encryptionFlags = encryptionFlags,
.colorSpace = colorSpace,
.colorRange = colorRange
};
jbyte* riAesKeyBuf = (*env)->GetByteArrayElements(env, riAesKey, NULL);
@@ -0,0 +1,592 @@
/*
* WARNING: do not edit!
* Generated by Makefile from include/openssl/cmp.h.in
*
* Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright Nokia 2007-2019
* Copyright Siemens AG 2015-2019
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_CMP_H
# define OPENSSL_CMP_H
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_CMP
# include <openssl/crmf.h>
# include <openssl/cmperr.h>
# include <openssl/cmp_util.h>
# include <openssl/http.h>
/* explicit #includes not strictly needed since implied by the above: */
# include <openssl/types.h>
# include <openssl/safestack.h>
# include <openssl/x509.h>
# include <openssl/x509v3.h>
# ifdef __cplusplus
extern "C" {
# endif
# define OSSL_CMP_PVNO 2
/*-
* PKIFailureInfo ::= BIT STRING {
* -- since we can fail in more than one way!
* -- More codes may be added in the future if/when required.
* badAlg (0),
* -- unrecognized or unsupported Algorithm Identifier
* badMessageCheck (1),
* -- integrity check failed (e.g., signature did not verify)
* badRequest (2),
* -- transaction not permitted or supported
* badTime (3),
* -- messageTime was not sufficiently close to the system time,
* -- as defined by local policy
* badCertId (4),
* -- no certificate could be found matching the provided criteria
* badDataFormat (5),
* -- the data submitted has the wrong format
* wrongAuthority (6),
* -- the authority indicated in the request is different from the
* -- one creating the response token
* incorrectData (7),
* -- the requester's data is incorrect (for notary services)
* missingTimeStamp (8),
* -- when the timestamp is missing but should be there
* -- (by policy)
* badPOP (9),
* -- the proof-of-possession failed
* certRevoked (10),
* -- the certificate has already been revoked
* certConfirmed (11),
* -- the certificate has already been confirmed
* wrongIntegrity (12),
* -- invalid integrity, password based instead of signature or
* -- vice versa
* badRecipientNonce (13),
* -- invalid recipient nonce, either missing or wrong value
* timeNotAvailable (14),
* -- the TSA's time source is not available
* unacceptedPolicy (15),
* -- the requested TSA policy is not supported by the TSA.
* unacceptedExtension (16),
* -- the requested extension is not supported by the TSA.
* addInfoNotAvailable (17),
* -- the additional information requested could not be
* -- understood or is not available
* badSenderNonce (18),
* -- invalid sender nonce, either missing or wrong size
* badCertTemplate (19),
* -- invalid cert. template or missing mandatory information
* signerNotTrusted (20),
* -- signer of the message unknown or not trusted
* transactionIdInUse (21),
* -- the transaction identifier is already in use
* unsupportedVersion (22),
* -- the version of the message is not supported
* notAuthorized (23),
* -- the sender was not authorized to make the preceding
* -- request or perform the preceding action
* systemUnavail (24),
* -- the request cannot be handled due to system unavailability
* systemFailure (25),
* -- the request cannot be handled due to system failure
* duplicateCertReq (26)
* -- certificate cannot be issued because a duplicate
* -- certificate already exists
* }
*/
# define OSSL_CMP_PKIFAILUREINFO_badAlg 0
# define OSSL_CMP_PKIFAILUREINFO_badMessageCheck 1
# define OSSL_CMP_PKIFAILUREINFO_badRequest 2
# define OSSL_CMP_PKIFAILUREINFO_badTime 3
# define OSSL_CMP_PKIFAILUREINFO_badCertId 4
# define OSSL_CMP_PKIFAILUREINFO_badDataFormat 5
# define OSSL_CMP_PKIFAILUREINFO_wrongAuthority 6
# define OSSL_CMP_PKIFAILUREINFO_incorrectData 7
# define OSSL_CMP_PKIFAILUREINFO_missingTimeStamp 8
# define OSSL_CMP_PKIFAILUREINFO_badPOP 9
# define OSSL_CMP_PKIFAILUREINFO_certRevoked 10
# define OSSL_CMP_PKIFAILUREINFO_certConfirmed 11
# define OSSL_CMP_PKIFAILUREINFO_wrongIntegrity 12
# define OSSL_CMP_PKIFAILUREINFO_badRecipientNonce 13
# define OSSL_CMP_PKIFAILUREINFO_timeNotAvailable 14
# define OSSL_CMP_PKIFAILUREINFO_unacceptedPolicy 15
# define OSSL_CMP_PKIFAILUREINFO_unacceptedExtension 16
# define OSSL_CMP_PKIFAILUREINFO_addInfoNotAvailable 17
# define OSSL_CMP_PKIFAILUREINFO_badSenderNonce 18
# define OSSL_CMP_PKIFAILUREINFO_badCertTemplate 19
# define OSSL_CMP_PKIFAILUREINFO_signerNotTrusted 20
# define OSSL_CMP_PKIFAILUREINFO_transactionIdInUse 21
# define OSSL_CMP_PKIFAILUREINFO_unsupportedVersion 22
# define OSSL_CMP_PKIFAILUREINFO_notAuthorized 23
# define OSSL_CMP_PKIFAILUREINFO_systemUnavail 24
# define OSSL_CMP_PKIFAILUREINFO_systemFailure 25
# define OSSL_CMP_PKIFAILUREINFO_duplicateCertReq 26
# define OSSL_CMP_PKIFAILUREINFO_MAX 26
# define OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN \
((1 << (OSSL_CMP_PKIFAILUREINFO_MAX + 1)) - 1)
# if OSSL_CMP_PKIFAILUREINFO_MAX_BIT_PATTERN > INT_MAX
# error CMP_PKIFAILUREINFO_MAX bit pattern does not fit in type int
# endif
typedef ASN1_BIT_STRING OSSL_CMP_PKIFAILUREINFO;
# define OSSL_CMP_CTX_FAILINFO_badAlg (1 << 0)
# define OSSL_CMP_CTX_FAILINFO_badMessageCheck (1 << 1)
# define OSSL_CMP_CTX_FAILINFO_badRequest (1 << 2)
# define OSSL_CMP_CTX_FAILINFO_badTime (1 << 3)
# define OSSL_CMP_CTX_FAILINFO_badCertId (1 << 4)
# define OSSL_CMP_CTX_FAILINFO_badDataFormat (1 << 5)
# define OSSL_CMP_CTX_FAILINFO_wrongAuthority (1 << 6)
# define OSSL_CMP_CTX_FAILINFO_incorrectData (1 << 7)
# define OSSL_CMP_CTX_FAILINFO_missingTimeStamp (1 << 8)
# define OSSL_CMP_CTX_FAILINFO_badPOP (1 << 9)
# define OSSL_CMP_CTX_FAILINFO_certRevoked (1 << 10)
# define OSSL_CMP_CTX_FAILINFO_certConfirmed (1 << 11)
# define OSSL_CMP_CTX_FAILINFO_wrongIntegrity (1 << 12)
# define OSSL_CMP_CTX_FAILINFO_badRecipientNonce (1 << 13)
# define OSSL_CMP_CTX_FAILINFO_timeNotAvailable (1 << 14)
# define OSSL_CMP_CTX_FAILINFO_unacceptedPolicy (1 << 15)
# define OSSL_CMP_CTX_FAILINFO_unacceptedExtension (1 << 16)
# define OSSL_CMP_CTX_FAILINFO_addInfoNotAvailable (1 << 17)
# define OSSL_CMP_CTX_FAILINFO_badSenderNonce (1 << 18)
# define OSSL_CMP_CTX_FAILINFO_badCertTemplate (1 << 19)
# define OSSL_CMP_CTX_FAILINFO_signerNotTrusted (1 << 20)
# define OSSL_CMP_CTX_FAILINFO_transactionIdInUse (1 << 21)
# define OSSL_CMP_CTX_FAILINFO_unsupportedVersion (1 << 22)
# define OSSL_CMP_CTX_FAILINFO_notAuthorized (1 << 23)
# define OSSL_CMP_CTX_FAILINFO_systemUnavail (1 << 24)
# define OSSL_CMP_CTX_FAILINFO_systemFailure (1 << 25)
# define OSSL_CMP_CTX_FAILINFO_duplicateCertReq (1 << 26)
/*-
* PKIStatus ::= INTEGER {
* accepted (0),
* -- you got exactly what you asked for
* grantedWithMods (1),
* -- you got something like what you asked for; the
* -- requester is responsible for ascertaining the differences
* rejection (2),
* -- you don't get it, more information elsewhere in the message
* waiting (3),
* -- the request body part has not yet been processed; expect to
* -- hear more later (note: proper handling of this status
* -- response MAY use the polling req/rep PKIMessages specified
* -- in Section 5.3.22; alternatively, polling in the underlying
* -- transport layer MAY have some utility in this regard)
* revocationWarning (4),
* -- this message contains a warning that a revocation is
* -- imminent
* revocationNotification (5),
* -- notification that a revocation has occurred
* keyUpdateWarning (6)
* -- update already done for the oldCertId specified in
* -- CertReqMsg
* }
*/
# define OSSL_CMP_PKISTATUS_accepted 0
# define OSSL_CMP_PKISTATUS_grantedWithMods 1
# define OSSL_CMP_PKISTATUS_rejection 2
# define OSSL_CMP_PKISTATUS_waiting 3
# define OSSL_CMP_PKISTATUS_revocationWarning 4
# define OSSL_CMP_PKISTATUS_revocationNotification 5
# define OSSL_CMP_PKISTATUS_keyUpdateWarning 6
typedef ASN1_INTEGER OSSL_CMP_PKISTATUS;
DECLARE_ASN1_ITEM(OSSL_CMP_PKISTATUS)
# define OSSL_CMP_CERTORENCCERT_CERTIFICATE 0
# define OSSL_CMP_CERTORENCCERT_ENCRYPTEDCERT 1
/* data type declarations */
typedef struct ossl_cmp_ctx_st OSSL_CMP_CTX;
typedef struct ossl_cmp_pkiheader_st OSSL_CMP_PKIHEADER;
DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKIHEADER)
typedef struct ossl_cmp_msg_st OSSL_CMP_MSG;
DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG)
DECLARE_ASN1_ENCODE_FUNCTIONS(OSSL_CMP_MSG, OSSL_CMP_MSG, OSSL_CMP_MSG)
typedef struct ossl_cmp_certstatus_st OSSL_CMP_CERTSTATUS;
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTSTATUS, OSSL_CMP_CERTSTATUS, OSSL_CMP_CERTSTATUS)
#define sk_OSSL_CMP_CERTSTATUS_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk))
#define sk_OSSL_CMP_CERTSTATUS_value(sk, idx) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk), (idx)))
#define sk_OSSL_CMP_CERTSTATUS_new(cmp) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp)))
#define sk_OSSL_CMP_CERTSTATUS_new_null() ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new_null())
#define sk_OSSL_CMP_CERTSTATUS_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp), (n)))
#define sk_OSSL_CMP_CERTSTATUS_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (n))
#define sk_OSSL_CMP_CERTSTATUS_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
#define sk_OSSL_CMP_CERTSTATUS_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
#define sk_OSSL_CMP_CERTSTATUS_delete(sk, i) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (i)))
#define sk_OSSL_CMP_CERTSTATUS_delete_ptr(sk, ptr) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr)))
#define sk_OSSL_CMP_CERTSTATUS_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
#define sk_OSSL_CMP_CERTSTATUS_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
#define sk_OSSL_CMP_CERTSTATUS_pop(sk) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk)))
#define sk_OSSL_CMP_CERTSTATUS_shift(sk) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk)))
#define sk_OSSL_CMP_CERTSTATUS_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk),ossl_check_OSSL_CMP_CERTSTATUS_freefunc_type(freefunc))
#define sk_OSSL_CMP_CERTSTATUS_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr), (idx))
#define sk_OSSL_CMP_CERTSTATUS_set(sk, idx, ptr) ((OSSL_CMP_CERTSTATUS *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr)))
#define sk_OSSL_CMP_CERTSTATUS_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
#define sk_OSSL_CMP_CERTSTATUS_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr))
#define sk_OSSL_CMP_CERTSTATUS_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_type(ptr), pnum)
#define sk_OSSL_CMP_CERTSTATUS_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk))
#define sk_OSSL_CMP_CERTSTATUS_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk))
#define sk_OSSL_CMP_CERTSTATUS_dup(sk) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk)))
#define sk_OSSL_CMP_CERTSTATUS_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTSTATUS) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTSTATUS_freefunc_type(freefunc)))
#define sk_OSSL_CMP_CERTSTATUS_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTSTATUS_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTSTATUS_sk_type(sk), ossl_check_OSSL_CMP_CERTSTATUS_compfunc_type(cmp)))
typedef struct ossl_cmp_itav_st OSSL_CMP_ITAV;
DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV)
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_ITAV, OSSL_CMP_ITAV, OSSL_CMP_ITAV)
#define sk_OSSL_CMP_ITAV_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk))
#define sk_OSSL_CMP_ITAV_value(sk, idx) ((OSSL_CMP_ITAV *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk), (idx)))
#define sk_OSSL_CMP_ITAV_new(cmp) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp)))
#define sk_OSSL_CMP_ITAV_new_null() ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new_null())
#define sk_OSSL_CMP_ITAV_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp), (n)))
#define sk_OSSL_CMP_ITAV_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (n))
#define sk_OSSL_CMP_ITAV_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
#define sk_OSSL_CMP_ITAV_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
#define sk_OSSL_CMP_ITAV_delete(sk, i) ((OSSL_CMP_ITAV *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (i)))
#define sk_OSSL_CMP_ITAV_delete_ptr(sk, ptr) ((OSSL_CMP_ITAV *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr)))
#define sk_OSSL_CMP_ITAV_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
#define sk_OSSL_CMP_ITAV_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
#define sk_OSSL_CMP_ITAV_pop(sk) ((OSSL_CMP_ITAV *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_ITAV_sk_type(sk)))
#define sk_OSSL_CMP_ITAV_shift(sk) ((OSSL_CMP_ITAV *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_ITAV_sk_type(sk)))
#define sk_OSSL_CMP_ITAV_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_ITAV_sk_type(sk),ossl_check_OSSL_CMP_ITAV_freefunc_type(freefunc))
#define sk_OSSL_CMP_ITAV_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr), (idx))
#define sk_OSSL_CMP_ITAV_set(sk, idx, ptr) ((OSSL_CMP_ITAV *)OPENSSL_sk_set(ossl_check_OSSL_CMP_ITAV_sk_type(sk), (idx), ossl_check_OSSL_CMP_ITAV_type(ptr)))
#define sk_OSSL_CMP_ITAV_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
#define sk_OSSL_CMP_ITAV_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr))
#define sk_OSSL_CMP_ITAV_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_type(ptr), pnum)
#define sk_OSSL_CMP_ITAV_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_ITAV_sk_type(sk))
#define sk_OSSL_CMP_ITAV_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk))
#define sk_OSSL_CMP_ITAV_dup(sk) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk)))
#define sk_OSSL_CMP_ITAV_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_ITAV) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_ITAV_freefunc_type(freefunc)))
#define sk_OSSL_CMP_ITAV_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_ITAV_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_ITAV_sk_type(sk), ossl_check_OSSL_CMP_ITAV_compfunc_type(cmp)))
typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT;
typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI;
DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI)
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_PKISI, OSSL_CMP_PKISI, OSSL_CMP_PKISI)
#define sk_OSSL_CMP_PKISI_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk))
#define sk_OSSL_CMP_PKISI_value(sk, idx) ((OSSL_CMP_PKISI *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk), (idx)))
#define sk_OSSL_CMP_PKISI_new(cmp) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp)))
#define sk_OSSL_CMP_PKISI_new_null() ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new_null())
#define sk_OSSL_CMP_PKISI_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp), (n)))
#define sk_OSSL_CMP_PKISI_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (n))
#define sk_OSSL_CMP_PKISI_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
#define sk_OSSL_CMP_PKISI_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
#define sk_OSSL_CMP_PKISI_delete(sk, i) ((OSSL_CMP_PKISI *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (i)))
#define sk_OSSL_CMP_PKISI_delete_ptr(sk, ptr) ((OSSL_CMP_PKISI *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr)))
#define sk_OSSL_CMP_PKISI_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
#define sk_OSSL_CMP_PKISI_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
#define sk_OSSL_CMP_PKISI_pop(sk) ((OSSL_CMP_PKISI *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_PKISI_sk_type(sk)))
#define sk_OSSL_CMP_PKISI_shift(sk) ((OSSL_CMP_PKISI *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_PKISI_sk_type(sk)))
#define sk_OSSL_CMP_PKISI_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_PKISI_sk_type(sk),ossl_check_OSSL_CMP_PKISI_freefunc_type(freefunc))
#define sk_OSSL_CMP_PKISI_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr), (idx))
#define sk_OSSL_CMP_PKISI_set(sk, idx, ptr) ((OSSL_CMP_PKISI *)OPENSSL_sk_set(ossl_check_OSSL_CMP_PKISI_sk_type(sk), (idx), ossl_check_OSSL_CMP_PKISI_type(ptr)))
#define sk_OSSL_CMP_PKISI_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
#define sk_OSSL_CMP_PKISI_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr))
#define sk_OSSL_CMP_PKISI_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_type(ptr), pnum)
#define sk_OSSL_CMP_PKISI_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_PKISI_sk_type(sk))
#define sk_OSSL_CMP_PKISI_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk))
#define sk_OSSL_CMP_PKISI_dup(sk) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk)))
#define sk_OSSL_CMP_PKISI_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_PKISI) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_PKISI_freefunc_type(freefunc)))
#define sk_OSSL_CMP_PKISI_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_PKISI_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_PKISI_sk_type(sk), ossl_check_OSSL_CMP_PKISI_compfunc_type(cmp)))
typedef struct ossl_cmp_certrepmessage_st OSSL_CMP_CERTREPMESSAGE;
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTREPMESSAGE, OSSL_CMP_CERTREPMESSAGE, OSSL_CMP_CERTREPMESSAGE)
#define sk_OSSL_CMP_CERTREPMESSAGE_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
#define sk_OSSL_CMP_CERTREPMESSAGE_value(sk, idx) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (idx)))
#define sk_OSSL_CMP_CERTREPMESSAGE_new(cmp) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp)))
#define sk_OSSL_CMP_CERTREPMESSAGE_new_null() ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new_null())
#define sk_OSSL_CMP_CERTREPMESSAGE_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp), (n)))
#define sk_OSSL_CMP_CERTREPMESSAGE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (n))
#define sk_OSSL_CMP_CERTREPMESSAGE_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
#define sk_OSSL_CMP_CERTREPMESSAGE_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
#define sk_OSSL_CMP_CERTREPMESSAGE_delete(sk, i) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (i)))
#define sk_OSSL_CMP_CERTREPMESSAGE_delete_ptr(sk, ptr) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr)))
#define sk_OSSL_CMP_CERTREPMESSAGE_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
#define sk_OSSL_CMP_CERTREPMESSAGE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
#define sk_OSSL_CMP_CERTREPMESSAGE_pop(sk) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
#define sk_OSSL_CMP_CERTREPMESSAGE_shift(sk) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
#define sk_OSSL_CMP_CERTREPMESSAGE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk),ossl_check_OSSL_CMP_CERTREPMESSAGE_freefunc_type(freefunc))
#define sk_OSSL_CMP_CERTREPMESSAGE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr), (idx))
#define sk_OSSL_CMP_CERTREPMESSAGE_set(sk, idx, ptr) ((OSSL_CMP_CERTREPMESSAGE *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr)))
#define sk_OSSL_CMP_CERTREPMESSAGE_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
#define sk_OSSL_CMP_CERTREPMESSAGE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr))
#define sk_OSSL_CMP_CERTREPMESSAGE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_type(ptr), pnum)
#define sk_OSSL_CMP_CERTREPMESSAGE_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
#define sk_OSSL_CMP_CERTREPMESSAGE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk))
#define sk_OSSL_CMP_CERTREPMESSAGE_dup(sk) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk)))
#define sk_OSSL_CMP_CERTREPMESSAGE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTREPMESSAGE) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTREPMESSAGE_freefunc_type(freefunc)))
#define sk_OSSL_CMP_CERTREPMESSAGE_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTREPMESSAGE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTREPMESSAGE_sk_type(sk), ossl_check_OSSL_CMP_CERTREPMESSAGE_compfunc_type(cmp)))
typedef struct ossl_cmp_pollrep_st OSSL_CMP_POLLREP;
typedef STACK_OF(OSSL_CMP_POLLREP) OSSL_CMP_POLLREPCONTENT;
typedef struct ossl_cmp_certresponse_st OSSL_CMP_CERTRESPONSE;
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CMP_CERTRESPONSE, OSSL_CMP_CERTRESPONSE, OSSL_CMP_CERTRESPONSE)
#define sk_OSSL_CMP_CERTRESPONSE_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk))
#define sk_OSSL_CMP_CERTRESPONSE_value(sk, idx) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_value(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk), (idx)))
#define sk_OSSL_CMP_CERTRESPONSE_new(cmp) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new(ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp)))
#define sk_OSSL_CMP_CERTRESPONSE_new_null() ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new_null())
#define sk_OSSL_CMP_CERTRESPONSE_new_reserve(cmp, n) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp), (n)))
#define sk_OSSL_CMP_CERTRESPONSE_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (n))
#define sk_OSSL_CMP_CERTRESPONSE_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
#define sk_OSSL_CMP_CERTRESPONSE_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
#define sk_OSSL_CMP_CERTRESPONSE_delete(sk, i) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_delete(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (i)))
#define sk_OSSL_CMP_CERTRESPONSE_delete_ptr(sk, ptr) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr)))
#define sk_OSSL_CMP_CERTRESPONSE_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
#define sk_OSSL_CMP_CERTRESPONSE_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
#define sk_OSSL_CMP_CERTRESPONSE_pop(sk) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_pop(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
#define sk_OSSL_CMP_CERTRESPONSE_shift(sk) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_shift(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
#define sk_OSSL_CMP_CERTRESPONSE_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk),ossl_check_OSSL_CMP_CERTRESPONSE_freefunc_type(freefunc))
#define sk_OSSL_CMP_CERTRESPONSE_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr), (idx))
#define sk_OSSL_CMP_CERTRESPONSE_set(sk, idx, ptr) ((OSSL_CMP_CERTRESPONSE *)OPENSSL_sk_set(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), (idx), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr)))
#define sk_OSSL_CMP_CERTRESPONSE_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
#define sk_OSSL_CMP_CERTRESPONSE_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr))
#define sk_OSSL_CMP_CERTRESPONSE_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_type(ptr), pnum)
#define sk_OSSL_CMP_CERTRESPONSE_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk))
#define sk_OSSL_CMP_CERTRESPONSE_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk))
#define sk_OSSL_CMP_CERTRESPONSE_dup(sk) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk)))
#define sk_OSSL_CMP_CERTRESPONSE_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CMP_CERTRESPONSE) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_copyfunc_type(copyfunc), ossl_check_OSSL_CMP_CERTRESPONSE_freefunc_type(freefunc)))
#define sk_OSSL_CMP_CERTRESPONSE_set_cmp_func(sk, cmp) ((sk_OSSL_CMP_CERTRESPONSE_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CMP_CERTRESPONSE_sk_type(sk), ossl_check_OSSL_CMP_CERTRESPONSE_compfunc_type(cmp)))
typedef STACK_OF(ASN1_UTF8STRING) OSSL_CMP_PKIFREETEXT;
/*
* function DECLARATIONS
*/
/* from cmp_asn.c */
OSSL_CMP_ITAV *OSSL_CMP_ITAV_create(ASN1_OBJECT *type, ASN1_TYPE *value);
void OSSL_CMP_ITAV_set0(OSSL_CMP_ITAV *itav, ASN1_OBJECT *type,
ASN1_TYPE *value);
ASN1_OBJECT *OSSL_CMP_ITAV_get0_type(const OSSL_CMP_ITAV *itav);
ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav);
int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
OSSL_CMP_ITAV *itav);
void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav);
void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg);
/* from cmp_ctx.c */
OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx);
/* CMP general options: */
# define OSSL_CMP_OPT_LOG_VERBOSITY 0
/* CMP transfer options: */
# define OSSL_CMP_OPT_KEEP_ALIVE 10
# define OSSL_CMP_OPT_MSG_TIMEOUT 11
# define OSSL_CMP_OPT_TOTAL_TIMEOUT 12
/* CMP request options: */
# define OSSL_CMP_OPT_VALIDITY_DAYS 20
# define OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT 21
# define OSSL_CMP_OPT_SUBJECTALTNAME_CRITICAL 22
# define OSSL_CMP_OPT_POLICIES_CRITICAL 23
# define OSSL_CMP_OPT_POPO_METHOD 24
# define OSSL_CMP_OPT_IMPLICIT_CONFIRM 25
# define OSSL_CMP_OPT_DISABLE_CONFIRM 26
# define OSSL_CMP_OPT_REVOCATION_REASON 27
/* CMP protection options: */
# define OSSL_CMP_OPT_UNPROTECTED_SEND 30
# define OSSL_CMP_OPT_UNPROTECTED_ERRORS 31
# define OSSL_CMP_OPT_OWF_ALGNID 32
# define OSSL_CMP_OPT_MAC_ALGNID 33
# define OSSL_CMP_OPT_DIGEST_ALGNID 34
# define OSSL_CMP_OPT_IGNORE_KEYUSAGE 35
# define OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR 36
int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val);
int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt);
/* CMP-specific callback for logging and outputting the error queue: */
int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_log_cb_t cb);
# define OSSL_CMP_CTX_set_log_verbosity(ctx, level) \
OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_LOG_VERBOSITY, level)
void OSSL_CMP_CTX_print_errors(const OSSL_CMP_CTX *ctx);
/* message transfer: */
int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path);
int OSSL_CMP_CTX_set1_server(OSSL_CMP_CTX *ctx, const char *address);
int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port);
int OSSL_CMP_CTX_set1_proxy(OSSL_CMP_CTX *ctx, const char *name);
int OSSL_CMP_CTX_set1_no_proxy(OSSL_CMP_CTX *ctx, const char *names);
int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb);
int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx);
typedef OSSL_CMP_MSG *(*OSSL_CMP_transfer_cb_t) (OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *req);
int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_transfer_cb_t cb);
int OSSL_CMP_CTX_set_transfer_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_transfer_cb_arg(const OSSL_CMP_CTX *ctx);
/* server authentication: */
int OSSL_CMP_CTX_set1_srvCert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_set1_expected_sender(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_set0_trustedStore(OSSL_CMP_CTX *ctx, X509_STORE *store);
X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_untrusted(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs);
STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted(const OSSL_CMP_CTX *ctx);
/* client authentication: */
int OSSL_CMP_CTX_set1_cert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
STACK_OF(X509) *candidates);
int OSSL_CMP_CTX_set1_pkey(OSSL_CMP_CTX *ctx, EVP_PKEY *pkey);
int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx,
const unsigned char *ref, int len);
int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx, const unsigned char *sec,
const int len);
/* CMP message header and extra certificates: */
int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
STACK_OF(X509) *extraCertsOut);
/* certificate template: */
int OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_CTX *ctx, int priv, EVP_PKEY *pkey);
EVP_PKEY *OSSL_CMP_CTX_get0_newPkey(const OSSL_CMP_CTX *ctx, int priv);
int OSSL_CMP_CTX_set1_issuer(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_set1_subjectName(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx,
const GENERAL_NAME *name);
int OSSL_CMP_CTX_set0_reqExtensions(OSSL_CMP_CTX *ctx, X509_EXTENSIONS *exts);
int OSSL_CMP_CTX_reqExtensions_have_SAN(OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_push0_policy(OSSL_CMP_CTX *ctx, POLICYINFO *pinfo);
int OSSL_CMP_CTX_set1_oldCert(OSSL_CMP_CTX *ctx, X509 *cert);
int OSSL_CMP_CTX_set1_p10CSR(OSSL_CMP_CTX *ctx, const X509_REQ *csr);
/* misc body contents: */
int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
/* certificate confirmation: */
typedef int (*OSSL_CMP_certConf_cb_t) (OSSL_CMP_CTX *ctx, X509 *cert,
int fail_info, const char **txt);
int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
const char **text);
int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb);
int OSSL_CMP_CTX_set_certConf_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
void *OSSL_CMP_CTX_get_certConf_cb_arg(const OSSL_CMP_CTX *ctx);
/* result fetching: */
int OSSL_CMP_CTX_get_status(const OSSL_CMP_CTX *ctx);
OSSL_CMP_PKIFREETEXT *OSSL_CMP_CTX_get0_statusString(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx);
# define OSSL_CMP_PKISI_BUFLEN 1024
X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx);
STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx,
const ASN1_OCTET_STRING *id);
int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx,
const ASN1_OCTET_STRING *nonce);
/* from cmp_status.c */
char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf,
size_t bufsize);
char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo,
char *buf, size_t bufsize);
OSSL_CMP_PKISI *
OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text);
/* from cmp_hdr.c */
ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const
OSSL_CMP_PKIHEADER *hdr);
ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
/* from cmp_msg.c */
OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
int OSSL_CMP_MSG_get_bodytype(const OSSL_CMP_MSG *msg);
int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid);
OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file, OSSL_LIB_CTX *libctx,
const char *propq);
int OSSL_CMP_MSG_write(const char *file, const OSSL_CMP_MSG *msg);
OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
/* from cmp_vfy.c */
int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg);
int OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX *ctx,
X509_STORE *trusted_store, X509 *cert);
/* from cmp_http.c */
OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *req);
/* from cmp_server.c */
typedef struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_CTX;
OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req);
OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
const OSSL_CMP_MSG *req);
OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(OSSL_LIB_CTX *libctx, const char *propq);
void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx);
typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t)
(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req, int certReqId,
const OSSL_CRMF_MSG *crm, const X509_REQ *p10cr,
X509 **certOut, STACK_OF(X509) **chainOut, STACK_OF(X509) **caPubs);
typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req,
const X509_NAME *issuer,
const ASN1_INTEGER *serial);
typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req,
const STACK_OF(OSSL_CMP_ITAV) *in,
STACK_OF(OSSL_CMP_ITAV) **out);
typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req,
const OSSL_CMP_PKISI *statusInfo,
const ASN1_INTEGER *errorCode,
const OSSL_CMP_PKIFREETEXT *errDetails);
typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req,
int certReqId,
const ASN1_OCTET_STRING *certHash,
const OSSL_CMP_PKISI *si);
typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *req, int certReqId,
OSSL_CMP_MSG **certReq,
int64_t *check_after);
int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx,
OSSL_CMP_SRV_cert_request_cb_t process_cert_request,
OSSL_CMP_SRV_rr_cb_t process_rr,
OSSL_CMP_SRV_genm_cb_t process_genm,
OSSL_CMP_SRV_error_cb_t process_error,
OSSL_CMP_SRV_certConf_cb_t process_certConf,
OSSL_CMP_SRV_pollReq_cb_t process_pollReq);
OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx);
int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx,
int val);
int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val);
int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val);
int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
int val);
/* from cmp_client.c */
X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type,
const OSSL_CRMF_MSG *crm);
# define OSSL_CMP_IR 0
# define OSSL_CMP_CR 2
# define OSSL_CMP_P10CR 4
# define OSSL_CMP_KUR 7
# define OSSL_CMP_exec_IR_ses(ctx) \
OSSL_CMP_exec_certreq(ctx, OSSL_CMP_IR, NULL)
# define OSSL_CMP_exec_CR_ses(ctx) \
OSSL_CMP_exec_certreq(ctx, OSSL_CMP_CR, NULL)
# define OSSL_CMP_exec_P10CR_ses(ctx) \
OSSL_CMP_exec_certreq(ctx, OSSL_CMP_P10CR, NULL)
# define OSSL_CMP_exec_KUR_ses(ctx) \
OSSL_CMP_exec_certreq(ctx, OSSL_CMP_KUR, NULL)
int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type,
const OSSL_CRMF_MSG *crm, int *checkAfter);
int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx);
STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx);
# ifdef __cplusplus
}
# endif
# endif /* !defined(OPENSSL_NO_CMP) */
#endif /* !defined(OPENSSL_CMP_H) */
@@ -0,0 +1,154 @@
/*
* WARNING: do not edit!
* Generated by Makefile from include/openssl/configuration.h.in
*
* Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_CONFIGURATION_H
# define OPENSSL_CONFIGURATION_H
# pragma once
# ifdef __cplusplus
extern "C" {
# endif
# ifdef OPENSSL_ALGORITHM_DEFINES
# error OPENSSL_ALGORITHM_DEFINES no longer supported
# endif
/*
* OpenSSL was configured with the following options:
*/
# define OPENSSL_CONFIGURED_API 30000
# ifndef OPENSSL_RAND_SEED_OS
# define OPENSSL_RAND_SEED_OS
# endif
# ifndef OPENSSL_THREADS
# define OPENSSL_THREADS
# endif
# ifndef OPENSSL_NO_ACVP_TESTS
# define OPENSSL_NO_ACVP_TESTS
# endif
# ifndef OPENSSL_NO_AFALGENG
# define OPENSSL_NO_AFALGENG
# endif
# ifndef OPENSSL_NO_ASAN
# define OPENSSL_NO_ASAN
# endif
# ifndef OPENSSL_NO_CAPIENG
# define OPENSSL_NO_CAPIENG
# endif
# ifndef OPENSSL_NO_CRYPTO_MDEBUG
# define OPENSSL_NO_CRYPTO_MDEBUG
# endif
# ifndef OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
# define OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE
# endif
# ifndef OPENSSL_NO_DEPRECATED
# define OPENSSL_NO_DEPRECATED
# endif
# ifndef OPENSSL_NO_DEVCRYPTOENG
# define OPENSSL_NO_DEVCRYPTOENG
# endif
# ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
# define OPENSSL_NO_EC_NISTP_64_GCC_128
# endif
# ifndef OPENSSL_NO_EGD
# define OPENSSL_NO_EGD
# endif
# ifndef OPENSSL_NO_ENGINE
# define OPENSSL_NO_ENGINE
# endif
# ifndef OPENSSL_NO_EXTERNAL_TESTS
# define OPENSSL_NO_EXTERNAL_TESTS
# endif
# ifndef OPENSSL_NO_FIPS_SECURITYCHECKS
# define OPENSSL_NO_FIPS_SECURITYCHECKS
# endif
# ifndef OPENSSL_NO_FUZZ_AFL
# define OPENSSL_NO_FUZZ_AFL
# endif
# ifndef OPENSSL_NO_FUZZ_LIBFUZZER
# define OPENSSL_NO_FUZZ_LIBFUZZER
# endif
# ifndef OPENSSL_NO_KTLS
# define OPENSSL_NO_KTLS
# endif
# ifndef OPENSSL_NO_LOADERENG
# define OPENSSL_NO_LOADERENG
# endif
# ifndef OPENSSL_NO_MD2
# define OPENSSL_NO_MD2
# endif
# ifndef OPENSSL_NO_MSAN
# define OPENSSL_NO_MSAN
# endif
# ifndef OPENSSL_NO_PADLOCKENG
# define OPENSSL_NO_PADLOCKENG
# endif
# ifndef OPENSSL_NO_RC5
# define OPENSSL_NO_RC5
# endif
# ifndef OPENSSL_NO_SCTP
# define OPENSSL_NO_SCTP
# endif
# ifndef OPENSSL_NO_SRP
# define OPENSSL_NO_SRP
# endif
# ifndef OPENSSL_NO_SSL3
# define OPENSSL_NO_SSL3
# endif
# ifndef OPENSSL_NO_SSL3_METHOD
# define OPENSSL_NO_SSL3_METHOD
# endif
# ifndef OPENSSL_NO_TESTS
# define OPENSSL_NO_TESTS
# endif
# ifndef OPENSSL_NO_TRACE
# define OPENSSL_NO_TRACE
# endif
# ifndef OPENSSL_NO_UBSAN
# define OPENSSL_NO_UBSAN
# endif
# ifndef OPENSSL_NO_UNIT_TEST
# define OPENSSL_NO_UNIT_TEST
# endif
# ifndef OPENSSL_NO_UPLINK
# define OPENSSL_NO_UPLINK
# endif
# ifndef OPENSSL_NO_WEAK_SSL_CIPHERS
# define OPENSSL_NO_WEAK_SSL_CIPHERS
# endif
# ifndef OPENSSL_NO_DYNAMIC_ENGINE
# define OPENSSL_NO_DYNAMIC_ENGINE
# endif
/* Generate 80386 code? */
# undef I386_ONLY
/*
* The following are cipher-specific, but are part of the public API.
*/
# if !defined(OPENSSL_SYS_UEFI)
# undef BN_LLONG
/* Only one for the following should be defined */
# define SIXTY_FOUR_BIT_LONG
# undef SIXTY_FOUR_BIT
# undef THIRTY_TWO_BIT
# endif
# define RC4_INT unsigned int
# ifdef __cplusplus
}
# endif
#endif /* OPENSSL_CONFIGURATION_H */
@@ -0,0 +1,227 @@
/*-
* WARNING: do not edit!
* Generated by Makefile from include/openssl/crmf.h.in
*
* Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright Nokia 2007-2019
* Copyright Siemens AG 2015-2019
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*
* CRMF (RFC 4211) implementation by M. Peylo, M. Viljanen, and D. von Oheimb.
*/
#ifndef OPENSSL_CRMF_H
# define OPENSSL_CRMF_H
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_CRMF
# include <openssl/opensslv.h>
# include <openssl/safestack.h>
# include <openssl/crmferr.h>
# include <openssl/x509v3.h> /* for GENERAL_NAME etc. */
/* explicit #includes not strictly needed since implied by the above: */
# include <openssl/types.h>
# include <openssl/x509.h>
# ifdef __cplusplus
extern "C" {
# endif
# define OSSL_CRMF_POPOPRIVKEY_THISMESSAGE 0
# define OSSL_CRMF_POPOPRIVKEY_SUBSEQUENTMESSAGE 1
# define OSSL_CRMF_POPOPRIVKEY_DHMAC 2
# define OSSL_CRMF_POPOPRIVKEY_AGREEMAC 3
# define OSSL_CRMF_POPOPRIVKEY_ENCRYPTEDKEY 4
# define OSSL_CRMF_SUBSEQUENTMESSAGE_ENCRCERT 0
# define OSSL_CRMF_SUBSEQUENTMESSAGE_CHALLENGERESP 1
typedef struct ossl_crmf_encryptedvalue_st OSSL_CRMF_ENCRYPTEDVALUE;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDVALUE)
typedef struct ossl_crmf_msg_st OSSL_CRMF_MSG;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_MSG)
DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_MSG)
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CRMF_MSG, OSSL_CRMF_MSG, OSSL_CRMF_MSG)
#define sk_OSSL_CRMF_MSG_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CRMF_MSG_sk_type(sk))
#define sk_OSSL_CRMF_MSG_value(sk, idx) ((OSSL_CRMF_MSG *)OPENSSL_sk_value(ossl_check_const_OSSL_CRMF_MSG_sk_type(sk), (idx)))
#define sk_OSSL_CRMF_MSG_new(cmp) ((STACK_OF(OSSL_CRMF_MSG) *)OPENSSL_sk_new(ossl_check_OSSL_CRMF_MSG_compfunc_type(cmp)))
#define sk_OSSL_CRMF_MSG_new_null() ((STACK_OF(OSSL_CRMF_MSG) *)OPENSSL_sk_new_null())
#define sk_OSSL_CRMF_MSG_new_reserve(cmp, n) ((STACK_OF(OSSL_CRMF_MSG) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CRMF_MSG_compfunc_type(cmp), (n)))
#define sk_OSSL_CRMF_MSG_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CRMF_MSG_sk_type(sk), (n))
#define sk_OSSL_CRMF_MSG_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CRMF_MSG_sk_type(sk))
#define sk_OSSL_CRMF_MSG_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CRMF_MSG_sk_type(sk))
#define sk_OSSL_CRMF_MSG_delete(sk, i) ((OSSL_CRMF_MSG *)OPENSSL_sk_delete(ossl_check_OSSL_CRMF_MSG_sk_type(sk), (i)))
#define sk_OSSL_CRMF_MSG_delete_ptr(sk, ptr) ((OSSL_CRMF_MSG *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr)))
#define sk_OSSL_CRMF_MSG_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr))
#define sk_OSSL_CRMF_MSG_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr))
#define sk_OSSL_CRMF_MSG_pop(sk) ((OSSL_CRMF_MSG *)OPENSSL_sk_pop(ossl_check_OSSL_CRMF_MSG_sk_type(sk)))
#define sk_OSSL_CRMF_MSG_shift(sk) ((OSSL_CRMF_MSG *)OPENSSL_sk_shift(ossl_check_OSSL_CRMF_MSG_sk_type(sk)))
#define sk_OSSL_CRMF_MSG_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CRMF_MSG_sk_type(sk),ossl_check_OSSL_CRMF_MSG_freefunc_type(freefunc))
#define sk_OSSL_CRMF_MSG_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr), (idx))
#define sk_OSSL_CRMF_MSG_set(sk, idx, ptr) ((OSSL_CRMF_MSG *)OPENSSL_sk_set(ossl_check_OSSL_CRMF_MSG_sk_type(sk), (idx), ossl_check_OSSL_CRMF_MSG_type(ptr)))
#define sk_OSSL_CRMF_MSG_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr))
#define sk_OSSL_CRMF_MSG_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr))
#define sk_OSSL_CRMF_MSG_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_type(ptr), pnum)
#define sk_OSSL_CRMF_MSG_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CRMF_MSG_sk_type(sk))
#define sk_OSSL_CRMF_MSG_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CRMF_MSG_sk_type(sk))
#define sk_OSSL_CRMF_MSG_dup(sk) ((STACK_OF(OSSL_CRMF_MSG) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CRMF_MSG_sk_type(sk)))
#define sk_OSSL_CRMF_MSG_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CRMF_MSG) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_copyfunc_type(copyfunc), ossl_check_OSSL_CRMF_MSG_freefunc_type(freefunc)))
#define sk_OSSL_CRMF_MSG_set_cmp_func(sk, cmp) ((sk_OSSL_CRMF_MSG_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CRMF_MSG_sk_type(sk), ossl_check_OSSL_CRMF_MSG_compfunc_type(cmp)))
typedef struct ossl_crmf_attributetypeandvalue_st OSSL_CRMF_ATTRIBUTETYPEANDVALUE;
typedef struct ossl_crmf_pbmparameter_st OSSL_CRMF_PBMPARAMETER;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PBMPARAMETER)
typedef struct ossl_crmf_poposigningkey_st OSSL_CRMF_POPOSIGNINGKEY;
typedef struct ossl_crmf_certrequest_st OSSL_CRMF_CERTREQUEST;
typedef struct ossl_crmf_certid_st OSSL_CRMF_CERTID;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTID)
DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID)
SKM_DEFINE_STACK_OF_INTERNAL(OSSL_CRMF_CERTID, OSSL_CRMF_CERTID, OSSL_CRMF_CERTID)
#define sk_OSSL_CRMF_CERTID_num(sk) OPENSSL_sk_num(ossl_check_const_OSSL_CRMF_CERTID_sk_type(sk))
#define sk_OSSL_CRMF_CERTID_value(sk, idx) ((OSSL_CRMF_CERTID *)OPENSSL_sk_value(ossl_check_const_OSSL_CRMF_CERTID_sk_type(sk), (idx)))
#define sk_OSSL_CRMF_CERTID_new(cmp) ((STACK_OF(OSSL_CRMF_CERTID) *)OPENSSL_sk_new(ossl_check_OSSL_CRMF_CERTID_compfunc_type(cmp)))
#define sk_OSSL_CRMF_CERTID_new_null() ((STACK_OF(OSSL_CRMF_CERTID) *)OPENSSL_sk_new_null())
#define sk_OSSL_CRMF_CERTID_new_reserve(cmp, n) ((STACK_OF(OSSL_CRMF_CERTID) *)OPENSSL_sk_new_reserve(ossl_check_OSSL_CRMF_CERTID_compfunc_type(cmp), (n)))
#define sk_OSSL_CRMF_CERTID_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), (n))
#define sk_OSSL_CRMF_CERTID_free(sk) OPENSSL_sk_free(ossl_check_OSSL_CRMF_CERTID_sk_type(sk))
#define sk_OSSL_CRMF_CERTID_zero(sk) OPENSSL_sk_zero(ossl_check_OSSL_CRMF_CERTID_sk_type(sk))
#define sk_OSSL_CRMF_CERTID_delete(sk, i) ((OSSL_CRMF_CERTID *)OPENSSL_sk_delete(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), (i)))
#define sk_OSSL_CRMF_CERTID_delete_ptr(sk, ptr) ((OSSL_CRMF_CERTID *)OPENSSL_sk_delete_ptr(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr)))
#define sk_OSSL_CRMF_CERTID_push(sk, ptr) OPENSSL_sk_push(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr))
#define sk_OSSL_CRMF_CERTID_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr))
#define sk_OSSL_CRMF_CERTID_pop(sk) ((OSSL_CRMF_CERTID *)OPENSSL_sk_pop(ossl_check_OSSL_CRMF_CERTID_sk_type(sk)))
#define sk_OSSL_CRMF_CERTID_shift(sk) ((OSSL_CRMF_CERTID *)OPENSSL_sk_shift(ossl_check_OSSL_CRMF_CERTID_sk_type(sk)))
#define sk_OSSL_CRMF_CERTID_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_OSSL_CRMF_CERTID_sk_type(sk),ossl_check_OSSL_CRMF_CERTID_freefunc_type(freefunc))
#define sk_OSSL_CRMF_CERTID_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr), (idx))
#define sk_OSSL_CRMF_CERTID_set(sk, idx, ptr) ((OSSL_CRMF_CERTID *)OPENSSL_sk_set(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), (idx), ossl_check_OSSL_CRMF_CERTID_type(ptr)))
#define sk_OSSL_CRMF_CERTID_find(sk, ptr) OPENSSL_sk_find(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr))
#define sk_OSSL_CRMF_CERTID_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr))
#define sk_OSSL_CRMF_CERTID_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_type(ptr), pnum)
#define sk_OSSL_CRMF_CERTID_sort(sk) OPENSSL_sk_sort(ossl_check_OSSL_CRMF_CERTID_sk_type(sk))
#define sk_OSSL_CRMF_CERTID_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_OSSL_CRMF_CERTID_sk_type(sk))
#define sk_OSSL_CRMF_CERTID_dup(sk) ((STACK_OF(OSSL_CRMF_CERTID) *)OPENSSL_sk_dup(ossl_check_const_OSSL_CRMF_CERTID_sk_type(sk)))
#define sk_OSSL_CRMF_CERTID_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(OSSL_CRMF_CERTID) *)OPENSSL_sk_deep_copy(ossl_check_const_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_copyfunc_type(copyfunc), ossl_check_OSSL_CRMF_CERTID_freefunc_type(freefunc)))
#define sk_OSSL_CRMF_CERTID_set_cmp_func(sk, cmp) ((sk_OSSL_CRMF_CERTID_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_OSSL_CRMF_CERTID_sk_type(sk), ossl_check_OSSL_CRMF_CERTID_compfunc_type(cmp)))
typedef struct ossl_crmf_pkipublicationinfo_st OSSL_CRMF_PKIPUBLICATIONINFO;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PKIPUBLICATIONINFO)
typedef struct ossl_crmf_singlepubinfo_st OSSL_CRMF_SINGLEPUBINFO;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_SINGLEPUBINFO)
typedef struct ossl_crmf_certtemplate_st OSSL_CRMF_CERTTEMPLATE;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE)
typedef STACK_OF(OSSL_CRMF_MSG) OSSL_CRMF_MSGS;
DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_MSGS)
typedef struct ossl_crmf_optionalvalidity_st OSSL_CRMF_OPTIONALVALIDITY;
/* crmf_pbm.c */
OSSL_CRMF_PBMPARAMETER *OSSL_CRMF_pbmp_new(OSSL_LIB_CTX *libctx, size_t slen,
int owfnid, size_t itercnt,
int macnid);
int OSSL_CRMF_pbm_new(OSSL_LIB_CTX *libctx, const char *propq,
const OSSL_CRMF_PBMPARAMETER *pbmp,
const unsigned char *msg, size_t msglen,
const unsigned char *sec, size_t seclen,
unsigned char **mac, size_t *maclen);
/* crmf_lib.c */
int OSSL_CRMF_MSG_set1_regCtrl_regToken(OSSL_CRMF_MSG *msg,
const ASN1_UTF8STRING *tok);
ASN1_UTF8STRING
*OSSL_CRMF_MSG_get0_regCtrl_regToken(const OSSL_CRMF_MSG *msg);
int OSSL_CRMF_MSG_set1_regCtrl_authenticator(OSSL_CRMF_MSG *msg,
const ASN1_UTF8STRING *auth);
ASN1_UTF8STRING
*OSSL_CRMF_MSG_get0_regCtrl_authenticator(const OSSL_CRMF_MSG *msg);
int
OSSL_CRMF_MSG_PKIPublicationInfo_push0_SinglePubInfo(OSSL_CRMF_PKIPUBLICATIONINFO *pi,
OSSL_CRMF_SINGLEPUBINFO *spi);
# define OSSL_CRMF_PUB_METHOD_DONTCARE 0
# define OSSL_CRMF_PUB_METHOD_X500 1
# define OSSL_CRMF_PUB_METHOD_WEB 2
# define OSSL_CRMF_PUB_METHOD_LDAP 3
int OSSL_CRMF_MSG_set0_SinglePubInfo(OSSL_CRMF_SINGLEPUBINFO *spi,
int method, GENERAL_NAME *nm);
# define OSSL_CRMF_PUB_ACTION_DONTPUBLISH 0
# define OSSL_CRMF_PUB_ACTION_PLEASEPUBLISH 1
int OSSL_CRMF_MSG_set_PKIPublicationInfo_action(OSSL_CRMF_PKIPUBLICATIONINFO *pi,
int action);
int OSSL_CRMF_MSG_set1_regCtrl_pkiPublicationInfo(OSSL_CRMF_MSG *msg,
const OSSL_CRMF_PKIPUBLICATIONINFO *pi);
OSSL_CRMF_PKIPUBLICATIONINFO
*OSSL_CRMF_MSG_get0_regCtrl_pkiPublicationInfo(const OSSL_CRMF_MSG *msg);
int OSSL_CRMF_MSG_set1_regCtrl_protocolEncrKey(OSSL_CRMF_MSG *msg,
const X509_PUBKEY *pubkey);
X509_PUBKEY
*OSSL_CRMF_MSG_get0_regCtrl_protocolEncrKey(const OSSL_CRMF_MSG *msg);
int OSSL_CRMF_MSG_set1_regCtrl_oldCertID(OSSL_CRMF_MSG *msg,
const OSSL_CRMF_CERTID *cid);
OSSL_CRMF_CERTID
*OSSL_CRMF_MSG_get0_regCtrl_oldCertID(const OSSL_CRMF_MSG *msg);
OSSL_CRMF_CERTID *OSSL_CRMF_CERTID_gen(const X509_NAME *issuer,
const ASN1_INTEGER *serial);
int OSSL_CRMF_MSG_set1_regInfo_utf8Pairs(OSSL_CRMF_MSG *msg,
const ASN1_UTF8STRING *utf8pairs);
ASN1_UTF8STRING
*OSSL_CRMF_MSG_get0_regInfo_utf8Pairs(const OSSL_CRMF_MSG *msg);
int OSSL_CRMF_MSG_set1_regInfo_certReq(OSSL_CRMF_MSG *msg,
const OSSL_CRMF_CERTREQUEST *cr);
OSSL_CRMF_CERTREQUEST
*OSSL_CRMF_MSG_get0_regInfo_certReq(const OSSL_CRMF_MSG *msg);
int OSSL_CRMF_MSG_set0_validity(OSSL_CRMF_MSG *crm,
ASN1_TIME *notBefore, ASN1_TIME *notAfter);
int OSSL_CRMF_MSG_set_certReqId(OSSL_CRMF_MSG *crm, int rid);
int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm);
int OSSL_CRMF_MSG_set0_extensions(OSSL_CRMF_MSG *crm, X509_EXTENSIONS *exts);
int OSSL_CRMF_MSG_push0_extension(OSSL_CRMF_MSG *crm, X509_EXTENSION *ext);
# define OSSL_CRMF_POPO_NONE -1
# define OSSL_CRMF_POPO_RAVERIFIED 0
# define OSSL_CRMF_POPO_SIGNATURE 1
# define OSSL_CRMF_POPO_KEYENC 2
# define OSSL_CRMF_POPO_KEYAGREE 3
int OSSL_CRMF_MSG_create_popo(int meth, OSSL_CRMF_MSG *crm,
EVP_PKEY *pkey, const EVP_MD *digest,
OSSL_LIB_CTX *libctx, const char *propq);
int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs,
int rid, int acceptRAVerified,
OSSL_LIB_CTX *libctx, const char *propq);
OSSL_CRMF_CERTTEMPLATE *OSSL_CRMF_MSG_get0_tmpl(const OSSL_CRMF_MSG *crm);
const ASN1_INTEGER
*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl);
const X509_NAME
*OSSL_CRMF_CERTTEMPLATE_get0_subject(const OSSL_CRMF_CERTTEMPLATE *tmpl);
const X509_NAME
*OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl);
X509_EXTENSIONS
*OSSL_CRMF_CERTTEMPLATE_get0_extensions(const OSSL_CRMF_CERTTEMPLATE *tmpl);
const X509_NAME
*OSSL_CRMF_CERTID_get0_issuer(const OSSL_CRMF_CERTID *cid);
const ASN1_INTEGER
*OSSL_CRMF_CERTID_get0_serialNumber(const OSSL_CRMF_CERTID *cid);
int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl,
EVP_PKEY *pubkey,
const X509_NAME *subject,
const X509_NAME *issuer,
const ASN1_INTEGER *serial);
X509
*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert,
OSSL_LIB_CTX *libctx, const char *propq,
EVP_PKEY *pkey);
# ifdef __cplusplus
}
# endif
# endif /* !defined(OPENSSL_NO_CRMF) */
#endif /* !defined(OPENSSL_CRMF_H) */
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -279,7 +279,8 @@ typedef unsigned __int64 uint64_t;
# define ossl_inline inline
# endif
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && \
!defined(__cplusplus)
# define ossl_noreturn _Noreturn
# elif defined(__GNUC__) && __GNUC__ >= 2
# define ossl_noreturn __attribute__((noreturn))
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2002-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (the "License"). You may not use
@@ -793,12 +793,15 @@ int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1,
EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len);
int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out);
# define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x)
# define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x)
# define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \
(char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x))
# define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \
(unsigned char *)(x))
# define d2i_ECPKParameters_bio(bp,x) \
ASN1_d2i_bio_of(EC_GROUP, NULL, d2i_ECPKParameters, bp, x)
# define i2d_ECPKParameters_bio(bp,x) \
ASN1_i2d_bio_of_const(EC_GROUP, i2d_ECPKParameters, bp, x)
# define d2i_ECPKParameters_fp(fp,x) \
(EC_GROUP *)ASN1_d2i_fp(NULL, (d2i_of_void *)d2i_ECPKParameters, (fp), \
(void **)(x))
# define i2d_ECPKParameters_fp(fp,x) \
ASN1_i2d_fp((i2d_of_void *)i2d_ECPKParameters, (fp), (void *)(x))
int ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off);
# ifndef OPENSSL_NO_STDIO
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
*
* Licensed under the OpenSSL license (the "License"). You may not use
@@ -722,6 +722,7 @@ typedef int (*dynamic_bind_engine) (ENGINE *e, const char *id,
CRYPTO_set_mem_functions(fns->mem_fns.malloc_fn, \
fns->mem_fns.realloc_fn, \
fns->mem_fns.free_fn); \
OPENSSL_init_crypto(OPENSSL_INIT_NO_ATEXIT, NULL); \
skip_cbs: \
if (!fn(e, id)) return 0; \
return 1; }
@@ -0,0 +1,128 @@
/*
* WARNING: do not edit!
* Generated by Makefile from include/openssl/ess.h.in
*
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_ESS_H
# define OPENSSL_ESS_H
# pragma once
# include <openssl/opensslconf.h>
# include <openssl/safestack.h>
# include <openssl/x509.h>
# include <openssl/esserr.h>
# ifdef __cplusplus
extern "C" {
# endif
typedef struct ESS_issuer_serial ESS_ISSUER_SERIAL;
typedef struct ESS_cert_id ESS_CERT_ID;
typedef struct ESS_signing_cert ESS_SIGNING_CERT;
SKM_DEFINE_STACK_OF_INTERNAL(ESS_CERT_ID, ESS_CERT_ID, ESS_CERT_ID)
#define sk_ESS_CERT_ID_num(sk) OPENSSL_sk_num(ossl_check_const_ESS_CERT_ID_sk_type(sk))
#define sk_ESS_CERT_ID_value(sk, idx) ((ESS_CERT_ID *)OPENSSL_sk_value(ossl_check_const_ESS_CERT_ID_sk_type(sk), (idx)))
#define sk_ESS_CERT_ID_new(cmp) ((STACK_OF(ESS_CERT_ID) *)OPENSSL_sk_new(ossl_check_ESS_CERT_ID_compfunc_type(cmp)))
#define sk_ESS_CERT_ID_new_null() ((STACK_OF(ESS_CERT_ID) *)OPENSSL_sk_new_null())
#define sk_ESS_CERT_ID_new_reserve(cmp, n) ((STACK_OF(ESS_CERT_ID) *)OPENSSL_sk_new_reserve(ossl_check_ESS_CERT_ID_compfunc_type(cmp), (n)))
#define sk_ESS_CERT_ID_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ESS_CERT_ID_sk_type(sk), (n))
#define sk_ESS_CERT_ID_free(sk) OPENSSL_sk_free(ossl_check_ESS_CERT_ID_sk_type(sk))
#define sk_ESS_CERT_ID_zero(sk) OPENSSL_sk_zero(ossl_check_ESS_CERT_ID_sk_type(sk))
#define sk_ESS_CERT_ID_delete(sk, i) ((ESS_CERT_ID *)OPENSSL_sk_delete(ossl_check_ESS_CERT_ID_sk_type(sk), (i)))
#define sk_ESS_CERT_ID_delete_ptr(sk, ptr) ((ESS_CERT_ID *)OPENSSL_sk_delete_ptr(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr)))
#define sk_ESS_CERT_ID_push(sk, ptr) OPENSSL_sk_push(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr))
#define sk_ESS_CERT_ID_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr))
#define sk_ESS_CERT_ID_pop(sk) ((ESS_CERT_ID *)OPENSSL_sk_pop(ossl_check_ESS_CERT_ID_sk_type(sk)))
#define sk_ESS_CERT_ID_shift(sk) ((ESS_CERT_ID *)OPENSSL_sk_shift(ossl_check_ESS_CERT_ID_sk_type(sk)))
#define sk_ESS_CERT_ID_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ESS_CERT_ID_sk_type(sk),ossl_check_ESS_CERT_ID_freefunc_type(freefunc))
#define sk_ESS_CERT_ID_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr), (idx))
#define sk_ESS_CERT_ID_set(sk, idx, ptr) ((ESS_CERT_ID *)OPENSSL_sk_set(ossl_check_ESS_CERT_ID_sk_type(sk), (idx), ossl_check_ESS_CERT_ID_type(ptr)))
#define sk_ESS_CERT_ID_find(sk, ptr) OPENSSL_sk_find(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr))
#define sk_ESS_CERT_ID_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr))
#define sk_ESS_CERT_ID_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_type(ptr), pnum)
#define sk_ESS_CERT_ID_sort(sk) OPENSSL_sk_sort(ossl_check_ESS_CERT_ID_sk_type(sk))
#define sk_ESS_CERT_ID_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ESS_CERT_ID_sk_type(sk))
#define sk_ESS_CERT_ID_dup(sk) ((STACK_OF(ESS_CERT_ID) *)OPENSSL_sk_dup(ossl_check_const_ESS_CERT_ID_sk_type(sk)))
#define sk_ESS_CERT_ID_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ESS_CERT_ID) *)OPENSSL_sk_deep_copy(ossl_check_const_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_copyfunc_type(copyfunc), ossl_check_ESS_CERT_ID_freefunc_type(freefunc)))
#define sk_ESS_CERT_ID_set_cmp_func(sk, cmp) ((sk_ESS_CERT_ID_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ESS_CERT_ID_sk_type(sk), ossl_check_ESS_CERT_ID_compfunc_type(cmp)))
typedef struct ESS_signing_cert_v2_st ESS_SIGNING_CERT_V2;
typedef struct ESS_cert_id_v2_st ESS_CERT_ID_V2;
SKM_DEFINE_STACK_OF_INTERNAL(ESS_CERT_ID_V2, ESS_CERT_ID_V2, ESS_CERT_ID_V2)
#define sk_ESS_CERT_ID_V2_num(sk) OPENSSL_sk_num(ossl_check_const_ESS_CERT_ID_V2_sk_type(sk))
#define sk_ESS_CERT_ID_V2_value(sk, idx) ((ESS_CERT_ID_V2 *)OPENSSL_sk_value(ossl_check_const_ESS_CERT_ID_V2_sk_type(sk), (idx)))
#define sk_ESS_CERT_ID_V2_new(cmp) ((STACK_OF(ESS_CERT_ID_V2) *)OPENSSL_sk_new(ossl_check_ESS_CERT_ID_V2_compfunc_type(cmp)))
#define sk_ESS_CERT_ID_V2_new_null() ((STACK_OF(ESS_CERT_ID_V2) *)OPENSSL_sk_new_null())
#define sk_ESS_CERT_ID_V2_new_reserve(cmp, n) ((STACK_OF(ESS_CERT_ID_V2) *)OPENSSL_sk_new_reserve(ossl_check_ESS_CERT_ID_V2_compfunc_type(cmp), (n)))
#define sk_ESS_CERT_ID_V2_reserve(sk, n) OPENSSL_sk_reserve(ossl_check_ESS_CERT_ID_V2_sk_type(sk), (n))
#define sk_ESS_CERT_ID_V2_free(sk) OPENSSL_sk_free(ossl_check_ESS_CERT_ID_V2_sk_type(sk))
#define sk_ESS_CERT_ID_V2_zero(sk) OPENSSL_sk_zero(ossl_check_ESS_CERT_ID_V2_sk_type(sk))
#define sk_ESS_CERT_ID_V2_delete(sk, i) ((ESS_CERT_ID_V2 *)OPENSSL_sk_delete(ossl_check_ESS_CERT_ID_V2_sk_type(sk), (i)))
#define sk_ESS_CERT_ID_V2_delete_ptr(sk, ptr) ((ESS_CERT_ID_V2 *)OPENSSL_sk_delete_ptr(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr)))
#define sk_ESS_CERT_ID_V2_push(sk, ptr) OPENSSL_sk_push(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr))
#define sk_ESS_CERT_ID_V2_unshift(sk, ptr) OPENSSL_sk_unshift(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr))
#define sk_ESS_CERT_ID_V2_pop(sk) ((ESS_CERT_ID_V2 *)OPENSSL_sk_pop(ossl_check_ESS_CERT_ID_V2_sk_type(sk)))
#define sk_ESS_CERT_ID_V2_shift(sk) ((ESS_CERT_ID_V2 *)OPENSSL_sk_shift(ossl_check_ESS_CERT_ID_V2_sk_type(sk)))
#define sk_ESS_CERT_ID_V2_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_ESS_CERT_ID_V2_sk_type(sk),ossl_check_ESS_CERT_ID_V2_freefunc_type(freefunc))
#define sk_ESS_CERT_ID_V2_insert(sk, ptr, idx) OPENSSL_sk_insert(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr), (idx))
#define sk_ESS_CERT_ID_V2_set(sk, idx, ptr) ((ESS_CERT_ID_V2 *)OPENSSL_sk_set(ossl_check_ESS_CERT_ID_V2_sk_type(sk), (idx), ossl_check_ESS_CERT_ID_V2_type(ptr)))
#define sk_ESS_CERT_ID_V2_find(sk, ptr) OPENSSL_sk_find(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr))
#define sk_ESS_CERT_ID_V2_find_ex(sk, ptr) OPENSSL_sk_find_ex(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr))
#define sk_ESS_CERT_ID_V2_find_all(sk, ptr, pnum) OPENSSL_sk_find_all(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_type(ptr), pnum)
#define sk_ESS_CERT_ID_V2_sort(sk) OPENSSL_sk_sort(ossl_check_ESS_CERT_ID_V2_sk_type(sk))
#define sk_ESS_CERT_ID_V2_is_sorted(sk) OPENSSL_sk_is_sorted(ossl_check_const_ESS_CERT_ID_V2_sk_type(sk))
#define sk_ESS_CERT_ID_V2_dup(sk) ((STACK_OF(ESS_CERT_ID_V2) *)OPENSSL_sk_dup(ossl_check_const_ESS_CERT_ID_V2_sk_type(sk)))
#define sk_ESS_CERT_ID_V2_deep_copy(sk, copyfunc, freefunc) ((STACK_OF(ESS_CERT_ID_V2) *)OPENSSL_sk_deep_copy(ossl_check_const_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_copyfunc_type(copyfunc), ossl_check_ESS_CERT_ID_V2_freefunc_type(freefunc)))
#define sk_ESS_CERT_ID_V2_set_cmp_func(sk, cmp) ((sk_ESS_CERT_ID_V2_compfunc)OPENSSL_sk_set_cmp_func(ossl_check_ESS_CERT_ID_V2_sk_type(sk), ossl_check_ESS_CERT_ID_V2_compfunc_type(cmp)))
DECLARE_ASN1_ALLOC_FUNCTIONS(ESS_ISSUER_SERIAL)
DECLARE_ASN1_ENCODE_FUNCTIONS_only(ESS_ISSUER_SERIAL, ESS_ISSUER_SERIAL)
DECLARE_ASN1_DUP_FUNCTION(ESS_ISSUER_SERIAL)
DECLARE_ASN1_ALLOC_FUNCTIONS(ESS_CERT_ID)
DECLARE_ASN1_ENCODE_FUNCTIONS_only(ESS_CERT_ID, ESS_CERT_ID)
DECLARE_ASN1_DUP_FUNCTION(ESS_CERT_ID)
DECLARE_ASN1_FUNCTIONS(ESS_SIGNING_CERT)
DECLARE_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT)
DECLARE_ASN1_ALLOC_FUNCTIONS(ESS_CERT_ID_V2)
DECLARE_ASN1_ENCODE_FUNCTIONS_only(ESS_CERT_ID_V2, ESS_CERT_ID_V2)
DECLARE_ASN1_DUP_FUNCTION(ESS_CERT_ID_V2)
DECLARE_ASN1_FUNCTIONS(ESS_SIGNING_CERT_V2)
DECLARE_ASN1_DUP_FUNCTION(ESS_SIGNING_CERT_V2)
ESS_SIGNING_CERT *OSSL_ESS_signing_cert_new_init(const X509 *signcert,
const STACK_OF(X509) *certs,
int set_issuer_serial);
ESS_SIGNING_CERT_V2 *OSSL_ESS_signing_cert_v2_new_init(const EVP_MD *hash_alg,
const X509 *signcert,
const
STACK_OF(X509) *certs,
int set_issuer_serial);
int OSSL_ESS_check_signing_certs(const ESS_SIGNING_CERT *ss,
const ESS_SIGNING_CERT_V2 *ssv2,
const STACK_OF(X509) *chain,
int require_signing_cert);
# ifdef __cplusplus
}
# endif
#endif
@@ -0,0 +1,36 @@
/*
* WARNING: do not edit!
* Generated by Makefile from include/openssl/fipskey.h.in
*
* Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#ifndef OPENSSL_FIPSKEY_H
# define OPENSSL_FIPSKEY_H
# pragma once
# ifdef __cplusplus
extern "C" {
# endif
/*
* The FIPS validation HMAC key, usable as an array initializer.
*/
#define FIPS_KEY_ELEMENTS \
0xf4, 0x55, 0x66, 0x50, 0xac, 0x31, 0xd3, 0x54, 0x61, 0x61, 0x0b, 0xac, 0x4e, 0xd8, 0x1b, 0x1a, 0x18, 0x1b, 0x2d, 0x8a, 0x43, 0xea, 0x28, 0x54, 0xcb, 0xae, 0x22, 0xca, 0x74, 0x56, 0x08, 0x13
/*
* The FIPS validation key, as a string.
*/
#define FIPS_KEY_STRING "f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813"
# ifdef __cplusplus
}
# endif
#endif
@@ -2,7 +2,7 @@
* WARNING: do not edit!
* Generated by crypto/objects/objects.pl
*
* Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved.
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
@@ -1,5 +1,5 @@
/*
* Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1999-2022 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -39,8 +39,8 @@ extern "C" {
* (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
* major minor fix final patch/beta)
*/
# define OPENSSL_VERSION_NUMBER 0x101010bfL
# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1k 25 Mar 2021"
# define OPENSSL_VERSION_NUMBER 0x1010111fL
# define OPENSSL_VERSION_TEXT "OpenSSL 1.1.1q 5 Jul 2022"
/*-
* The macros below are to be used for shared library (.so, .dll, ...)
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
* Copyright 2005 Nokia. All rights reserved.
*
@@ -1305,6 +1305,8 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
# define SSL_CTRL_GET_MAX_PROTO_VERSION 131
# define SSL_CTRL_GET_SIGNATURE_NID 132
# define SSL_CTRL_GET_TMP_KEY 133
# define SSL_CTRL_GET_VERIFY_CERT_STORE 137
# define SSL_CTRL_GET_CHAIN_CERT_STORE 138
# define SSL_CERT_SET_FIRST 1
# define SSL_CERT_SET_NEXT 2
# define SSL_CERT_SET_SERVER 3
@@ -1360,10 +1362,14 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)(st))
# define SSL_CTX_set1_verify_cert_store(ctx,st) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)(st))
# define SSL_CTX_get0_verify_cert_store(ctx,st) \
SSL_CTX_ctrl(ctx,SSL_CTRL_GET_VERIFY_CERT_STORE,0,(char *)(st))
# define SSL_CTX_set0_chain_cert_store(ctx,st) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)(st))
# define SSL_CTX_set1_chain_cert_store(ctx,st) \
SSL_CTX_ctrl(ctx,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)(st))
# define SSL_CTX_get0_chain_cert_store(ctx,st) \
SSL_CTX_ctrl(ctx,SSL_CTRL_GET_CHAIN_CERT_STORE,0,(char *)(st))
# define SSL_set0_chain(s,sk) \
SSL_ctrl(s,SSL_CTRL_CHAIN,0,(char *)(sk))
# define SSL_set1_chain(s,sk) \
@@ -1386,10 +1392,14 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,0,(char *)(st))
# define SSL_set1_verify_cert_store(s,st) \
SSL_ctrl(s,SSL_CTRL_SET_VERIFY_CERT_STORE,1,(char *)(st))
#define SSL_get0_verify_cert_store(s,st) \
SSL_ctrl(s,SSL_CTRL_GET_VERIFY_CERT_STORE,0,(char *)(st))
# define SSL_set0_chain_cert_store(s,st) \
SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,0,(char *)(st))
# define SSL_set1_chain_cert_store(s,st) \
SSL_ctrl(s,SSL_CTRL_SET_CHAIN_CERT_STORE,1,(char *)(st))
#define SSL_get0_chain_cert_store(s,st) \
SSL_ctrl(s,SSL_CTRL_GET_CHAIN_CERT_STORE,0,(char *)(st))
# define SSL_get1_groups(s, glist) \
SSL_ctrl(s,SSL_CTRL_GET_GROUPS,0,(int*)(glist))
# define SSL_CTX_set1_groups(ctx, glist, glistlen) \
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -70,6 +70,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_FINAL_EMS 486
# define SSL_F_FINAL_KEY_SHARE 503
# define SSL_F_FINAL_MAXFRAGMENTLEN 557
# define SSL_F_FINAL_PSK 639
# define SSL_F_FINAL_RENEGOTIATE 483
# define SSL_F_FINAL_SERVER_NAME 558
# define SSL_F_FINAL_SIG_ALGS 497
@@ -592,6 +593,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_MISSING_ECDSA_SIGNING_CERT 381
# define SSL_R_MISSING_FATAL 256
# define SSL_R_MISSING_PARAMETERS 290
# define SSL_R_MISSING_PSK_KEX_MODES_EXTENSION 310
# define SSL_R_MISSING_RSA_CERTIFICATE 168
# define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
# define SSL_R_MISSING_RSA_SIGNING_CERT 170
@@ -633,6 +635,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_NO_VERIFY_COOKIE_CALLBACK 403
# define SSL_R_NULL_SSL_CTX 195
# define SSL_R_NULL_SSL_METHOD_PASSED 196
# define SSL_R_OCSP_CALLBACK_FAILURE 294
# define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197
# define SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED 344
# define SSL_R_OVERFLOW_ERROR 237
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -38,6 +38,7 @@ int ERR_load_X509V3_strings(void);
# define X509V3_F_I2S_ASN1_IA5STRING 149
# define X509V3_F_I2S_ASN1_INTEGER 120
# define X509V3_F_I2V_AUTHORITY_INFO_ACCESS 138
# define X509V3_F_I2V_AUTHORITY_KEYID 173
# define X509V3_F_LEVEL_ADD_NODE 168
# define X509V3_F_NOTICE_SECTION 132
# define X509V3_F_NREF_NOS 133
@@ -78,6 +79,7 @@ int ERR_load_X509V3_strings(void);
# define X509V3_F_V2I_TLS_FEATURE 165
# define X509V3_F_V3_GENERIC_EXTENSION 116
# define X509V3_F_X509V3_ADD1_I2D 140
# define X509V3_F_X509V3_ADD_LEN_VALUE 174
# define X509V3_F_X509V3_ADD_VALUE 105
# define X509V3_F_X509V3_EXT_ADD 104
# define X509V3_F_X509V3_EXT_ADD_ALIAS 106
Binary file not shown.
@@ -17,6 +17,12 @@ Java_com_limelight_nvstream_jni_MoonBridge_sendMousePosition(JNIEnv *env, jclass
LiSendMousePositionEvent(x, y, referenceWidth, referenceHeight);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMouseMoveAsMousePosition(JNIEnv *env, jclass clazz,
jshort deltaX, jshort deltaY, jshort referenceWidth, jshort referenceHeight) {
LiSendMouseMoveAsMousePositionEvent(deltaX, deltaY, referenceWidth, referenceHeight);
}
JNIEXPORT void JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_sendMouseButton(JNIEnv *env, jclass clazz, jbyte buttonEvent, jbyte mouseButton) {
LiSendMouseButtonEvent(buttonEvent, mouseButton);
+6 -6
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="256dp"
android:height="256dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z"
android:fillColor="#FFFFFF"/>
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM17,13h-4v4h-2v-4L7,13v-2h4L11,7h2v4h4v2z" />
</vector>
+6 -6
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="512dp"
android:height="512dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="512dp"
android:height="512dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z"
android:fillColor="#FFFFFF"/>
android:fillColor="#FFFFFF"
android:pathData="M21,2L3,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h7v2L8,20v2h8v-2h-2v-2h7c1.1,0 2,-0.9 2,-2L23,4c0,-1.1 -0.9,-2 -2,-2zM21,16L3,16L3,4h18v12z" />
</vector>
+5 -5
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="256dp"
android:height="256dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z"/>
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
</vector>
+6 -6
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="128dp"
android:height="128dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"
android:fillColor="#FFFFFF"/>
android:fillColor="#FFFFFF"
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z" />
</vector>
+8 -4
View File
@@ -1,5 +1,9 @@
<vector android:height="128dp" android:width="128dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFF"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
+6 -6
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="128dp"
android:height="128dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="128dp"
android:height="128dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM10,16.5v-9l6,4.5 -6,4.5z"
android:fillColor="#FFFFFF"/>
android:fillColor="#FFFFFF"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM9.5,16.5v-9l7,4.5L9.5,16.5z" />
</vector>
+6 -6
View File
@@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="256dp"
android:height="256dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
android:width="256dp"
android:height="256dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"
android:fillColor="#FFFFFF"/>
android:fillColor="#FFFFFF"
android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
</vector>
@@ -13,6 +13,7 @@
android:text="@string/title_add_pc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:preferKeepClear="true"
android:layout_centerHorizontal="true"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentTop="true"/>
@@ -29,6 +30,7 @@
android:layout_alignParentStart="true"
android:ems="10"
android:singleLine="true"
android:preferKeepClear="true"
android:inputType="textNoSuggestions"
android:hint="@string/ip_hint" >
@@ -43,6 +45,7 @@
android:layout_below="@+id/manuallyAddPcText"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:preferKeepClear="true"
android:text="@android:string/ok"/>
</RelativeLayout>
@@ -25,6 +25,7 @@
android:gravity="center"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:preferKeepClear="true"
android:textSize="28sp"/>
</RelativeLayout>
+15 -1
View File
@@ -4,11 +4,23 @@
android:layout_height="match_parent"
tools:context=".Game" >
<View
android:id="@+id/backgroundTouchView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center" />
<com.limelight.ui.StreamView
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"
@@ -21,6 +33,7 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:gravity="left"
android:background="#80000000"
android:preferKeepClear="true"
android:visibility="gone" />
<TextView
@@ -34,6 +47,7 @@
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="right"
android:background="#80000000"
android:preferKeepClear="true"
android:visibility="gone" />
</merge>
@@ -57,6 +57,7 @@
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:src="@drawable/ic_settings"
android:preferKeepClear="true"
style="?android:attr/borderlessButtonStyle"/>
<ImageButton
@@ -69,6 +70,7 @@
android:layout_toRightOf="@+id/settingsButton"
android:layout_toEndOf="@+id/settingsButton"
android:src="@drawable/ic_help"
android:preferKeepClear="true"
style="?android:attr/borderlessButtonStyle"/>
<ImageButton
@@ -81,6 +83,7 @@
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:src="@drawable/ic_add"
android:preferKeepClear="true"
style="?android:attr/borderlessButtonStyle"/>
</RelativeLayout>
@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
<monochrome android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_pc_scut_background"/>
<foreground android:drawable="@mipmap/ic_pc_scut_foreground"/>
<monochrome android:drawable="@mipmap/ic_pc_scut_foreground"/>
</adaptive-icon>
+144
View File
@@ -0,0 +1,144 @@
<?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_hevcauto">Автоматично</string>
<string name="videoformat_hevcalways">Винаги използване на HEVC (може да крашне)</string>
<string name="videoformat_hevcnever">Никога да не се използва 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>
+250 -1
View File
@@ -1,2 +1,251 @@
<?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_hevcauto">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="videoformat_hevcnever">Nikdy nepoužívat HEVC</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>
+21 -1
View File
@@ -218,7 +218,7 @@
<string name="pcview_menu_header_offline">Offline</string>
<string name="pcview_menu_header_online">Online</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Verwende HEVC so fern stabile Unterstützung vorhanden ist</string>
<string name="videoformat_hevcauto">Automatisch</string>
<string name="videoformat_hevcalways">Immer HEVC verwenden (könnte Crashes verursachen)</string>
<string name="videoformat_hevcnever">Nie HEVC verwenden</string>
<string name="title_frame_pacing">Video Frame-Pacing</string>
@@ -242,4 +242,24 @@
<string name="resolution_720p">720p</string>
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="summary_troubleshooting">Tipps zur Diagnose und Behebung häufiger Streaming-Probleme anzeigen</string>
<string name="pacing_balanced_alt">Ausbalanciert mit FPS-Limit</string>
<string name="summary_checkbox_absolute_mouse_mode">Dies kann die Mausbeschleunigung für die Fernsteuerung natürlicher gestalten, ist aber mit vielen Spielen nicht kompatibel.</string>
<string name="title_troubleshooting">Anleitung zur Fehlersuche</string>
<string name="title_privacy_policy">Datenschutzbestimmungen</string>
<string name="title_checkbox_enable_audiofx">Unterstützung des System-Equalizer aktivieren</string>
<string name="summary_setup_guide">Zeige Anweisungen zum Einrichten Ihres Gaming-PCs für das Streaming an</string>
<string name="title_checkbox_absolute_mouse_mode">Modus für ferngesteuerte Maus</string>
<string name="category_help">Hilfe</string>
<string name="title_setup_guide">Einstellungsanleitung</string>
<string name="summary_privacy_policy">Moonlight\'s Datenschutzbestimmungen anzeigen</string>
<string name="summary_seekbar_deadzone">Hinweis: Einige Spiele können eine größere Controller-Totzone erzwingen als die, die in Moonlight konfiguriert ist.</string>
<string name="summary_checkbox_enable_audiofx">Ermöglicht das Funktionieren von Audioeffekten beim Streaming, kann aber die Audio-Latenz erhöhen</string>
<string name="resolution_prefix_native_portrait">(Portrait)</string>
<string name="title_checkbox_reduce_refresh_rate">Aktualisierungsrate verringern erlauben</string>
<string name="summary_checkbox_reduce_refresh_rate">Durch das Verringern der Display Aktualisierungsrate, kann, auf Kosten der Video-Latenz, der Akkuverbrauch reduziert werden</string>
<string name="resolution_prefix_native_landscape">(Landscape)</string>
<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>
</resources>
+139 -12
View File
@@ -48,7 +48,9 @@
<string name="conn_terminated_msg">La conexión ha finalizando</string>
<!-- General strings -->
<string name="ip_hint">Dirección IP del PC con GeForce</string>
<string name="searching_pc">Buscando por PCs con GeForce Experience ejecutándose</string>
<string name="searching_pc">Buscando por PCs con GameStream ejecutándose...
\n
\nVerifica que GameStream esté activado en las opciones de SHIELD dentro de GeForce Experience.</string>
<string name="yes">Si</string>
<string name="no">No</string>
<string name="lost_connection">Conexión perdida</string>
@@ -74,8 +76,8 @@
<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="summary_resolution_list">Establecer unos valores demasiado altos puede causar lag o cierres inesperados</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>
@@ -87,7 +89,7 @@
<string name="title_seekbar_deadzone">Ajustar zona muerta del stick analógico</string>
<string name="suffix_seekbar_deadzone">%</string>
<string name="title_checkbox_xb1_driver">Driver para mando Xbox 360/One</string>
<string name="summary_checkbox_xb1_driver">Activa el driver USB incluido para dispositivos sin soporte nativo para mandos de Xbox.</string>
<string name="summary_checkbox_xb1_driver">Activa el driver USB incluido para dispositivos sin soporte nativo para mandos de Xbox</string>
<string name="category_on_screen_controls_settings">Configuración de controles en pantalla</string>
<string name="title_checkbox_show_onscreen_controls">Mostrar controles en pantalla</string>
<string name="summary_checkbox_show_onscreen_controls">Muestra controles virtuales superpuestos en la pantalla táctil</string>
@@ -105,17 +107,17 @@
<string name="summary_checkbox_host_audio">Reproducir audio en el ordenador y en este dispositivo</string>
<string name="category_advanced_settings">Configuración avanzada</string>
<string name="title_video_format">Cambiar configuración HEVC</string>
<string name="summary_video_format">HEVC reduce el ancho de banda de vídeo, pero requiere un dispositivo bastante actual.</string>
<string name="summary_video_format">HEVC reduce el ancho de banda de vídeo, pero requiere un dispositivo reciente</string>
<!-- Array strings -->
<string name="videoformat_hevcauto">Usar HEVC solo si es estable</string>
<string name="videoformat_hevcalways">Siempre usar HEVC (puede fallar)</string>
<string name="videoformat_hevcauto">Automático (Recomendado)</string>
<string name="videoformat_hevcalways">Preferir HEVC</string>
<string name="videoformat_hevcnever">Nunca usar HEVC</string>
<string name="nettest_title_done">Prueba de Red Completada</string>
<string name="scut_not_paired">PC no emparejado</string>
<string name="scut_invalid_uuid">PC proporcionado no es válido</string>
<string name="scut_invalid_app_id">App proporcionada no es válida</string>
<string name="help_loading_title">Visor de Ayuda</string>
<string name="pcview_menu_header_online">En Línea</string>
<string name="scut_invalid_uuid">El PC proporcionado no es válido</string>
<string name="scut_invalid_app_id">La App proporcionada no es válida</string>
<string name="help_loading_title">Visor de ayuda</string>
<string name="pcview_menu_header_online">En línea</string>
<string name="pcview_menu_header_unknown">Actualizando</string>
<string name="pcview_menu_test_network">Probar Conexión de Red</string>
<string name="pcview_menu_details">Ver Detalles</string>
@@ -131,11 +133,136 @@
<string name="title_decoding_error">Falló el Decodificador de Video</string>
<string name="scut_deleted_pc">PC eliminado</string>
<string name="scut_pc_not_found">PC no encontrado</string>
<string name="help_loading_msg">Cargando página de ayuda </string>
<string name="help_loading_msg">Cargando página de ayuda…</string>
<string name="pcview_menu_header_offline">Fuera de línea</string>
<string name="nettest_text_success">Tu red parece no estar bloqueando Moonlight. Si aun tienes problemas de conexión, comprueba la configuración del firewall de tu PC.
\n
\nSi estas intentado transmitir mediante Internet, instala en tu pc la Moonlight Internet Hosting Tool y ejecuta el Internet Streaming Tester incluido para comprobar la conexión de tu PC a internet.</string>
<string name="nettest_text_blocked">La conexión de red actual de tu dispositivo esta bloqueando Moonlight. La Transmisión mediante Internet puede no funcionar mientras estés conectado a esta red.</string>
<string name="pair_already_in_progress">Emparejamiento ya en progreso</string>
<string name="resolution_prefix_native_fullscreen">Pantalla Completa Nativa</string>
<string name="title_audio_config_list">Configuración de Sonido Envolvente</string>
<string name="title_decoding_reset">Reiniciar Opciones de Video</string>
<string name="no_video_received_error">No se recibe video desde el equipo anfitrión.</string>
<string name="applist_details_id">ID de Aplicación:</string>
<string name="title_checkbox_mouse_emulation">Emulación de ratón usando el mando</string>
<string name="pacing_latency">Preferir la menor latencia posible</string>
<string name="pacing_balanced">Equilibrado</string>
<string name="pacing_smoothness">Preferir mayor fluidez de video (puede incrementar significativamente la latencia)</string>
<string name="perf_overlay_decoder">Decodificador: %1$s</string>
<string name="perf_overlay_incomingfps">Tasa de cuadros obtenida de la red: %1$.2f FPS</string>
<string name="perf_overlay_renderingfps">Tasa de Cuadros Renderizada: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Cuadros perdidos por tu conexión de internet: %1$.2f%%</string>
<string name="perf_overlay_netlatency">Latencia promedio de red:%1$d ms (variación: %2$d ms)</string>
<string name="perf_overlay_dectime">Tiempo promedio de descodificado: %1$.2f ms</string>
<string name="perf_overlay_streamdetails">Transmisión video: %1$s %2$.2f FPS</string>
<string name="title_fps_list">Tasa de cuadros en el video</string>
<string name="summary_fps_list">Incrementar para una experiencia mas fluida en la transmisión. Disminuir para una mejoría en el rendimiento en dispositivos de gama de entrada.</string>
<string name="summary_reset_osc">Reiniciar toda la configuración a las predeterminadas de tamaño y posición para los controles en pantalla</string>
<string name="summary_troubleshooting">Mostrar consejos para diagnosticar y corregir errores comunes respecto a la transmisión</string>
<string name="title_privacy_policy">Política de Privacidad</string>
<string name="resolution_360p">360p</string>
<string name="resolution_1440p">1440p</string>
<string name="resolution_4k">4K</string>
<string name="suffix_osc_opacity">%</string>
<string name="title_checkbox_enable_pip">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>
<string name="title_troubleshooting">Guía de Solución de Errores</string>
<string name="resolution_1080p">1080p</string>
<string name="summary_frame_pacing">Especificar como balancear la latencia de video y la fluidez</string>
<string name="pacing_balanced_alt">Equilibrado con limitador de FPS (Cuadros por Segundo)</string>
<string name="audioconf_51surround">5.1 Sonido Envolvente</string>
<string name="audioconf_stereo">Estéreo</string>
<string name="check_ports_msg">Revisa la configuración de tu firewall, así como, las reglas de redireccionamiento para él(los) puerto(s):</string>
<string name="error_usb_prohibited">El acceso a USB está restringido en tu dispositivo por el administrador. Revisar tus ajustes en MDM o Knox.</string>
<string name="message_decoding_error">Moonlight se ha cerrado debido a una incompatibilidad con el decodificador de vídeo de este dispositivo. Asegúrate de que GeForce Experience está actualizado a la última versión en tu PC. Intenta ajustar la configuración de streaming si los bloqueos continúan.</string>
<string name="message_decoding_reset">La decodificación de video de tu equipo sigue fallando con las opciones elegidas. Las opciones de la transmisión han sido revertidas a las predeterminadas.</string>
<string name="video_decoder_init_failed">El descodificador de video no pudo ser iniciado. Tu dispositivo puede no soportar la resolución elegida o la tasa de cuadros por segundo.</string>
<string name="no_frame_received_error">La conexión de internet no está teniendo un buen desempeño. Reduce la tasa de bits de video o prueba en una conexión de mayor velocidad.</string>
<string name="unable_to_pin_shortcut">Tu lanzador predeterminado no permite la creación de accesos directos anclados.</string>
<string name="early_termination_error">Algo ha salido mal en el PC anfitrión cuando se inicio la transmisión.
\n
\nVerifica que no tengas ningún contenido protegido por DRM abierto en el equipo. También prueba reiniciando el equipo anfitrión.
\n
\nSi el problema persiste, intenta reinstalar los controladores de la tarjeta de video (GPU) además de GeForce Experience.</string>
<string name="title_details">Detalles</string>
<string name="poor_connection_msg">Conexión pobre al PC</string>
<string name="applist_menu_details">Ver Detalles</string>
<string name="applist_menu_scut">Crear Acceso Directo</string>
<string name="applist_menu_tv_channel">Agregar al Canal</string>
<string name="applist_menu_hide_app">Esconder Aplicación</string>
<string name="applist_connect_msg">Conectando al Equipo…</string>
<string name="summary_checkbox_mouse_nav_buttons">Activar esta opción puede desconfigurar la función de clic derecho en algunos dispositivos inestables</string>
<string name="text_native_res_dialog">Modos de resolución nativa no son oficialmente soportados por GeForce Experience, así que no se no se aplicarán por su cuenta en la pantalla del equipo anfitrión. Vas a necesitar ajustarlos manualmente en el juego.
\n
\nSi eliges crear una resolución personalizada en el Panel de Control de Nvidia para ajustarse a la resolución de tu dispositivo, por favor considera haber leído y entendido la advertencia de NVIDIA respectivo a cualquier daño posible a tu monitor, inestabilidad del equipo, y otros problemas potencialmente posibles.
\n
\nNo somos responsables de cualquier problema por haber creador una resolución personalizada en tu PC.
\n
\nFinalmente, tu dispositivo o tu Pc anfitrión, podrían no soportar la transmisión a resolución nativa. Si no funciona en tu equipo, puede que solo no tengas suerte de momento.</string>
<string name="resolution_prefix_native">Nativo</string>
<string name="summary_audio_config_list">Activar sonido envolvente de 5.1 o 7.1 canales para sistemas de teatro en casa</string>
<string name="title_checkbox_vibrate_fallback">Emular la vibración del mando con vibración del equipo</string>
<string name="summary_checkbox_enable_audiofx">Permitir funcionar efectos de sonido durante la transmisión, pero podría incrementar la latencia del sonido</string>
<string name="summary_checkbox_usb_bind_all">Usar el controlador de USB de Moonlight para todos los mandos soportados, incluso si el control de Xbox se encuentra presente</string>
<string name="summary_checkbox_mouse_emulation">Presionar por un periodo largo el botón de inicio hará cambiar el mando a modo de ratón</string>
<string name="title_checkbox_mouse_nav_buttons">Activar los botones atrás y adelante del ratón</string>
<string name="title_unlock_fps">Desbloquear todas las opciones de tasa de cuadros disponibles</string>
<string name="summary_unlock_fps">Transmitir a 90 o 120 FPS puede reducir latencia en dispositivos de gama alta pero puede causar retrasos en dispositivos que no lo soporten</string>
<string name="title_enable_perf_overlay">Mostrar estadísticas de rendimiento mientras la transmisión está activa</string>
<string name="summary_enable_post_stream_toast">Mostrar un mensaje sobre la información de latencia cuando la transmisión termine</string>
<string name="help">Ayuda</string>
<string name="delete_pc_msg">¿Estás seguro de eliminar este PC\?</string>
<string name="slow_connection_msg">Conexión lenta al PC
\nReduce la tasa de bits</string>
<string name="addpc_wrong_sitelocal">La dirección no luce correcta. Debes usar la dirección IP Pública de tu Rúter para la transmisión por Internet.</string>
<string name="title_native_res_dialog">Advertencia Resolución Nativa</string>
<string name="suffix_seekbar_bitrate_mbps">Mbps</string>
<string name="category_input_settings">Opciones de Entrada</string>
<string name="title_checkbox_touchscreen_trackpad">Usa la pantalla táctil como panel táctil</string>
<string name="summary_checkbox_touchscreen_trackpad">Si está activo, la pantalla táctil funcionará como panel táctil. Si está desactivado, la pantalla táctil directamente controlará el cursor del ratón.</string>
<string name="summary_seekbar_deadzone">Nota: Algunos juegos pueden forzar una zona muerta mayor a la que Moonlight esta configurada a usar.</string>
<string name="title_checkbox_flip_face_buttons">Invertir botones frontales</string>
<string name="summary_checkbox_absolute_mouse_mode">Esto puede hacer que la aceleración de mouse se comporte mas natural para uso de escritorio remoto, pero es incompatible con muchos juegos.</string>
<string name="title_checkbox_enable_audiofx">Activar el soporte para ecualizador de sistema</string>
<string name="summary_checkbox_vibrate_fallback">Vibrar el dispositivo para emular el retumbe si tu mando de control no lo soporta</string>
<string name="title_checkbox_usb_bind_all">Sobrescribir el soporte nativo del control de Xbox</string>
<string name="summary_checkbox_flip_face_buttons">Invertir botones frontales A/B y X/Y para los mandos y los botones sobre la pantalla</string>
<string name="title_checkbox_absolute_mouse_mode">Modo de ratón para escritorio remoto</string>
<string name="title_checkbox_vibrate_osc">Activar vibración</string>
<string name="summary_checkbox_vibrate_osc">Hacer vibrar tu dispositivo para emular la vibración del juego para los controles en pantalla</string>
<string name="title_reset_osc">Borrar la configuración guardada de la plantilla para el control en pantalla</string>
<string name="dialog_title_reset_osc">Reiniciar a Plantilla Predeterminada</string>
<string name="dialog_text_reset_osc">¿Estás seguro de que quieres eliminar tus configuraciones guardadas para las plantillas de los controles en pantalla\?</string>
<string name="toast_reset_osc_success">Establecer Controles en Pantalla en modo Predeterminado</string>
<string name="title_osc_opacity">Cambiar la transparencia de los controles en pantalla</string>
<string name="summary_osc_opacity">Hacer los controles en pantalla más/menos transparentes</string>
<string name="dialog_title_osc_opacity">Cambiar opacidad</string>
<string name="summary_checkbox_enable_pip">Permite que la transmisión sea vista (pero no controlable) mientras se usa la multitarea</string>
<string name="title_disable_frame_drop">Nunca disminuir cuadros</string>
<string name="summary_disable_frame_drop">Puede reducir micro-tartamudeos (Stuttering) en algunos dispositivos , pero puede incrementar latencia</string>
<string name="title_enable_hdr">Activar HDR (Alto Rango Dinámico / Experimental)</string>
<string name="summary_enable_hdr">Transmitir HDR (Alto Rango Dinámico) cuando el juego, el PC y la Tarjeta de Video (GPU) lo soporten. HDR requiere de una Tarjeta de Video de la serie GTX 1000 o superior.</string>
<string name="summary_enable_perf_overlay">Mostrar en tiempo real la información del desempeño de la transmisión mientras está activa la misma</string>
<string name="title_enable_post_stream_toast">Mostrar mensajes sobre latencia mientras se transmite</string>
<string name="category_help">Ayuda</string>
<string name="title_setup_guide">Guía para la Configuración</string>
<string name="summary_setup_guide">Mostrar instrucciones para como configurar tu PC para juegos para la transmisión</string>
<string name="summary_privacy_policy">Mostrar la política de privacidad de Moonlight</string>
<string name="resolution_480p">480p</string>
<string name="fps_30">30 FPS</string>
<string name="fps_60">60 FPS</string>
<string name="fps_90">90 FPS</string>
<string name="title_frame_pacing">Ritmo de cuadros por segundo en video</string>
<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">Usar rango (0-255) de color completo</string>
<string name="summary_full_range">Esto puede causar problemas de video o bloqueos si la pantalla de tu dispositivo no puede manejar contenido de rango completo.</string>
</resources>
+24 -2
View File
@@ -228,8 +228,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">Utiliser HEVC uniquement s\'il est stable</string>
<string name="videoformat_hevcalways">Utilisez toujours HEVC (mais il peut planter)</string>
<string name="videoformat_hevcauto">Automatique (recommandé)</string>
<string name="videoformat_hevcalways">Préférez le HEVC</string>
<string name="videoformat_hevcnever">N\'utilisez jamais 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>
@@ -242,4 +242,26 @@
<string name="resolution_1440p">1440p</string>
<string name="resolution_1080p">1080p</string>
<string name="resolution_4k">4K</string>
<string name="category_help">Aide</string>
<string name="title_setup_guide">Guide de configuration</string>
<string name="title_troubleshooting">Guide de dépannage</string>
<string name="title_privacy_policy">Politique de confidentialité</string>
<string name="summary_privacy_policy">Voir la politique de confidentialité de Moonlight</string>
<string name="summary_setup_guide">Afficher les instructions sur la façon de configurer votre PC de jeu pour le streaming</string>
<string name="summary_troubleshooting">Afficher des conseils pour diagnostiquer et résoudre les problèmes de streaming courants</string>
<string name="pacing_balanced_alt">Équilibré avec limite FPS</string>
<string name="title_checkbox_absolute_mouse_mode">Mode souris pour bureau à distance</string>
<string name="summary_seekbar_deadzone">Remarque : Certains jeux peuvent imposer une zone morte plus grande que celle que Moonlight est configuré pour utiliser.</string>
<string name="summary_checkbox_absolute_mouse_mode">Cela peut rendre l\'accélération de la souris plus naturelle pour l\'utilisation du bureau à distance, mais elle est incompatible avec de nombreux jeux.</string>
<string name="resolution_prefix_native_landscape">(Paysage)</string>
<string name="resolution_prefix_native_portrait">(Portrait)</string>
<string name="title_checkbox_reduce_refresh_rate">Autoriser la réduction du taux de rafraîchissement</string>
<string name="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>
</resources>
+96
View File
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="scut_not_paired">Komputer tidak terpasang</string>
<string name="scut_pc_not_found">Komputer tidak ditemukan</string>
<string name="scut_invalid_uuid">Komputer yang diberikan tidak valid</string>
<string name="help_loading_title">Lihat bantuan</string>
<string name="help_loading_msg">Memuat laman bantuan…</string>
<string name="pcview_menu_header_online">Tersedia</string>
<string name="pcview_menu_header_offline">Tidak tersedia</string>
<string name="pcview_menu_header_unknown">Memuat ulang</string>
<string name="pcview_menu_app_list">Lihat semua aplikasi</string>
<string name="pcview_menu_pair_pc">Pasangkan dengan komputer</string>
<string name="pcview_menu_unpair_pc">Batalkan pemasangan</string>
<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.
\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>
<string name="nettest_text_failure">Koneksi jaringan perangkat anda sepertinya memblokir Moonlight. Streaming lewat Internet mungkin tidak bekerja ketika terhubung dengan jaringan ini.
\n
\nPort-port ini telah diblokir:
\n</string>
<string name="nettest_text_blocked">Koneksi jaringan perangkat anda memblokir Moonlight. Streaming lewat Internet mungkin tidak bekerja ketika terhubung dengan jaringan ini.</string>
<string name="pair_pc_offline">Komputer tidak tersedia</string>
<string name="pair_pairing_title">Memasang</string>
<string name="pair_pairing_msg">Mohon isi PIN ini di komputer target:</string>
<string name="pair_incorrect_pin">PIN salah</string>
<string name="pair_fail">Pemasangan gagal</string>
<string name="pair_already_in_progress">Pemasangan sedang berlangsung</string>
<string name="wol_pc_online">Komputer tersedia</string>
<string name="wol_no_mac">Tidak bisa membangunkan komputer karena GFE tidak mengirimkan alamat MAC</string>
<string name="wol_waking_pc">Membangunkan komputer…</string>
<string name="wol_waking_msg">Membangunkan komputer mungkin akan membutuhkan beberapa saat. Jika tidak bisa, pastikan konfigurasi Wake-On-LAN sudah benar.</string>
<string name="unpairing">Memutuskan pemasangan…</string>
<string name="unpair_success">Pemutusan pemasangan berhasil</string>
<string name="unpair_fail">Gagal memutuskan pemasangan</string>
<string name="error_pc_offline">Komputer tidak tersedia</string>
<string name="title_decoding_error">Dekoder video berhenti bekerja</string>
<string name="message_decoding_error">Moonlight telah berhenti bekerja dikarenakan inkompatibilitas dengan dekoder video perangkat ini. Pastikan GeForce Experience sudah diperbarui ke versi terkini pada komputer Anda. Coba ganti pengaturan stream jika masih berlanjut.</string>
<string name="title_decoding_reset">Pengaturan video dipulihkan</string>
<string name="message_decoding_reset">Dekoder video perangkat Anda terus-menerus berhenti pada pengaturan stream yang dipilih. Pengaturan stream Anda telah dipulihkan ke bawaan.</string>
<string name="error_usb_prohibited">Akses USB dilarang oleh Administrator perangkat Anda. Cek pengaturan Knox atau MDM Anda.</string>
<string name="no_video_received_error">Tidak ada video yang diterima dari host.</string>
<string name="no_frame_received_error">Kinerja koneksi jaringan anda tidak baik. Kurangi pengaturan bitrate video Anda atau coba koneksi yang lebih cepat.</string>
<string name="check_ports_msg">Cek pengaturan firewall dan port forwarding untuk port-port ini:</string>
<string name="conn_establishing_title">Membangun koneksi</string>
<string name="conn_establishing_msg">Memulai koneksi</string>
<string name="conn_metered">Peringatan: Koneksi aktif Anda terbatas!</string>
<string name="conn_client_latency">Rata-rata latensi dekoding bingkai:</string>
<string name="conn_client_latency_hw">Latensi dekoder perangkat keras:</string>
<string name="conn_hardware_latency">Rata-rata latensi dekoder perangkat keras:</string>
<string name="conn_starting">Memulai</string>
<string name="conn_error_title">Koneksi eror</string>
<string name="conn_error_msg">Gagal untuk memulai</string>
<string name="conn_terminated_title">Koneksi dihentikan</string>
<string name="conn_terminated_msg">Koneksi telah terhenti</string>
<string name="ip_hint">Alamat IP komputer GeForce</string>
<string name="searching_pc">Mencari komputer yang menjalankan GameStream...
\n
\nPastikan GameStream diaktifkan pada pengaturan SHIELD GeForce Experience.</string>
<string name="yes">Ya</string>
<string name="no">Tidak</string>
<string name="lost_connection">Koneksi dengan komputer hilang</string>
<string name="title_details">Rincian</string>
<string name="delete_pc_msg">Apakah Anda yakin ingin menghapus komputer ini\?</string>
<string name="slow_connection_msg">Koneksi terhadap komputer lambat
\nKurangi bitrate anda</string>
<string name="poor_connection_msg">Koneksi dengan komputer buruk</string>
<string name="perf_overlay_streamdetails">Stream video: %1$s %2$.2f FPS</string>
<string name="perf_overlay_decoder">Dekoder: %1$s</string>
<string name="perf_overlay_incomingfps">Kecepatan bingkai masuk dari jaringan: %1$.2f FPS</string>
<string name="scut_deleted_pc">Komputer dihapus</string>
<string name="scut_invalid_app_id">Aplikasi yang diberikan tidak valid</string>
<string name="pcview_menu_test_network">Uji koneksi jaringan</string>
<string name="pcview_menu_details">Lihat rincian</string>
<string name="nettest_title_done">Uji jaringan selesai</string>
<string name="pairing">Memasang…</string>
<string name="nettest_text_success">Jaringan Anda sepertinya tidak memblokir Moonlight. Jika Anda masih mengalami masalah menghubungkan, cek pengaturan firewall komputer Anda.
\n
\nJika anda mencoba stream lewat internet, install Moonlight Internet Hosting Tool pada komputer anda dan jalankan Internet Streaming Tester untuk mengecek koneksi Internet komputer Anda.</string>
<string name="pair_pc_ingame">Komputer sedang ada di game. Anda harus menutupnya terlebih dahulu.</string>
<string name="wol_fail">Gagal mengirim paket Wake-On-LAN</string>
<string name="unpair_error">Perangkat tidak terpasang</string>
<string name="error_manager_not_running">ComputerManager tidak berjalan. Mohon tunggu beberapa saat atau mulai ulang aplikasi.</string>
<string name="error_404">GFE memberikan eror HTTP 404. Pastikan komputer anda menggunakan kartu grafis yang didukung. Penggunaan aplikasi remote desktop juga dapat menyebabakan eror ini. Coba mulai ulang perangkat Anda atau install ulang GFE.</string>
<string name="unable_to_pin_shortcut">Peluncur Anda tidak memperbolehkan pembuatan shortcut yang disematkan.</string>
<string name="video_decoder_init_failed">Gagal memulai dekoder video. Perangkat Anda mungkin tidak mendukung resolusi atau kecepatan bingkai yang dipilih.</string>
<string name="early_termination_error">Ada yang salah dengan komputer host anda ketika memulai stream.
\n
\nPastikan tidak ada konten yang dilindungi DRM yang terbuka di komputer host Anda. Coba mulai ulang komputer host.
\n
\nJika masalah berkelanjutan, coba install ulang GeForce Experience dan driver video grafis Anda.</string>
<string name="help">Bantuan</string>
</resources>
+21 -1
View File
@@ -208,7 +208,7 @@
<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">Usa HEVC solo se stabile</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="title_frame_pacing">Bilanciamento frame video</string>
@@ -243,4 +243,24 @@
<string name="perf_overlay_renderingfps">Frame rate renderizzato: %1$.2f FPS</string>
<string name="perf_overlay_netdrops">Frame scartati dalla tua connessione di rete: %1$.2f%%</string>
<string name="perf_overlay_netlatency">Latenza media della rete: %1$d ms (varianza: %2$d ms)</string>
<string name="category_help">Aiuto</string>
<string name="title_setup_guide">Guida configurazione</string>
<string name="pacing_balanced_alt">Bilanciato con il limite FPS</string>
<string name="summary_seekbar_deadzone">Nota: Alcuni giochi possono imporre una deadzone più grande di quella che Moonlight è configurato per utilizzare.</string>
<string name="title_checkbox_absolute_mouse_mode">Modalità mouse desktop remoto</string>
<string name="summary_checkbox_absolute_mouse_mode">Questo può rendere l\'accelerazione del mouse più naturale per l\'utilizzo del desktop remoto, ma è incompatibile con molti giochi.</string>
<string name="summary_setup_guide">Visualizza le istruzioni su come configurare il tuo PC da gaming per lo streaming</string>
<string name="title_troubleshooting">Guida alla risoluzione dei problemi</string>
<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>
</resources>

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