Compare commits

...

382 Commits

Author SHA1 Message Date
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
Cameron Gutman 4bdc2e0aba Add F-Droid metadata for 274 2022-05-22 18:02:21 -05:00
Cameron Gutman e69061082b Version 10.1.1 2022-05-22 17:16:37 -05:00
Cameron Gutman 1da2ec3cb1 Merge remote-tracking branch 'origin/weblate' 2022-05-22 17:15:44 -05:00
Cameron Gutman 8ffc3b80b2 Rework use of URLs in NvHTTP
- Fixes parsing inconsistencies between URI and HttpUrl
- Fixes a couple of serverinfo requests sent without uniqueid and UUID
- Avoids PairingManager having to look into NvHTTP internals
2022-05-22 16:47:45 -05:00
Cameron Gutman 08f8b6cb8e Keep the SpinnerDialog visible while the connectivity test runs 2022-05-22 15:36:38 -05:00
Cameron Gutman fb09c9692c Fix handling of InterruptedExceptions 2022-05-22 15:31:06 -05:00
Cameron Gutman 4901b0c78f Stop parallel polling threads when we find a working address 2022-05-22 14:56:28 -05:00
Cameron Gutman 0a2117241f Wrap Choreographer calls to releaseOutputBuffer() in try/catch 2022-05-22 14:32:03 -05:00
Wen-haur Chiu f352cfd15b Translated using Weblate (Chinese (Traditional))
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_Hant/
2022-05-21 14:16:28 +02:00
Cameron Gutman ac7c5c1064 Improve handling of required XML tags 2022-05-20 17:15:26 -05:00
Cameron Gutman 077cb2103d Version 10.1 2022-05-18 22:44:46 -05:00
Cameron Gutman cdeda011a4 Temporarily disable in-app links until they are translated 2022-05-18 22:40:47 -05:00
Cameron Gutman 894c146988 Fix JAVA_HOME path on VS2022 CI image 2022-05-18 00:57:05 -05:00
Cameron Gutman 61cc9e151f Use newer AppVeyor machine image 2022-05-18 00:38:47 -05:00
Cameron Gutman cfe4c9ff21 Target Android 12L 2022-05-17 17:16:28 -05:00
Cameron Gutman d4bd29b320 Properly deal with battery saver mode in capped FPS mode 2022-05-17 00:14:55 -05:00
Cameron Gutman 7f2f2056c3 Add in-app privacy policy link to comply with Google Play policies
Also added Setup Guide and Troubleshooting Guide links too.
2022-05-15 15:56:19 -05:00
Cameron Gutman 4dd3b2cfb7 Tweak capped FPS option text 2022-05-14 23:33:43 -05:00
Cameron Gutman 2e62ad0f00 Merge remote-tracking branch 'origin/weblate' 2022-05-14 23:31:51 -05:00
Cameron Gutman 41ef292b82 Fix frame rate cap not taking effect with the unlock FPS option enabled 2022-05-14 21:19:51 -05:00
Cameron Gutman aa60671c88 Return the selected refresh rate now that the capped FPS mode is not default 2022-05-14 20:53:42 -05:00
Cameron Gutman f1ccba39e8 Don't raise refresh rate above stream FPS except in min latency mode 2022-05-14 20:53:07 -05:00
Cameron Gutman 226e580a30 Prevent microstutter in balanced mode when streaming at 60 FPS on a 120 Hz display 2022-05-14 20:08:41 -05:00
Cameron Gutman 6f8e719200 Update AGP 2022-05-14 18:25:48 -05:00
Cameron Gutman c127af1e05 Rewrite polling logic to avoid needing to poll using a separate socket first 2022-05-14 18:14:37 -05:00
Wen-haur Chiu 648904cc69 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (211 of 211 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-05-11 19:13:59 +02:00
Cameron Gutman dc85ddb3f9 Reintroduce option of using old frame pacing algorithm using capped FPS 2022-05-08 15:20:08 -05:00
Cameron Gutman 23a7d8555f Avoid activity restarts in StreamSettings and AddComputerManually
We would ideally save and restore state, but this is fine for these specific
transient user activities.

Fixes #1052
Fixes #1055
2022-05-08 14:55:47 -05:00
Cameron Gutman bc9e250d34 Merge remote-tracking branch 'origin/weblate' 2022-05-08 14:40:07 -05:00
Cameron Gutman 2203186527 Remove extra ViewGroup between OSC and StreamView
This allows touch events to be properly split
2022-05-08 14:39:32 -05:00
DankXylese 53d3d9ecb8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2022-04-28 21:13:07 +02:00
Cameron Gutman de549f67a1 Update README 2022-04-05 19:51:44 -05:00
Jorys Paulin 755c41481a Translated using Weblate (French)
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2022-04-04 10:12:11 +02:00
Dominik Chrástecký aebc2126bc Added translation using Weblate (Czech) 2022-04-03 19:50:26 +02:00
Wen-haur Chiu f43547fb31 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-03-25 18:11:43 +01:00
CorteX 398e4df7cf Translated using Weblate (Chinese (Simplified))
Currently translated at 98.0% (206 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2022-03-23 06:58:35 +01:00
reloxx13 ff68efc3f5 Translated using Weblate (German)
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2022-03-21 09:59:13 +01:00
Caio Gabriel 8ba2f51bda Translated using Weblate (Portuguese)
Currently translated at 9.0% (19 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt/
2022-03-19 22:58:22 +01:00
Caio Gabriel 87b79b278b Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt_BR/
2022-03-19 22:58:21 +01:00
Caio Gabriel 121e3ea9be Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt_BR/
2022-03-18 16:45:57 +01:00
Caio Gabriel ec6ed79ee1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt_BR/
2022-03-18 03:47:44 +01:00
Caio Gabriel ca125826a7 Translated using Weblate (Portuguese)
Currently translated at 8.5% (18 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt/
2022-03-17 22:58:19 +01:00
Cameron Gutman dd0aecf108 Update BouncyCastle 2022-03-15 22:16:41 -05:00
Wen-haur Chiu ef5cb2f0cd Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-03-09 15:58:49 +01:00
Cameron Gutman e5a7bb40e9 Version 10.0 2022-03-08 19:29:48 -06:00
Cameron Gutman bfdda48fee Merge remote-tracking branch 'origin/weblate' 2022-03-05 17:22:58 -06:00
Cameron Gutman ebea1bb5c1 Update AGP 2022-03-05 17:21:41 -06:00
bruh 14bc1552fc Translated using Weblate (Vietnamese)
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/vi/
2022-03-03 11:56:18 +01:00
Emanuele Conti a5b80d3944 Translated using Weblate (Italian)
Currently translated at 100.0% (210 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-03-03 11:56:18 +01:00
Emanuele Conti 75d0eedc2b Translated using Weblate (Italian)
Currently translated at 90.9% (191 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-02-23 16:58:16 +01:00
Benjamín Bustos 29ac7028fa Translated using Weblate (Spanish)
Currently translated at 56.1% (118 of 210 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/es/
2022-02-23 16:58:15 +01:00
Cameron Gutman 8a63b61495 Avoid touchscreens when looking for pointer capture capable devices 2022-02-18 17:07:23 -06:00
Cameron Gutman eb9e6443e2 Display frame pacing mode in crash logs 2022-02-18 17:00:21 -06:00
Cameron Gutman 362c466a16 Reintroduce never drop frames option 2022-02-18 16:04:49 -06:00
Cameron Gutman 5dac42646b Merge remote-tracking branch 'origin/weblate' 2022-02-17 23:48:52 -06:00
Cameron Gutman c25faf6426 Replace frame pacing hack with Choreographer-based rendering
This mimics the frame pacing logic now present in the iOS client.
2022-02-17 23:48:02 -06:00
Wen-haur Chiu 81df1245b4 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (205 of 205 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-02-16 14:57:48 +01:00
Emanuele Conti 2bf4d92185 Translated using Weblate (Italian)
Currently translated at 72.6% (149 of 205 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-02-16 14:57:48 +01:00
Wen-haur Chiu ae6073fe80 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (205 of 205 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-02-14 12:55:53 +01:00
Wen-haur Chiu d0463da2a1 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (205 of 205 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-02-13 05:52:36 +01:00
Cameron Gutman c0f8001627 Ignore relative mouse inputs from non-mouse tools
Apparently this can happen for the SPen on Android 12
2022-02-12 19:50:59 -06:00
Cameron Gutman f39bf61b04 Try to wake the host PC when connecting via the ShortcutTrampoline
Fixes #1024
2022-02-12 18:35:12 -06:00
Cameron Gutman 9c8237dab0 Add Greek language option 2022-02-12 17:52:31 -06:00
Cameron Gutman b88251fa79 Fix translation-related Lint warnings/errors 2022-02-12 17:44:09 -06:00
Cameron Gutman 208855917e Move existing translated arrays.xml strings to strings.xml 2022-02-12 17:39:00 -06:00
Cameron Gutman 34bdf450e9 Merge remote-tracking branch 'origin/weblate' 2022-02-12 17:21:49 -06:00
Cameron Gutman 998fa1f4e9 Move translatable array strings into strings.xml for Weblate support 2022-02-12 17:20:56 -06:00
人工知能 5c80f7d58c Update arrays.xml (#1042)
fix translations
2022-02-12 14:37:54 -06:00
Cameron Gutman 7552181e24 Plumb setHdrMode callback into MediaCodecDecoderRenderer 2022-02-12 14:31:25 -06:00
Cameron Gutman 4b2e26050e Only enable pointer capture if a compatible input device is connected 2022-02-12 14:21:19 -06:00
Cameron Gutman 530b48de71 Move recapture on focus gain logic to InputCaptureProvider 2022-02-12 13:58:55 -06:00
Emanuele Conti f4721901f8 Translated using Weblate (Italian)
Currently translated at 76.1% (144 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/it/
2022-02-08 18:54:38 +01:00
Cameron Gutman 8b692269c1 Remove per-app HDR support check
It doesn't seem to make a difference anymore whether it's supported or not.
GFE seems happy to enter HDR mode anyway.
2022-02-07 20:23:11 -06:00
Cameron Gutman 079eca7b4d Update AGP and Gradle 2022-02-06 22:18:24 -06:00
Wh1t3st4r fee40cdbe2 Translated using Weblate (Portuguese)
Currently translated at 7.9% (15 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/pt/
2022-02-01 17:52:56 +01:00
Wh1t3st4r 66920bb4cb Added translation using Weblate (Portuguese) 2022-01-31 17:10:49 +01:00
Wh1t3st4r fdbf810aa2 Added translation using Weblate (Portuguese (Brazil)) 2022-01-31 16:08:38 +01:00
GeraltOfTrivia 08bfc1de4a Translated using Weblate (Greek)
Currently translated at 98.9% (187 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/el/
2022-01-25 18:56:12 +01:00
GeraltOfTrivia 76149328fe Added translation using Weblate (Greek) 2022-01-24 17:51:06 +01:00
Wout Rombouts 285f33f3f1 Translated using Weblate (Dutch)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nl/
2022-01-19 12:55:54 +01:00
Wen-haur Chiu b17c1b7588 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2022-01-13 16:54:04 +01:00
Wen-haur Chiu 5b25c90db8 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-12-28 10:52:10 +01:00
Wen-haur Chiu 931a0a5168 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-12-27 10:16:59 +01:00
Cameron Gutman f6a46438bd Merge remote-tracking branch 'origin/weblate' 2021-12-15 20:56:10 -06:00
Cameron Gutman 4a60ec1755 Fix excessive high-res scroll speed on newer GFE versions 2021-12-14 22:02:12 -06:00
Cameron Gutman ec222413dd Update NDK and AGP 2021-12-14 21:48:44 -06:00
Wen-haur Chiu 5a28239813 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-12-13 09:53:46 +01:00
Cameron Gutman da45cba2ff Send fractional scroll events properly 2021-12-08 22:11:44 -06:00
Cameron Gutman 54bc34496a Merge remote-tracking branch 'origin/weblate' 2021-10-06 21:18:00 -05:00
Zero O 294910ac84 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-09-14 03:39:29 +02:00
Mert 71d2c6a5d5 Translated using Weblate (Turkish)
Currently translated at 21.1% (40 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/tr/
2021-08-24 21:34:36 +02:00
Cameron Gutman 79bf17fe24 Add fastlane metadata for v9.10.1 2021-08-21 15:25:45 -05:00
Cameron Gutman 31f66031bc Version 9.10.1 2021-08-21 15:22:05 -05:00
Cameron Gutman d3f2284791 Update NDK to r23 2021-08-18 00:33:57 -05:00
Cameron Gutman ec647608c4 Allow state loss when committing SettingsFragment 2021-08-18 00:24:30 -05:00
Cameron Gutman 597582ddd8 Add workaround for NPE in getNetworkInterfaces() 2021-08-18 00:04:34 -05:00
Cameron Gutman c6d9889182 Fix lint results path for Gradle 7.0 2021-08-10 02:12:03 -05:00
Cameron Gutman 7c58234174 Use JDK 11 for Gradle 7.0 2021-08-10 02:02:24 -05:00
Cameron Gutman ae9282b0af Plumb UTF-8 text support through to NvConnection 2021-08-10 00:14:13 -05:00
Cameron Gutman 310ba646fc Update Gradle 2021-08-09 23:24:44 -05:00
LiuAnnan d479908939 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2021-07-30 13:33:24 +02:00
Nikita Epifanov 5cd5d68d22 Translated using Weblate (Russian)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2021-07-23 10:32:56 +02:00
Cameron Gutman 3e0bf25acb Update moonlight-common-c 2021-07-17 14:16:40 -05:00
Cameron Gutman f3d277c94a Update Maven dependencies 2021-07-17 14:01:59 -05:00
Cameron Gutman 04545ecbb0 Avoid tons of redundant calls to InputEvent.getSource() 2021-07-17 14:01:12 -05:00
Cameron Gutman 5350651d6f Fix crash when using USB driver on Android 12 2021-07-17 13:59:11 -05:00
Cameron Gutman f2e2e28419 Fix NPE if we receive a SOURCE_CLASS_POSITION event with no associated device 2021-07-17 13:15:57 -05:00
Cameron Gutman b9031785ac Fix crash if maxShortcutCountPerActivity is zero 2021-07-17 13:08:25 -05:00
Cameron Gutman 91a72474a1 Version 9.10 r2 2021-07-16 21:01:16 -05:00
Cameron Gutman b6e7c425c6 Fix input from SOURCE_TRACKPAD devices 2021-07-16 20:44:01 -05:00
Cameron Gutman 834ace4566 Add SoC details and performance class to exception data 2021-07-16 20:00:03 -05:00
Cameron Gutman 54af70005d Fix spurious gamepad removal when entering PiP with PS4 controller on Android 12
The relative mouse axes AXIS_RELATIVE_X/Y are added/removed when gaining/losing input focus
2021-07-16 19:51:14 -05:00
Cameron Gutman f2bf168925 Fix possible rumble crash if only the lower motor byte is non-zero 2021-07-16 19:25:10 -05:00
Cameron Gutman 27ffbd8dec Version 9.10 2021-07-16 19:23:37 -05:00
Cameron Gutman eaa82592fe Merge remote-tracking branch 'origin/weblate' 2021-07-15 19:59:07 -05:00
Cameron Gutman 73784585a8 Fix new Android 12 rumble code based on real hardware testing
Independent rumble motor controller tested working on:
- DualShock 4 (USB and BT)
- DualShock 3 (USB)
- Xbox Series X (USB)
2021-07-15 19:51:08 -05:00
Cameron Gutman 262d562dd9 Implement enhanced rumble support for Android 12 devices
This allows independent control of large and small motors which
was not possible with the old single Vibrator API.

Currently untested on real hardware.
2021-07-14 20:18:35 -05:00
Cameron Gutman ab4f904dc9 Target Android 12 2021-07-14 20:04:46 -05:00
Cameron Gutman fc4fdd5ee2 Implement seamless PiP entry on Android 12 2021-07-14 20:00:53 -05:00
Cameron Gutman 41c5b62b1a Update AGP to 4.2.2 2021-07-14 19:58:12 -05:00
Cameron Gutman 239cb0435c Add new backup rules for Android 12 2021-07-14 19:58:01 -05:00
bruh c6ccc7a6e2 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/vi/
2021-07-05 18:33:43 +02:00
Cameron Gutman 6cedb9019c Pass RTSP session URL to moonlight-common-c for dynamic ports 2021-07-02 17:41:07 -05:00
Furkan 8bc64f0438 Translated using Weblate (Turkish)
Currently translated at 19.0% (36 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/tr/
2021-07-02 18:33:32 +02:00
WALKTHROUGH RAYMAND LEGENDS 89e6e39e58 Translated using Weblate (Hungarian)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/hu/
2021-07-02 18:33:31 +02:00
Furkan 645761f677 Added translation using Weblate (Turkish) 2021-07-01 17:53:08 +02:00
DankXylese 0fc60f7855 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/uk/
2021-06-30 13:33:24 +02:00
LUTEN VR ce38460d87 Translated using Weblate (Korean)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2021-06-28 03:36:01 +02:00
Jorys Paulin de8e759d3a Translated using Weblate (French)
Currently translated at 100.0% (189 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2021-06-28 03:36:00 +02:00
Cameron Gutman 06f6134538 Version 9.9.6 2021-06-25 00:53:28 -05:00
Cameron Gutman ac352b3a23 Merge remote-tracking branch 'origin/weblate' 2021-06-25 00:26:06 -05:00
Cameron Gutman 9b8e65e552 Add cutout resolution options on Android 9 2021-06-25 00:24:26 -05:00
Cameron Gutman 35999a05f0 Minor code cleanup 2021-06-24 23:50:15 -05:00
Cameron Gutman 86ee30e9b4 Don't process drags for the non-primary finger 2021-06-24 23:19:06 -05:00
Allan Nordhøy a81c4a1e23 Translated using Weblate (Norwegian Bokmål)
Currently translated at 88.8% (168 of 189 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-06-24 07:32:33 +02:00
Cameron Gutman 394ce458a0 Add additional native resolution options on Android 10+ with display insets included
Fixes #956
Fixes #986
2021-06-22 23:56:45 -05:00
Cameron Gutman f187e57899 Fix FPS display on stats overlay 2021-06-22 23:43:10 -05:00
Cameron Gutman a15335872d Update moonlight-common-c to fix audio problems on old GFE and Sunshine versions 2021-06-22 22:12:32 -05:00
Cameron Gutman beb77b4dab Add Hungarian language option 2021-06-22 21:58:45 -05:00
Cameron Gutman aa80d8cd0a Change H.265 to HEVC 2021-06-22 21:53:15 -05:00
Cameron Gutman 77d197f14e Merge remote-tracking branch 'origin/weblate' 2021-06-22 21:50:57 -05:00
WALKTHROUGH RAYMAND LEGENDS f98fbb778c Translated using Weblate (Hungarian)
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/hu/
2021-06-15 14:32:25 +02:00
Cameron Gutman c46a0106f2 Version 9.9.5 2021-06-14 23:34:16 -05:00
WALKTHROUGH RAYMAND LEGENDS cbf3db0be0 Added translation using Weblate (Hungarian) 2021-06-13 21:33:00 +02:00
Cameron Gutman 21f3710083 Update moonlight-common-c with performance and audio improvements 2021-06-13 10:18:32 -05:00
Cameron Gutman 8ac5768f4f Change H.265 to HEVC to match other clients 2021-06-12 11:00:30 -05:00
Cameron Gutman 2458b9305c Merge remote-tracking branch 'origin/weblate' 2021-06-12 10:54:07 -05:00
Artem a8909ea2a5 Translated using Weblate (Russian)
Currently translated at 99.4% (187 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2021-06-11 22:32:00 +02:00
Cameron Gutman ac7c35c6c2 Version 9.9.4 2021-06-03 21:51:21 -05:00
Cameron Gutman e4631b5a85 Update moonlight-common-c with audio FEC support 2021-06-03 21:23:55 -05:00
Cameron Gutman e1c50b5dc5 Merge remote-tracking branch 'origin/weblate' 2021-06-03 21:20:56 -05:00
Zero O c6c5a5cd12 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-06-02 05:33:02 +02:00
Zero O bd4854a607 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2021-06-02 05:33:01 +02:00
LUTEN VR cd0181e6f4 Translated using Weblate (Korean)
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2021-05-29 13:33:23 +02:00
bruh 287b1d2b4d Translated using Weblate (Vietnamese)
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/vi/
2021-05-28 08:32:48 +02:00
LUTEN VR 10c61bb0a7 Translated using Weblate (Korean)
Currently translated at 100.0% (188 of 188 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2021-05-24 02:42:49 +02:00
Cameron Gutman 92215ac34f Version 9.9.3.1 for Amazon 2021-05-22 14:40:25 -05:00
Cameron Gutman f64d50d8c8 Hide the help button on Fire TV
The last reviewer complained that the GitHub wiki was not
entirely navigable via the Fire TV remote.
2021-05-22 14:36:25 -05:00
Cameron Gutman b74e0ce48f Remove receive time from performance overlay
It is superseded by network latency
2021-05-22 14:08:46 -05:00
Cameron Gutman 27cb0029a8 Merge remote-tracking branch 'origin/weblate' 2021-05-22 14:07:37 -05:00
LUTEN VR ce6f193f06 Translated using Weblate (Korean)
Currently translated at 80.5% (153 of 190 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ko/
2021-05-21 20:33:05 +02:00
Cameron Gutman a862ffdde4 Version 9.9.3 2021-05-16 20:49:28 -05:00
Cameron Gutman 3f1cd8a118 Use HEVC at 4K on Qualcomm since RFI is temporarily disabled 2021-05-16 20:39:58 -05:00
Cameron Gutman bb4b5838e3 Enable HEVC on Realtek SoCs 2021-05-16 20:39:00 -05:00
Cameron Gutman ea98d64184 Consolidate performance overlay lines to reduce wasted space 2021-05-16 20:20:36 -05:00
Cameron Gutman 98f3c56da5 Remove duplicate Japanese language entry 2021-05-16 20:15:45 -05:00
Cameron Gutman 20b7619380 Update moonlight-common-c to avoid excessive ENet retransmissions when RTT variance is 0 2021-05-16 15:41:44 -05:00
Cameron Gutman 7b1c3f05c7 Update moonlight-common-c with with more accurate RTTs and minRequiredFecPackets 2021-05-16 14:52:23 -05:00
Cameron Gutman 9166998442 Fix casts of RTT info 2021-05-15 17:07:08 -05:00
Cameron Gutman e1f6b577bf Switch to Maven Central repositories 2021-05-15 16:56:58 -05:00
Cameron Gutman ba0d08b2a6 Update AGP 2021-05-15 16:56:32 -05:00
Cameron Gutman e79c12a038 Add network latency to performance overlay 2021-05-15 16:56:19 -05:00
Cameron Gutman 2ca5182a28 Convert the big perf text block into strings for each line 2021-05-15 16:45:38 -05:00
Cameron Gutman 205e627209 Integrate Japanese and Vietnamese translations 2021-05-13 00:36:30 -05:00
Cameron Gutman 425d4f3f63 Merge remote-tracking branch 'origin/weblate' 2021-05-13 00:27:22 -05:00
bruh d69843e122 Translated using Weblate (Vietnamese)
Currently translated at 100.0% (182 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/vi/
2021-05-13 07:05:19 +02:00
bruh d2586d3b59 Added translation using Weblate (Vietnamese) 2021-05-11 16:12:48 +02:00
Cameron Gutman edab84c89b Bump version again 2021-05-06 22:26:40 -05:00
Cameron Gutman dd08754f1f Actually update moonlight-common-c for 4K RFI workaround 2021-05-06 22:26:07 -05:00
Cameron Gutman 2cdfe85091 Version 9.9.2 2021-05-06 22:21:36 -05:00
Cameron Gutman a11acef36f Update moonlight-common-c with 4K RFI and audio latency fix 2021-05-06 22:18:19 -05:00
Cameron Gutman 1e34dbf616 Don't add native resolutions on TVs 2021-05-06 20:45:02 -05:00
Cameron Gutman b3d4763ef6 Fix native screen resolution on devices running Lollipop and earlier
Fixes #967
2021-05-06 20:31:06 -05:00
Cameron Gutman fe630e9383 Merge remote-tracking branch 'origin/weblate' 2021-05-06 17:27:10 -05:00
Cameron Gutman 826a20785f Create debug symbols for our native libraries for Google Play 2021-05-05 20:29:40 -05:00
Cameron Gutman 75932d7621 Update Gradle 2021-05-05 20:29:15 -05:00
Zero O 62d095af4f Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (182 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hant/
2021-05-01 04:32:16 +02:00
Zero O 1594735aa0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (182 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2021-05-01 04:32:16 +02:00
Cameron Gutman cbd0bdf9fc Version 9.9.1 2021-04-29 18:32:08 -05:00
Cameron Gutman d3e8e8fb9c Update moonlight-common-c with RTSP handshake retry logic 2021-04-29 18:23:41 -05:00
Cameron Gutman 66406c5a48 Version 9.9 2021-04-27 18:20:00 -05:00
Cameron Gutman 753c600dd2 Merge remote-tracking branch 'origin/weblate' 2021-04-27 17:46:37 -05:00
Cameron Gutman b28b1df348 Update moonlight-common-c with multi-FEC and audio latency fixes 2021-04-27 17:44:14 -05:00
Cameron Gutman b94649162e Allow compatibility aliases to match preferred decoders 2021-04-27 17:43:19 -05:00
Cameron Gutman ee50e19dbd Fix use of Android 11 low latency decoding feature 2021-04-27 17:43:04 -05:00
Cameron Gutman cc23f8b831 Revert vt-low-latency option
Fixes #973
2021-04-26 19:10:07 -05:00
Cameron Gutman bac7b68bb1 One more attempt to fix exception parsing 2021-04-26 19:07:54 -05:00
Nikita Epifanov f9a622c89b Translated using Weblate (Russian)
Currently translated at 100.0% (182 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2021-04-26 13:32:09 +02:00
Cameron Gutman c321dc5e81 Version 9.8.7 2021-04-23 19:48:17 -05:00
Cameron Gutman 72f37c9df4 Enable audio stream encryption 2021-04-23 19:38:24 -05:00
Cameron Gutman 544eac0c8a Attempt to prevent possible error parsing exception string 2021-04-23 19:12:41 -05:00
Cameron Gutman 823593ddae Revert "Avoid Amlogic HEVC decoders until the latency issue is understood"
This reverts commit 3600e704c4.
2021-04-19 23:08:20 -05:00
Cameron Gutman 3600e704c4 Avoid Amlogic HEVC decoders until the latency issue is understood 2021-04-19 22:46:55 -05:00
Cameron Gutman 0c79d756a4 Add more specific problem text to the decoder exceptions 2021-04-19 22:44:17 -05:00
Cameron Gutman eb531a7a88 Fix OpenSSL build script and rebuild 2021-04-18 21:47:06 -05:00
Cameron Gutman d6634d30dc Update moonlight-common-c 2021-04-18 19:21:06 -05:00
Cameron Gutman f87806b1b4 Update to OpenSSL 1.1.1k without no-asm 2021-04-18 18:23:56 -05:00
Cameron Gutman 2a5afeb5ff Don't use HEVC on Fire TV 3 2021-04-18 14:42:52 -05:00
Cameron Gutman fc5495f1ec Add vendor low latency option for Exynos 2021-04-18 14:17:26 -05:00
Cameron Gutman 699cc361a2 Add additional vendor-specific low latency options for Qualcomm and HiSilicon SoCs 2021-04-18 12:49:25 -05:00
shower 31bf4f10c0 Translated using Weblate (Chinese (Simplified))
Currently translated at 93.9% (171 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/zh_Hans/
2021-04-17 13:27:02 +02:00
Cameron Gutman fe704af62f Version 9.8.6 2021-04-09 19:35:02 -05:00
Cameron Gutman e74517543d Update common-c for initial GFE 3.22 compatibility 2021-04-09 19:32:39 -05:00
Nikita Epifanov 44acf19742 Translated using Weblate (Russian)
Currently translated at 97.8% (178 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2021-04-08 11:26:58 +02:00
Jorys Paulin bf20aa253e Translated using Weblate (French)
Currently translated at 100.0% (182 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2021-04-05 03:40:29 +02:00
Cameron Gutman 81c815840d Version 9.8.5 2021-04-03 12:39:02 -05:00
Cameron Gutman e9cd63dc5f Removed deprecated ProGuard option 2021-04-03 12:00:53 -05:00
Cameron Gutman 1ae8f67d93 Add Norwegian Bokmål option to the language list 2021-04-03 11:59:57 -05:00
Cameron Gutman daa1e10333 Merge remote-tracking branch 'origin/weblate' 2021-04-03 11:47:27 -05:00
Cameron Gutman a8a356e703 Add Amazon Luna support in Xbox 360 driver 2021-04-03 11:45:02 -05:00
Rener kaka ca440cc5dd Added translation using Weblate (Kurdish (Central)) 2021-04-02 21:11:43 +02:00
Øyvind Heddeland Instefjord 95a9fb4f62 Translated using Weblate (Norwegian Bokmål)
Currently translated at 90.1% (164 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-04-01 17:26:57 +02:00
Cameron Gutman 7db9e27112 Update NDK to r22b 2021-03-31 20:07:08 -05:00
Cameron Gutman 03bcdbe3f7 Update moonlight-common-c to pick up AMF HEVC parsing fix 2021-03-31 20:06:53 -05:00
Cameron Gutman f0762a6213 Version 9.8.4 2021-03-21 21:51:54 -05:00
Allan Nordhøy 67fbc6b3ad Translated using Weblate (Norwegian Bokmål)
Currently translated at 88.4% (161 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-03-21 10:37:10 +01:00
Jorys Paulin d9662d7396 Translated using Weblate (French)
Currently translated at 95.6% (174 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/fr/
2021-03-21 10:37:10 +01:00
Nedelcu Constantin Marius Nedelcu 5ccbbf259d Translated using Weblate (Norwegian Bokmål)
Currently translated at 87.3% (159 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-03-21 06:29:37 +01:00
Allan Nordhøy 179c2f8723 Translated using Weblate (Norwegian Bokmål)
Currently translated at 87.3% (159 of 182 strings)

Translation: Moonlight Game Streaming/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-03-21 06:29:36 +01:00
Allan Nordhøy c76e0a40a7 Translated using Weblate (Norwegian Bokmål)
Currently translated at 59.3% (108 of 182 strings)

Translation: moonlight/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/nb_NO/
2021-03-21 02:34:36 +01:00
Artem 03407e528f Translated using Weblate (Russian)
Currently translated at 94.5% (172 of 182 strings)

Translation: moonlight/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/ru/
2021-03-21 02:34:36 +01:00
reloxx13 0c41d742cf Translated using Weblate (German)
Currently translated at 100.0% (182 of 182 strings)

Translation: moonlight/moonlight-android
Translate-URL: https://hosted.weblate.org/projects/moonlight/moonlight-android/de/
2021-03-21 02:34:36 +01:00
Allan Nordhøy ed2f471a4e Added translation using Weblate (Norwegian Bokmål) 2021-03-21 02:34:36 +01:00
Cameron Gutman 04efec101e Sync Xbox driver VIDs with Linux 5.11 2021-03-20 18:49:34 -05:00
Cameron Gutman a6c69012cc Add Weblate link and badge 2021-03-20 18:15:40 -05:00
Cameron Gutman 0045c54d8e Reapply a portion of 1d3e42f that should not have been reverted 2021-03-20 11:11:12 -05:00
Cameron Gutman 45436c006f Cancel a pending drag timer before setting a new one 2021-03-20 11:04:34 -05:00
Cameron Gutman cc183c0da8 Cancel a pending timer before setting a new one 2021-03-20 10:59:47 -05:00
Cameron Gutman 523f1df98b Remove superfluous simulated shift key up/down events
Setting the shift modifier flag alone is sufficient for current GFE versions
2021-03-20 10:38:15 -05:00
Cameron Gutman 5843dff278 Apply new fix for #840 2021-03-20 10:24:06 -05:00
Cameron Gutman 7f24f47978 Revert "Use a global set of modifier flags rather than per-device flags"
This reverts commit 1d3e42f92e.
2021-03-20 10:08:58 -05:00
Cameron Gutman b1f9fd459e Update NDK to r22 2021-03-20 10:07:08 -05:00
Cameron Gutman 48988eb785 Update AGP to 4.1.3 2021-03-20 10:06:51 -05:00
Cameron Gutman 0045a885b9 Migrate to AppVeyor 2021-03-03 19:56:20 -06:00
Cameron Gutman 0b57f60454 Migrate from travis-ci.org to travis-ci.com 2021-03-03 01:54:20 -06:00
Cameron Gutman f0857c7da2 Add issue template 2021-03-03 01:41:13 -06:00
Cameron Gutman 15faa2e841 Version 9.8.3 2021-03-02 18:48:12 -06:00
Cameron Gutman da103f7197 Don't use our built-in Switch Pro mapping on Android 10+ 2021-02-28 16:35:17 -06:00
Cameron Gutman 1d3e42f92e Use a global set of modifier flags rather than per-device flags
Fixes #840
2021-02-28 11:26:35 -06:00
Cameron Gutman 20ced841dd Handle pointer capture on SOURCE_TOUCHPAD devices 2021-02-27 15:48:37 -06:00
Cameron Gutman 54ebd0a796 Fix streaming in the Android 12 emulator 2021-02-27 15:46:59 -06:00
Cameron Gutman e636a7171b Add explicit android:exported value for Android 12 2021-02-27 15:46:23 -06:00
Cameron Gutman e8f847065b Version 9.8.2 2021-01-31 21:08:12 -06:00
Cameron Gutman 1c806bb572 Only use the virtual device as a gamepad if at least one gamepad is present 2021-01-31 19:42:41 -06:00
Cameron Gutman 963133598f Add hack to work around https://issuetracker.google.com/issues/163120692 2021-01-31 19:29:57 -06:00
Cameron Gutman fedaa74c47 Update AGP to 4.1.2 2021-01-31 19:28:42 -06:00
Cameron Gutman e322baf1d7 Version 9.8.1 2021-01-09 19:42:45 -06:00
Cameron Gutman 173a07cb59 Update ENet 2021-01-09 19:25:21 -06:00
Cameron Gutman 364afff860 Allow display resolution adjustment when streaming at a native resolution 2021-01-09 19:24:21 -06:00
Cameron Gutman 1b59e61b8e Include PC name in the PC context menu header 2020-12-31 16:42:26 -06:00
Cameron Gutman b1f453f7ba Charge time spent in the decode unit queue to the decoder rather than receive time 2020-12-31 16:35:49 -06:00
Cameron Gutman 175e842feb Support multiple native resolution options 2020-12-30 16:29:07 -06:00
213 changed files with 7647 additions and 2364 deletions
+48
View File
@@ -0,0 +1,48 @@
---
name: Bug report
about: Follow the troubleshooting guide before reporting a bug
---
**READ ME FIRST!**
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
**Describe the bug**
A clear and concise description of what the bug is.
**Steps to reproduce**
Any special steps that are required for the bug to appear.
**Screenshots**
If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
**Affected games**
List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
**Other Moonlight clients**
- Does the issue occur when using Moonlight on PC or iOS?
**Moonlight settings (please complete the following information)**
- Have any settings been adjusted from defaults?
- If so, which settings have been changed?
- Does the problem still occur after reverting settings back to default?
**Gamepad-related issues (please complete if problem is gamepad-related)**
- Do you have any gamepads connected to your host PC directly?
- If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
- Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
- Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
**Device details (please complete the following information)**
- Android version: [e.g. Android 10]
- Device model: [e.g. Samsung Galaxy S21]
**Server PC details (please complete the following information)**
- OS: [e.g. Windows 10 1809]
- GeForce Experience version: [e.g. 3.16.0.140]
- Nvidia GPU driver: [e.g. 417.35]
- Antivirus and firewall software: [e.g. Windows Defender and Windows Firewall]
**Additional context**
Anything else you think may be relevant to the issue or special about your specific setup.
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: false
+17
View File
@@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
-18
View File
@@ -1,18 +0,0 @@
language: android
dist: trusty
git:
depth: 1
android:
components:
- tools
- platform-tools
- build-tools-30.0.0
- android-30
before_install:
- sdkmanager --list
install:
- yes | sdkmanager "ndk;21.0.6113669"
+4 -3
View File
@@ -1,15 +1,16 @@
# Moonlight Android
[![Travis CI Status](https://travis-ci.org/moonlight-stream/moonlight-android.svg?branch=master)](https://travis-ci.org/moonlight-stream/moonlight-android)
[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/232a8tadrrn8jv0k/branch/master?svg=true)](https://ci.appveyor.com/project/cgutman/moonlight-android/branch/master)
[![Translation Status](https://hosted.weblate.org/widgets/moonlight/-/moonlight-android/svg-badge.svg)](https://hosted.weblate.org/projects/moonlight/moonlight-android/)
[Moonlight for Android](https://moonlight-stream.org) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
[Moonlight for Android](https://moonlight-stream.org) is an open source client for NVIDIA GameStream, as used by the NVIDIA Shield.
Moonlight for Android will allow you to stream your full collection of games from your Windows PC to your Android device,
whether in your own home or over the internet.
Moonlight also has a [PC client](https://github.com/moonlight-stream/moonlight-qt) and [iOS/tvOS client](https://github.com/moonlight-stream/moonlight-ios).
Check out [the Moonlight wiki](https://github.com/moonlight-stream/moonlight-docs/wiki) for more detailed project information, setup guide, or troubleshooting steps.
You can follow development on our [Discord server](https://moonlight-stream.org/discord) and help translate Moonlight into your language on [Weblate](https://hosted.weblate.org/projects/moonlight/moonlight-android/).
## Downloads
* [Google Play Store](https://play.google.com/store/apps/details?id=com.limelight)
+26 -15
View File
@@ -1,23 +1,28 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
ndkVersion "23.2.8568313"
compileSdk 33
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
minSdk 16
targetSdk 33
versionName "9.8"
versionCode = 251
versionName "10.7"
versionCode = 286
// 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 {
@@ -27,6 +32,7 @@ android {
applicationId "com.limelight.root"
dimension "root"
buildConfigField "boolean", "ROOT_BUILD", "true"
}
nonRoot {
@@ -38,12 +44,13 @@ android {
applicationId "com.limelight"
dimension "root"
buildConfigField "boolean", "ROOT_BUILD", "false"
}
}
lintOptions {
lint {
disable 'MissingTranslation'
lintConfig file("lint.xml")
lintConfig file('lint.xml')
}
bundle {
@@ -53,7 +60,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
@@ -63,9 +70,10 @@ android {
buildTypes {
debug {
applicationIdSuffix ".debug"
resValue "string", "app_label", "Moonlight (Debug)"
resValue "string", "app_label_root", "Moonlight (Root Debug)"
minifyEnabled true
useProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
@@ -100,6 +108,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'
@@ -114,10 +124,11 @@ android {
}
dependencies {
implementation 'org.bouncycastle:bcprov-jdk15on:1.66'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.66'
implementation 'org.bouncycastle:bcprov-jdk15on:1.70'
implementation 'org.bouncycastle:bcpkix-jdk15on:1.70'
implementation 'org.jcodec:jcodec:0.2.3'
implementation 'com.squareup.okhttp3:okhttp:3.12.12'
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
implementation 'com.squareup.okio:okio:1.17.5'
implementation 'org.jmdns:jmdns:3.5.5'
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>
+14 -1
View File
@@ -35,6 +35,7 @@
<application
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/backup_rules_s"
android:networkSecurityConfig="@xml/network_security_config"
android:isGame="true"
android:banner="@drawable/atv_banner"
@@ -43,27 +44,37 @@
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+ -->
<activity
android:name=".PcView"
android:exported="true"
android:resizeableActivity="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
<intent-filter>
@@ -97,6 +108,7 @@
<activity
android:name=".preferences.StreamSettings"
android:resizeableActivity="true"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:label="Streaming Settings">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
@@ -106,6 +118,7 @@
android:name=".preferences.AddComputerManually"
android:resizeableActivity="true"
android:windowSoftInputMode="stateVisible"
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
android:label="Add Computer Manually">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
@@ -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);
+358 -154
View File
@@ -2,6 +2,7 @@ package com.limelight;
import com.limelight.binding.PlatformBinding;
import com.limelight.binding.audio.AndroidAudioRenderer;
import com.limelight.binding.input.ControllerHandler;
import com.limelight.binding.input.KeyboardTranslator;
import com.limelight.binding.input.capture.InputCaptureManager;
@@ -58,7 +59,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Rational;
import android.view.Display;
import android.view.InputDevice;
@@ -78,7 +78,8 @@ import android.widget.TextView;
import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -88,7 +89,7 @@ import java.util.Locale;
public class Game extends Activity implements SurfaceHolder.Callback,
OnGenericMotionListener, OnTouchListener, NvConnectionListener, EvdevListener,
OnSystemUiVisibilityChangeListener, GameGestures, StreamView.InputCallbacks,
PerfOverlayListener
PerfOverlayListener, UsbDriverService.UsbDriverStateListener
{
private int lastButtonState = 0;
@@ -108,6 +109,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private static final int THREE_FINGER_TAP_THRESHOLD = 300;
private ControllerHandler controllerHandler;
private KeyboardTranslator keyboardTranslator;
private VirtualController virtualController;
private PreferenceConfiguration prefConfig;
@@ -118,8 +120,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private boolean displayedFailureDialog = false;
private boolean connecting = false;
private boolean connected = false;
private boolean autoEnterPip = false;
private boolean surfaceCreated = false;
private boolean attemptedConnection = false;
private int suppressPipRefCount = 0;
private String pcName;
private String appName;
private InputCaptureProvider inputCaptureProvider;
private int modifierFlags = 0;
@@ -150,6 +156,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
UsbDriverService.UsbDriverBinder binder = (UsbDriverService.UsbDriverBinder) iBinder;
binder.setListener(controllerHandler);
binder.setStateListener(Game.this);
binder.start();
connectedToUsbDriverService = true;
}
@@ -214,9 +222,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
prefConfig = PreferenceConfiguration.readPreferences(this);
tombstonePrefs = Game.this.getSharedPreferences("DecoderTombstone", 0);
if (prefConfig.stretchVideo) {
if (prefConfig.stretchVideo || shouldIgnoreInsetsForResolution(prefConfig.width, prefConfig.height)) {
// Allow the activity to layout under notches if the fill-screen option
// was turned on by the user
// was turned on by the user or it's a full-screen native resolution
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
getWindow().getAttributes().layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -259,23 +267,30 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Make sure Wi-Fi is fully powered up
WifiManager wifiMgr = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
highPerfWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Moonlight High Perf Lock");
highPerfWifiLock.setReferenceCounted(false);
highPerfWifiLock.acquire();
try {
highPerfWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "Moonlight High Perf Lock");
highPerfWifiLock.setReferenceCounted(false);
highPerfWifiLock.acquire();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
lowLatencyWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY, "Moonlight Low Latency Lock");
lowLatencyWifiLock.setReferenceCounted(false);
lowLatencyWifiLock.acquire();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
lowLatencyWifiLock = wifiMgr.createWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY, "Moonlight Low Latency Lock");
lowLatencyWifiLock.setReferenceCounted(false);
lowLatencyWifiLock.acquire();
}
} catch (SecurityException e) {
// Some Samsung Galaxy S10+/S10e devices throw a SecurityException from
// WifiLock.acquire() even though we have android.permission.WAKE_LOCK in our manifest.
e.printStackTrace();
}
appName = Game.this.getIntent().getStringExtra(EXTRA_APP_NAME);
pcName = Game.this.getIntent().getStringExtra(EXTRA_PC_NAME);
String host = Game.this.getIntent().getStringExtra(EXTRA_HOST);
String appName = Game.this.getIntent().getStringExtra(EXTRA_APP_NAME);
int appId = Game.this.getIntent().getIntExtra(EXTRA_APP_ID, StreamConfiguration.INVALID_APP_ID);
String uniqueId = Game.this.getIntent().getStringExtra(EXTRA_UNIQUEID);
String uuid = Game.this.getIntent().getStringExtra(EXTRA_PC_UUID);
String pcName = Game.this.getIntent().getStringExtra(EXTRA_PC_NAME);
boolean willStreamHdr = Game.this.getIntent().getBooleanExtra(EXTRA_APP_HDR, false);
boolean appSupportsHdr = Game.this.getIntent().getBooleanExtra(EXTRA_APP_HDR, false);
byte[] derCertData = Game.this.getIntent().getByteArrayExtra(EXTRA_SERVER_CERT);
X509Certificate serverCert = null;
@@ -301,7 +316,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
shortcutHelper.reportComputerShortcutUsed(computer);
if (appName != null) {
// This may be null if launched from the "Resume Session" PC context menu item
shortcutHelper.reportGameLaunched(computer, new NvApp(appName, appId, willStreamHdr));
shortcutHelper.reportGameLaunched(computer, new NvApp(appName, appId, appSupportsHdr));
}
// Initialize the MediaCodec helper before creating the decoder
@@ -309,42 +324,33 @@ public class Game extends Activity implements SurfaceHolder.Callback,
MediaCodecHelper.initialize(this, glPrefs.glRenderer);
// Check if the user has enabled HDR
boolean willStreamHdr = false;
if (prefConfig.enableHdr) {
// Check if the app supports it
if (!willStreamHdr) {
Toast.makeText(this, "This game does not support HDR10", Toast.LENGTH_SHORT).show();
}
// It does, so start our HDR checklist
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// We already know the app supports HDR if willStreamHdr is set.
// Start our HDR checklist
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Display display = getWindowManager().getDefaultDisplay();
Display.HdrCapabilities hdrCaps = display.getHdrCapabilities();
// We must now ensure our display is compatible with HDR10
boolean foundHdr10 = false;
if (hdrCaps != null) {
// getHdrCapabilities() returns null on Lenovo Lenovo Mirage Solo (vega), Android 8.0
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
foundHdr10 = true;
willStreamHdr = true;
break;
}
}
}
if (!foundHdr10) {
if (!willStreamHdr) {
// Nope, no HDR for us :(
willStreamHdr = false;
Toast.makeText(this, "Display does not support HDR10", Toast.LENGTH_LONG).show();
}
}
else {
Toast.makeText(this, "HDR requires Android 7.0 or later", Toast.LENGTH_LONG).show();
willStreamHdr = false;
}
}
else {
willStreamHdr = false;
}
// Check if the user has enabled performance stats overlay
if (prefConfig.enablePerfOverlay) {
@@ -377,9 +383,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
Toast.makeText(this, "Decoder does not support HEVC Main10HDR10", Toast.LENGTH_LONG).show();
}
// Display a message to the user if H.265 was forced on but we still didn't find a decoder
// Display a message to the user if HEVC was forced on but we still didn't find a decoder
if (prefConfig.videoFormat == PreferenceConfiguration.FORCE_H265_ON && !decoderRenderer.isHevcSupported()) {
Toast.makeText(this, "No H.265 decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show();
Toast.makeText(this, "No HEVC decoder found.\nFalling back to H.264.", Toast.LENGTH_LONG).show();
}
int gamepadMask = ControllerHandler.getAttachedControllerMask(this);
@@ -398,52 +404,22 @@ public class Game extends Activity implements SurfaceHolder.Callback,
float displayRefreshRate = prepareDisplayForRendering();
LimeLog.info("Display refresh rate: "+displayRefreshRate);
// HACK: Despite many efforts to ensure low latency consistent frame
// delivery, the best non-lossy mechanism is to buffer 1 extra frame
// in the output pipeline. Android does some buffering on its end
// in SurfaceFlinger and it's difficult (impossible?) to inspect
// the precise state of the buffer queue to the screen after we
// release a frame for rendering.
//
// Since buffering a frame adds latency and we are primarily a
// latency-optimized client, rather than one designed for picture-perfect
// accuracy, we will synthetically induce a negative pressure on the display
// output pipeline by driving the decoder input pipeline under the speed
// that the display can refresh. This ensures a constant negative pressure
// to keep latency down but does induce a periodic frame loss. However, this
// periodic frame loss is *way* less than what we'd already get in Marshmallow's
// display pipeline where frames are dropped outside of our control if they land
// on the same V-sync.
//
// Hopefully, we can get rid of this once someone comes up with a better way
// to track the state of the pipeline and time frames.
// If the user requested frame pacing using a capped FPS, we will need to change our
// desired FPS setting here in accordance with the active display refresh rate.
int roundedRefreshRate = Math.round(displayRefreshRate);
int chosenFrameRate = prefConfig.fps;
if (!prefConfig.disableFrameDrop || prefConfig.unlockFps) {
if (Build.DEVICE.equals("coral") || Build.DEVICE.equals("flame")) {
// HACK: Pixel 4 (XL) ignores the preferred display mode and lowers refresh rate,
// causing frame pacing issues. See https://issuetracker.google.com/issues/143401475
// To work around this, use frame drop mode if we want to stream at >= 60 FPS.
if (prefConfig.fps >= 60) {
LimeLog.info("Using Pixel 4 rendering hack");
decoderRenderer.enableLegacyFrameDropRendering();
}
}
else if (prefConfig.fps >= roundedRefreshRate) {
if (prefConfig.unlockFps) {
if (prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_CAP_FPS) {
if (prefConfig.fps >= roundedRefreshRate) {
if (prefConfig.fps > roundedRefreshRate + 3) {
// Use frame drops when rendering above the screen frame rate
decoderRenderer.enableLegacyFrameDropRendering();
prefConfig.framePacing = PreferenceConfiguration.FRAME_PACING_BALANCED;
LimeLog.info("Using drop mode for FPS > Hz");
} else if (roundedRefreshRate <= 49) {
// Let's avoid clearly bogus refresh rates and fall back to legacy rendering
decoderRenderer.enableLegacyFrameDropRendering();
prefConfig.framePacing = PreferenceConfiguration.FRAME_PACING_BALANCED;
LimeLog.info("Bogus refresh rate: " + roundedRefreshRate);
}
// HACK: Avoid crashing on some MTK devices
else if (decoderRenderer.isBlacklistedForFrameRate(roundedRefreshRate - 1)) {
// Use the old rendering strategy on these broken devices
decoderRenderer.enableLegacyFrameDropRendering();
} else {
else {
chosenFrameRate = roundedRefreshRate - 1;
LimeLog.info("Adjusting FPS target for screen to " + chosenFrameRate);
}
@@ -459,7 +435,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
.setResolution(prefConfig.width, prefConfig.height)
.setLaunchRefreshRate(prefConfig.fps)
.setRefreshRate(chosenFrameRate)
.setApp(new NvApp(appName != null ? appName : "app", appId, willStreamHdr))
.setApp(new NvApp(appName != null ? appName : "app", appId, appSupportsHdr))
.setBitrate(prefConfig.bitrate)
.setEnableSops(prefConfig.enableSops)
.enableLocalAudioPlayback(prefConfig.playHostAudio)
@@ -473,14 +449,17 @@ public class Game extends Activity implements SurfaceHolder.Callback,
.setAttachedGamepadMask(gamepadMask)
.setClientRefreshRateX100((int)(displayRefreshRate * 100))
.setAudioConfiguration(prefConfig.audioConfiguration)
.setAudioEncryption(true)
.build();
// Initialize the connection
conn = new NvConnection(host, uniqueId, config, PlatformBinding.getCryptoProvider(this), serverCert);
controllerHandler = new ControllerHandler(this, conn, this, prefConfig);
keyboardTranslator = new KeyboardTranslator();
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
inputManager.registerInputDeviceListener(controllerHandler, null);
inputManager.registerInputDeviceListener(keyboardTranslator, null);
// Initialize touch contexts
for (int i = 0; i < touchContextMap.length; i++) {
@@ -490,7 +469,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
else {
touchContextMap[i] = new RelativeTouchContext(conn, i,
REFERENCE_HORIZ_RES, REFERENCE_VERT_RES,
streamView);
streamView, prefConfig);
}
}
@@ -551,6 +530,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
performanceOverlayView.setVisibility(View.GONE);
notificationOverlayView.setVisibility(View.GONE);
// Update GameManager state to indicate we're in PiP (still gaming, but interruptible)
UiHelper.notifyStreamEnteringPiP(this);
}
else {
isHidingOverlays = false;
@@ -566,27 +548,99 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
notificationOverlayView.setVisibility(requestedNotificationOverlayVisibility);
// Update GameManager state to indicate we're out of PiP (gaming, non-interruptible)
UiHelper.notifyStreamExitingPiP(this);
}
}
}
@TargetApi(Build.VERSION_CODES.O)
private PictureInPictureParams getPictureInPictureParams(boolean autoEnter) {
PictureInPictureParams.Builder builder =
new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(prefConfig.width, prefConfig.height))
.setSourceRectHint(new Rect(
streamView.getLeft(), streamView.getTop(),
streamView.getRight(), streamView.getBottom()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
builder.setAutoEnterEnabled(autoEnter);
builder.setSeamlessResizeEnabled(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (appName != null) {
builder.setTitle(appName);
if (pcName != null) {
builder.setSubtitle(pcName);
}
}
else if (pcName != null) {
builder.setTitle(pcName);
}
}
return builder.build();
}
private void updatePipAutoEnter() {
if (!prefConfig.enablePip) {
return;
}
boolean autoEnter = connected && suppressPipRefCount == 0;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
setPictureInPictureParams(getPictureInPictureParams(autoEnter));
}
else {
autoEnterPip = autoEnter;
}
}
public void setMetaKeyCaptureState(boolean enabled) {
// This uses custom APIs present on some Samsung devices to allow capture of
// meta key events while streaming.
try {
Class<?> semWindowManager = Class.forName("com.samsung.android.view.SemWindowManager");
Method getInstanceMethod = semWindowManager.getMethod("getInstance");
Object manager = getInstanceMethod.invoke(null);
if (manager != null) {
Class<?>[] parameterTypes = new Class<?>[2];
parameterTypes[0] = String.class;
parameterTypes[1] = boolean.class;
Method requestMetaKeyEventMethod = semWindowManager.getDeclaredMethod("requestMetaKeyEvent", parameterTypes);
requestMetaKeyEventMethod.invoke(manager, this.getComponentName(), enabled);
}
else {
LimeLog.warning("SemWindowManager.getInstance() returned null");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
public void onUserLeaveHint() {
super.onUserLeaveHint();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (prefConfig.enablePip && connected) {
// PiP is only supported on Oreo and later, and we don't need to manually enter PiP on
// Android S and later. On Android R, we will use onPictureInPictureRequested() instead.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
if (autoEnterPip) {
try {
// This has thrown all sorts of weird exceptions on Samsung devices
// running Oreo. Just eat them and close gracefully on leave, rather
// than crashing.
enterPictureInPictureMode(
new PictureInPictureParams.Builder()
.setAspectRatio(new Rational(prefConfig.width, prefConfig.height))
.setSourceRectHint(new Rect(
streamView.getLeft(), streamView.getTop(),
streamView.getRight(), streamView.getBottom()))
.build());
enterPictureInPictureMode(getPictureInPictureParams(false));
} catch (Exception e) {
e.printStackTrace();
}
@@ -594,27 +648,32 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
}
@Override
@TargetApi(Build.VERSION_CODES.R)
public boolean onPictureInPictureRequested() {
// Enter PiP when requested unless we're on Android 12 which supports auto-enter.
if (autoEnterPip && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
enterPictureInPictureMode(getPictureInPictureParams(false));
}
return true;
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Capture is lost when focus is lost, so it must be requested again
// when focus is regained.
if (inputCaptureProvider.isCapturingEnabled() && hasFocus) {
// Recapture the pointer if focus was regained. On Android Q,
// we have to delay a bit before requesting capture because otherwise
// we'll hit the "requestPointerCapture called for a window that has no focus"
// error and it will not actually capture the cursor.
Handler h = new Handler();
h.postDelayed(new Runnable() {
@Override
public void run() {
streamView.requestPointerCapture();
}
}, 500);
}
}
// We can't guarantee the state of modifiers keys which may have
// lifted while focus was not on us. Clear the modifier state.
this.modifierFlags = 0;
// With Android native pointer capture, capture is lost when focus is lost,
// so it must be requested again when focus is regained.
inputCaptureProvider.onWindowFocusChanged(hasFocus);
}
private boolean isRefreshRateEqualMatch(float refreshRate) {
return refreshRate >= prefConfig.fps &&
refreshRate <= prefConfig.fps + 3;
}
private boolean isRefreshRateGoodMatch(float refreshRate) {
@@ -622,6 +681,26 @@ public class Game extends Activity implements SurfaceHolder.Callback,
Math.round(refreshRate) % prefConfig.fps <= 3;
}
private boolean shouldIgnoreInsetsForResolution(int width, int height) {
// Never ignore insets for non-native resolutions
if (!PreferenceConfiguration.isNativeResolution(width, height)) {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Display display = getWindowManager().getDefaultDisplay();
for (Display.Mode candidate : display.getSupportedModes()) {
// Ignore insets if this is an exact match for the display resolution
if ((width == candidate.getPhysicalWidth() && height == candidate.getPhysicalHeight()) ||
(height == candidate.getPhysicalWidth() && width == candidate.getPhysicalHeight())) {
return true;
}
}
}
return false;
}
private float prepareDisplayForRendering() {
Display display = getWindowManager().getDefaultDisplay();
WindowManager.LayoutParams windowLayoutParams = getWindow().getAttributes();
@@ -630,7 +709,11 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// On M, we can explicitly set the optimal display mode
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Display.Mode bestMode = display.getMode();
boolean isNativeResolutionStream = PreferenceConfiguration.isNativeResolution(prefConfig.width, prefConfig.height);
boolean refreshRateIsGood = isRefreshRateGoodMatch(bestMode.getRefreshRate());
boolean refreshRateIsEqual = isRefreshRateEqualMatch(bestMode.getRefreshRate());
boolean isTelevision = getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
for (Display.Mode candidate : display.getSupportedModes()) {
boolean refreshRateReduced = candidate.getRefreshRate() < bestMode.getRefreshRate();
boolean resolutionReduced = candidate.getPhysicalWidth() < bestMode.getPhysicalWidth() ||
@@ -641,14 +724,15 @@ public class Game extends Activity implements SurfaceHolder.Callback,
LimeLog.info("Examining display mode: "+candidate.getPhysicalWidth()+"x"+
candidate.getPhysicalHeight()+"x"+candidate.getRefreshRate());
if (candidate.getPhysicalWidth() > 4096) {
if (candidate.getPhysicalWidth() > 4096 && prefConfig.width <= 4096) {
// Avoid resolutions options above 4K to be safe
continue;
}
// On non-4K streams, we force the resolution to never change unless it's above
// 60 FPS, which may require a resolution reduction due to HDMI bandwidth limitations.
if (prefConfig.width < 3840 && prefConfig.fps <= 60) {
// 60 FPS, which may require a resolution reduction due to HDMI bandwidth limitations,
// or it's a native resolution stream.
if (prefConfig.width < 3840 && prefConfig.fps <= 60 && !isNativeResolutionStream) {
if (display.getMode().getPhysicalWidth() != candidate.getPhysicalWidth() ||
display.getMode().getPhysicalHeight() != candidate.getPhysicalHeight()) {
continue;
@@ -661,12 +745,38 @@ public class Game extends Activity implements SurfaceHolder.Callback,
continue;
}
if (refreshRateIsGood) {
// We have a good matching refresh rate, so we're looking for equal or greater
// that is also a good matching refresh rate for our stream frame rate.
if (refreshRateReduced || !isRefreshRateGoodMatch(candidate.getRefreshRate())) {
if (prefConfig.framePacing != PreferenceConfiguration.FRAME_PACING_MIN_LATENCY &&
refreshRateIsEqual && !isRefreshRateEqualMatch(candidate.getRefreshRate())) {
// If we had an equal refresh rate and this one is not, skip it. In min latency
// mode, we want to always prefer the highest frame rate even though it may cause
// microstuttering.
continue;
}
else if (refreshRateIsGood) {
// We've already got a good match, so if this one isn't also good, it's not
// worth considering at all.
if (!isRefreshRateGoodMatch(candidate.getRefreshRate())) {
continue;
}
// We don't want ever reduce our refresh rate unless we found an exact
// match and we're not in min latency mode.
if (refreshRateReduced) {
if (prefConfig.framePacing == PreferenceConfiguration.FRAME_PACING_MIN_LATENCY) {
continue;
}
else if (!isRefreshRateEqualMatch(candidate.getRefreshRate())) {
continue;
}
// For refresh rates lower than 50hz, we want to check if the device is a TV.
// Some TV's may have issues when attempting to lower its refresh rate
// As opposed to mobile devices, which are designed to lower refresh rate
// for battery life reasons.
else if(isTelevision && candidate.getRefreshRate() < 50) {
continue;
}
}
}
else if (!isRefreshRateGoodMatch(candidate.getRefreshRate())) {
// We didn't have a good match and this match isn't good either, so just don't
@@ -683,6 +793,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
bestMode = candidate;
refreshRateIsGood = isRefreshRateGoodMatch(candidate.getRefreshRate());
refreshRateIsEqual = isRefreshRateEqualMatch(candidate.getRefreshRate());
}
LimeLog.info("Selected display mode: "+bestMode.getPhysicalWidth()+"x"+
bestMode.getPhysicalHeight()+"x"+bestMode.getRefreshRate());
@@ -763,9 +874,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return displayRefreshRate;
}
else {
// Use the actual refresh rate of the display, since the preferred refresh rate or mode
// may not actually be applied (ex: Pixel 4 with Smooth Display disabled).
return getWindowManager().getDefaultDisplay().getRefreshRate();
// Use the lower of the current refresh rate and the selected refresh rate.
// The preferred refresh rate may not actually be applied (ex: Battery Saver mode).
return Math.min(getWindowManager().getDefaultDisplay().getRefreshRate(), displayRefreshRate);
}
}
@@ -773,6 +884,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private final Runnable hideSystemUi = new Runnable() {
@Override
public void run() {
// TODO: Do we want to use WindowInsetsController here on R+ instead of
// SYSTEM_UI_FLAG_IMMERSIVE_STICKY? They seem to do the same thing as of S...
// In multi-window mode on N+, we need to drop our layout flags or we'll
// be drawing underneath the system UI.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && isInMultiWindowMode()) {
@@ -837,10 +951,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
protected void onDestroy() {
super.onDestroy();
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
if (controllerHandler != null) {
InputManager inputManager = (InputManager) getSystemService(Context.INPUT_SERVICE);
inputManager.unregisterInputDeviceListener(controllerHandler);
}
if (keyboardTranslator != null) {
inputManager.unregisterInputDeviceListener(keyboardTranslator);
}
if (lowLatencyWifiLock != null) {
lowLatencyWifiLock.release();
@@ -892,10 +1009,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Add the video codec to the post-stream toast
if (message != null) {
if (videoFormat == MoonBridge.VIDEO_FORMAT_H265_MAIN10) {
message += " [H.265 HDR]";
message += " [HEVC HDR]";
}
else if (videoFormat == MoonBridge.VIDEO_FORMAT_H265) {
message += " [H.265]";
message += " [HEVC]";
}
else if (videoFormat == MoonBridge.VIDEO_FORMAT_H264) {
message += " [H.264]";
@@ -994,8 +1111,14 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return false;
}
private static byte getModifierState(KeyEvent event) {
byte modifier = 0;
// We cannot simply use modifierFlags for all key event processing, because
// some IMEs will not generate real key events for pressing Shift. Instead
// they will simply send key events with isShiftPressed() returning true,
// and we will need to send the modifier flag ourselves.
private byte getModifierState(KeyEvent event) {
// Start with the global modifier state to ensure we cover the case
// detailed in https://github.com/moonlight-stream/moonlight-android/issues/840
byte modifier = getModifierState();
if (event.isShiftPressed()) {
modifier |= KeyboardPacket.MODIFIER_SHIFT;
}
@@ -1027,8 +1150,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Handle a synthetic back button event that some Android OS versions
// create as a result of a right-click. This event WILL repeat if
// the right mouse button is held down, so we ignore those.
if ((event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) &&
int eventSource = event.getSource();
if ((eventSource == InputDevice.SOURCE_MOUSE ||
eventSource == InputDevice.SOURCE_MOUSE_RELATIVE) &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
// Send the right mouse button event if mouse back and forward
@@ -1053,7 +1177,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (!handled) {
// Try the keyboard handler
short translated = KeyboardTranslator.translate(event.getKeyCode());
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
return false;
}
@@ -1076,7 +1200,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
byte modifiers = getModifierState(event);
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
conn.sendKeyboardInput((short) 0x8010, KeyboardPacket.KEY_DOWN, modifiers);
}
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_DOWN, modifiers);
}
@@ -1098,8 +1221,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Handle a synthetic back button event that some Android OS versions
// create as a result of a right-click.
if ((event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) &&
int eventSource = event.getSource();
if ((eventSource == InputDevice.SOURCE_MOUSE ||
eventSource == InputDevice.SOURCE_MOUSE_RELATIVE) &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
// Send the right mouse button event if mouse back and forward
@@ -1123,7 +1247,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (!handled) {
// Try the keyboard handler
short translated = KeyboardTranslator.translate(event.getKeyCode());
short translated = keyboardTranslator.translate(event.getKeyCode(), event.getDeviceId());
if (translated == 0) {
return false;
}
@@ -1142,9 +1266,6 @@ public class Game extends Activity implements SurfaceHolder.Callback,
modifiers |= KeyboardPacket.MODIFIER_SHIFT;
}
conn.sendKeyboardInput(translated, KeyboardPacket.KEY_UP, modifiers);
if (KeyboardTranslator.needsShift(event.getKeyCode())) {
conn.sendKeyboardInput((short) 0x8010, KeyboardPacket.KEY_UP, getModifierState(event));
}
}
return true;
@@ -1161,10 +1282,10 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
@Override
public void showKeyboard() {
LimeLog.info("Showing keyboard overlay");
public void toggleKeyboard() {
LimeLog.info("Toggling keyboard overlay");
InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
inputManager.toggleSoftInput(0, 0);
}
// Returns true if the event was consumed
@@ -1175,21 +1296,25 @@ public class Game extends Activity implements SurfaceHolder.Callback,
return false;
}
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
int eventSource = event.getSource();
if ((eventSource & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (controllerHandler.handleMotionEvent(event)) {
return true;
}
}
else if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0 ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE)
else if ((eventSource & InputDevice.SOURCE_CLASS_POINTER) != 0 ||
(eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 ||
eventSource == InputDevice.SOURCE_MOUSE_RELATIVE)
{
// This case is for mice and non-finger touch devices
if (event.getSource() == InputDevice.SOURCE_MOUSE ||
event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE ||
if (eventSource == InputDevice.SOURCE_MOUSE ||
(eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0 || // SOURCE_TOUCHPAD
eventSource == InputDevice.SOURCE_MOUSE_RELATIVE ||
(event.getPointerCount() >= 1 &&
(event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE ||
event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS ||
event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER)))
event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER)) ||
eventSource == 12290) // 12290 = Samsung DeX mode desktop mouse
{
int changedButtons = event.getButtonState() ^ lastButtonState;
@@ -1209,18 +1334,48 @@ public class Game extends Activity implements SurfaceHolder.Callback,
short deltaY = (short)inputCaptureProvider.getRelativeAxisY(event);
if (deltaX != 0 || deltaY != 0) {
conn.sendMouseMove(deltaX, deltaY);
if (prefConfig.absoluteMouseMode) {
conn.sendMouseMoveAsMousePosition(deltaX, deltaY, (short)view.getWidth(), (short)view.getHeight());
}
else {
conn.sendMouseMove(deltaX, deltaY);
}
}
}
else if ((eventSource & InputDevice.SOURCE_CLASS_POSITION) != 0) {
// If this input device is not associated with the view itself (like a trackpad),
// we'll convert the device-specific coordinates to use to send the cursor position.
// This really isn't ideal but it's probably better than nothing.
//
// Trackpad on newer versions of Android (Oreo and later) should be caught by the
// relative axes case above. If we get here, we're on an older version that doesn't
// support pointer capture.
InputDevice device = event.getDevice();
if (device != null) {
InputDevice.MotionRange xRange = device.getMotionRange(MotionEvent.AXIS_X, eventSource);
InputDevice.MotionRange yRange = device.getMotionRange(MotionEvent.AXIS_Y, eventSource);
// All touchpads coordinate planes should start at (0, 0)
if (xRange != null && yRange != null && xRange.getMin() == 0 && yRange.getMin() == 0) {
int xMax = (int)xRange.getMax();
int yMax = (int)yRange.getMax();
// Touchpads must be smaller than (65535, 65535)
if (xMax <= Short.MAX_VALUE && yMax <= Short.MAX_VALUE) {
conn.sendMousePosition((short)event.getX(), (short)event.getY(),
(short)xMax, (short)yMax);
}
}
}
}
else if (view != null) {
// Otherwise send absolute position
// Otherwise send absolute position based on the view for SOURCE_CLASS_POINTER
updateMousePosition(view, event);
}
if (event.getActionMasked() == MotionEvent.ACTION_SCROLL) {
// Send the vertical scroll packet
byte vScrollClicks = (byte) event.getAxisValue(MotionEvent.AXIS_VSCROLL);
conn.sendMouseScroll(vScrollClicks);
conn.sendMouseHighResScroll((short)(event.getAxisValue(MotionEvent.AXIS_VSCROLL) * 120));
}
if ((changedButtons & MotionEvent.BUTTON_PRIMARY) != 0) {
@@ -1276,14 +1431,14 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (event.getPointerCount() == 1 && event.getActionIndex() == 0) {
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
lastAbsTouchDownTime = SystemClock.uptimeMillis();
lastAbsTouchDownTime = event.getEventTime();
lastAbsTouchDownX = event.getX(0);
lastAbsTouchDownY = event.getY(0);
// Stylus is left click
conn.sendMouseButtonDown(MouseButtonPacket.BUTTON_LEFT);
} else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
lastAbsTouchDownTime = SystemClock.uptimeMillis();
lastAbsTouchDownTime = event.getEventTime();
lastAbsTouchDownX = event.getX(0);
lastAbsTouchDownY = event.getY(0);
@@ -1293,14 +1448,14 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
else if (event.getActionMasked() == MotionEvent.ACTION_UP || event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
if (event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS) {
lastAbsTouchUpTime = SystemClock.uptimeMillis();
lastAbsTouchUpTime = event.getEventTime();
lastAbsTouchUpX = event.getX(0);
lastAbsTouchUpY = event.getY(0);
// Stylus is left click
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
} else if (event.getToolType(0) == MotionEvent.TOOL_TYPE_ERASER) {
lastAbsTouchUpTime = SystemClock.uptimeMillis();
lastAbsTouchUpTime = event.getEventTime();
lastAbsTouchUpX = event.getX(0);
lastAbsTouchUpY = event.getY(0);
@@ -1336,7 +1491,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN &&
event.getPointerCount() == 3) {
// Three fingers down
threeFingerDownTime = SystemClock.uptimeMillis();
threeFingerDownTime = event.getEventTime();
// Cancel the first and second touches to avoid
// erroneous events
@@ -1359,25 +1514,33 @@ public class Game extends Activity implements SurfaceHolder.Callback,
for (TouchContext touchContext : touchContextMap) {
touchContext.setPointerCount(event.getPointerCount());
}
context.touchDownEvent(eventX, eventY, true);
context.touchDownEvent(eventX, eventY, event.getEventTime(), true);
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
if (event.getPointerCount() == 1) {
if (event.getPointerCount() == 1 &&
(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || (event.getFlags() & MotionEvent.FLAG_CANCELED) == 0)) {
// All fingers up
if (SystemClock.uptimeMillis() - threeFingerDownTime < THREE_FINGER_TAP_THRESHOLD) {
if (event.getEventTime() - threeFingerDownTime < THREE_FINGER_TAP_THRESHOLD) {
// This is a 3 finger tap to bring up the keyboard
showKeyboard();
toggleKeyboard();
return true;
}
}
context.touchUpEvent(eventX, eventY);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && (event.getFlags() & MotionEvent.FLAG_CANCELED) != 0) {
context.cancelTouch();
}
else {
context.touchUpEvent(eventX, eventY, event.getEventTime());
}
for (TouchContext touchContext : touchContextMap) {
touchContext.setPointerCount(event.getPointerCount() - 1);
}
if (actionIndex == 0 && event.getPointerCount() > 1 && !context.isCancelled()) {
// The original secondary touch now becomes primary
context.touchDownEvent((int)event.getX(1), (int)event.getY(1), false);
context.touchDownEvent((int)event.getX(1), (int)event.getY(1), event.getEventTime(), false);
}
break;
case MotionEvent.ACTION_MOVE:
@@ -1391,7 +1554,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
{
aTouchContextMap.touchMoveEvent(
(int)event.getHistoricalX(aTouchContextMap.getActionIndex(), i),
(int)event.getHistoricalY(aTouchContextMap.getActionIndex(), i));
(int)event.getHistoricalY(aTouchContextMap.getActionIndex(), i),
event.getHistoricalEventTime(i));
}
}
}
@@ -1402,7 +1566,8 @@ public class Game extends Activity implements SurfaceHolder.Callback,
{
aTouchContextMap.touchMoveEvent(
(int)event.getX(aTouchContextMap.getActionIndex()),
(int)event.getY(aTouchContextMap.getActionIndex()));
(int)event.getY(aTouchContextMap.getActionIndex()),
event.getEventTime());
}
}
break;
@@ -1451,7 +1616,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_EXIT:
case MotionEvent.ACTION_HOVER_MOVE:
if (SystemClock.uptimeMillis() - lastAbsTouchUpTime <= STYLUS_UP_DEAD_ZONE_DELAY &&
if (event.getEventTime() - lastAbsTouchUpTime <= STYLUS_UP_DEAD_ZONE_DELAY &&
Math.sqrt(Math.pow(eventX - lastAbsTouchUpX, 2) + Math.pow(eventY - lastAbsTouchUpY, 2)) <= STYLUS_UP_DEAD_ZONE_RADIUS) {
// Enforce a small deadzone between touch up and hover or touch down to allow more precise double-clicking
return;
@@ -1460,7 +1625,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_UP:
if (SystemClock.uptimeMillis() - lastAbsTouchDownTime <= STYLUS_DOWN_DEAD_ZONE_DELAY &&
if (event.getEventTime() - lastAbsTouchDownTime <= STYLUS_DOWN_DEAD_ZONE_DELAY &&
Math.sqrt(Math.pow(eventX - lastAbsTouchDownX, 2) + Math.pow(eventY - lastAbsTouchDownY, 2)) <= STYLUS_DOWN_DEAD_ZONE_RADIUS) {
// Enforce a small deadzone between touch down and move or touch up to allow more precise double-clicking
return;
@@ -1509,9 +1674,13 @@ public class Game extends Activity implements SurfaceHolder.Callback,
private void stopConnection() {
if (connecting || connected) {
connecting = connected = false;
updatePipAutoEnter();
controllerHandler.stop();
// Update GameManager state to indicate we're no longer in game
UiHelper.notifyStreamEnded(this);
// Stop may take a few hundred ms to do some network I/O to tell
// the server we're going away and clean up. Let it run in a separate
// thread to keep things smooth for the UI. Inside moonlight-common,
@@ -1581,6 +1750,9 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Enable cursor visibility again
inputCaptureProvider.disableCapture();
// Disable meta key capture
setMetaKeyCaptureState(false);
if (!displayedFailureDialog) {
displayedFailureDialog = true;
LimeLog.severe("Connection terminated: " + errorCode);
@@ -1606,6 +1778,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
break;
case MoonBridge.ML_ERROR_UNEXPECTED_EARLY_TERMINATION:
case MoonBridge.ML_ERROR_PROTECTED_CONTENT:
message = getResources().getString(R.string.early_termination_error);
break;
@@ -1673,6 +1846,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
connected = true;
connecting = false;
updatePipAutoEnter();
// Hide the mouse cursor now after a short delay.
// Doing it before dismissing the spinner seems to be undone
@@ -1690,6 +1864,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
// Keep the display on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Enable meta key capture
setMetaKeyCaptureState(true);
// Update GameManager state to indicate we're in game
UiHelper.notifyStreamConnected(Game.this);
hideSystemUi(1000);
}
});
@@ -1724,6 +1904,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
controllerHandler.handleRumble(controllerNumber, lowFreqMotor, highFreqMotor);
}
@Override
public void setHdrMode(boolean enabled) {
LimeLog.info("Display HDR mode: " + (enabled ? "enabled" : "disabled"));
decoderRenderer.setHdrMode(enabled);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if (!surfaceCreated) {
@@ -1733,8 +1919,12 @@ public class Game extends Activity implements SurfaceHolder.Callback,
if (!attemptedConnection) {
attemptedConnection = true;
// Update GameManager state to indicate we're "loading" while connecting
UiHelper.notifyStreamConnecting(Game.this);
decoderRenderer.setRenderTarget(holder);
conn.start(PlatformBinding.getAudioRenderer(), decoderRenderer, Game.this);
conn.start(new AndroidAudioRenderer(Game.this, prefConfig.enableAudioFx),
decoderRenderer, Game.this);
}
}
@@ -1810,7 +2000,7 @@ public class Game extends Activity implements SurfaceHolder.Callback,
@Override
public void keyboardEvent(boolean buttonDown, short keyCode) {
short keyMap = KeyboardTranslator.translate(keyCode);
short keyMap = keyboardTranslator.translate(keyCode, -1);
if (keyMap != 0) {
// handleSpecialKeys() takes the Android keycode
if (handleSpecialKeys(keyCode, buttonDown)) {
@@ -1858,4 +2048,18 @@ public class Game extends Activity implements SurfaceHolder.Callback,
}
});
}
@Override
public void onUsbPermissionPromptStarting() {
// Disable PiP auto-enter while the USB permission prompt is on-screen. This prevents
// us from entering PiP while the user is interacting with the OS permission dialog.
suppressPipRefCount++;
updatePipAutoEnter();
}
@Override
public void onUsbPermissionPromptCompleted() {
suppressPipRefCount--;
updatePipAutoEnter();
}
}
@@ -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
+20 -7
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);
@@ -155,6 +160,13 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
}
});
// Amazon review didn't like the help button because the wiki was not entirely
// navigable via the Fire TV remote (though the relevant parts were). Let's hide
// it on Fire TV.
if (getPackageManager().hasSystemFeature("amazon.hardware.fire_tv")) {
helpButton.setVisibility(View.GONE);
}
getFragmentManager().beginTransaction()
.replace(R.id.pcFragmentContainer, new AdapterFragment())
.commitAllowingStateLoss();
@@ -319,20 +331,23 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
// Add a header with PC status details
menu.clearHeader();
String headerTitle = computer.details.name + " - ";
switch (computer.details.state)
{
case ONLINE:
menu.setHeaderTitle(R.string.pcview_menu_header_online);
headerTitle += getResources().getString(R.string.pcview_menu_header_online);
break;
case OFFLINE:
menu.setHeaderIcon(R.drawable.ic_pc_offline);
menu.setHeaderTitle(R.string.pcview_menu_header_offline);
headerTitle += getResources().getString(R.string.pcview_menu_header_offline);
break;
case UNKNOWN:
menu.setHeaderTitle(R.string.pcview_menu_header_unknown);
headerTitle += getResources().getString(R.string.pcview_menu_header_unknown);
break;
}
menu.setHeaderTitle(headerTitle);
// Inflate the context menu
if (computer.details.state == ComputerDetails.State.OFFLINE ||
computer.details.state == ComputerDetails.State.UNKNOWN) {
@@ -364,8 +379,7 @@ 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;
}
@@ -502,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;
}
@@ -13,11 +13,13 @@ import com.limelight.computers.ComputerManagerService;
import com.limelight.nvstream.http.ComputerDetails;
import com.limelight.nvstream.http.NvApp;
import com.limelight.nvstream.http.PairingManager;
import com.limelight.nvstream.wol.WakeOnLanSender;
import com.limelight.utils.Dialog;
import com.limelight.utils.ServerHelper;
import com.limelight.utils.SpinnerDialog;
import com.limelight.utils.UiHelper;
import java.io.IOException;
import java.util.ArrayList;
import java.util.UUID;
@@ -26,6 +28,7 @@ public class ShortcutTrampoline extends Activity {
private NvApp app;
private ArrayList<Intent> intentStack = new ArrayList<>();
private int wakeHostTries = 10;
private ComputerDetails computer;
private SpinnerDialog blockingLoadSpinner;
@@ -79,6 +82,23 @@ public class ShortcutTrampoline extends Activity {
return;
}
// Try to wake the target PC if it's offline (up to some retry limit)
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);
// If we sent at least one WoL packet, reset the computer state
// to force ComputerManager to poll it again.
managerBinder.invalidateStateForComputer(computer.uuid);
return;
} catch (IOException e) {
// If we got an exception, we couldn't send a single WoL packet,
// so fallthrough into the offline error path.
e.printStackTrace();
}
}
if (details.state != ComputerDetails.State.UNKNOWN) {
runOnUiThread(new Runnable() {
@Override
@@ -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() {
@@ -1,5 +1,6 @@
package com.limelight.binding.input;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.hardware.input.InputManager;
@@ -7,9 +8,11 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.media.AudioAttributes;
import android.os.Build;
import android.os.SystemClock;
import android.os.CombinedVibration;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.os.VibratorManager;
import android.util.SparseArray;
import android.view.InputDevice;
import android.view.InputEvent;
@@ -28,6 +31,8 @@ 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;
@@ -43,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<>();
@@ -57,6 +59,7 @@ 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 boolean hasGameController;
private final PreferenceConfiguration prefConfig;
@@ -69,9 +72,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
this.prefConfig = prefConfig;
this.deviceVibrator = (Vibrator) activityContext.getSystemService(Context.VIBRATOR_SERVICE);
// 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) {
@@ -107,6 +111,8 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
defaultContext.rightStickDeadzoneRadius = (float) stickDeadzone;
defaultContext.leftTriggerAxis = MotionEvent.AXIS_BRAKE;
defaultContext.rightTriggerAxis = MotionEvent.AXIS_GAS;
defaultContext.hatXAxis = MotionEvent.AXIS_HAT_X;
defaultContext.hatYAxis = MotionEvent.AXIS_HAT_Y;
defaultContext.controllerNumber = (short) 0;
defaultContext.assignedControllerNumber = true;
defaultContext.external = false;
@@ -153,11 +159,36 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
}
// This can happen when gaining/losing input focus with some devices.
// Input devices that have a trackpad may gain/lose AXIS_RELATIVE_X/Y.
@Override
public void onInputDeviceChanged(int deviceId) {
// Remove and re-add
onInputDeviceRemoved(deviceId);
onInputDeviceAdded(deviceId);
InputDevice device = InputDevice.getDevice(deviceId);
if (device == null) {
return;
}
// If we don't have a context for this device, we don't need to update anything
InputDeviceContext existingContext = inputDeviceContexts.get(deviceId);
if (existingContext == null) {
return;
}
LimeLog.info("Device changed: "+existingContext.name+" ("+deviceId+")");
// Don't release the controller number, because we will carry it over if it is present.
// We also want to make sure the change is invisible to the host PC to avoid an add/remove
// cycle for the gamepad which may break some games.
existingContext.destroy();
InputDeviceContext newContext = createInputDeviceContextForDevice(device);
// Copy over existing controller number state
newContext.assignedControllerNumber = existingContext.assignedControllerNumber;
newContext.reservedControllerNumber = existingContext.reservedControllerNumber;
newContext.controllerNumber = existingContext.controllerNumber;
inputDeviceContexts.put(deviceId, newContext);
}
public void stop() {
@@ -171,6 +202,7 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
deviceContext.destroy();
}
sceManager.stop();
deviceVibrator.cancel();
}
@@ -194,6 +226,28 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
return true;
}
// HACK for https://issuetracker.google.com/issues/163120692
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
if (device.getId() == -1) {
// This "virtual" device could be input from any of the attached devices.
// Look to see if any gamepads are connected.
int[] ids = InputDevice.getDeviceIds();
for (int id : ids) {
InputDevice dev = InputDevice.getDevice(id);
if (dev == null) {
// This device was removed during enumeration
continue;
}
// If there are any gamepad devices connected, we'll
// report that this virtual device is a gamepad.
if (hasJoystickAxes(dev) || hasGamepadButtons(dev)) {
return true;
}
}
}
}
// Otherwise, we'll try anything that claims to be a non-alphabetic keyboard
return device.getKeyboardType() != InputDevice.KEYBOARD_TYPE_ALPHABETIC;
}
@@ -454,6 +508,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);
@@ -463,7 +518,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
context.productId = dev.getProductId();
}
if (dev.getVibrator().hasVibrator()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && hasDualAmplitudeControlledRumbleVibrators(dev.getVibratorManager())) {
context.vibratorManager = dev.getVibratorManager();
}
else if (dev.getVibrator().hasVibrator()) {
context.vibrator = dev.getVibrator();
}
@@ -648,9 +706,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.
@@ -703,6 +758,13 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
return null;
}
// HACK for https://issuetracker.google.com/issues/163120692
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {
if (event.getDeviceId() == -1) {
return defaultContext;
}
}
// Return the existing context if it exists
InputDeviceContext context = inputDeviceContexts.get(event.getDeviceId());
if (context != null) {
@@ -864,7 +926,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
return KeyEvent.KEYCODE_BUTTON_MODE;
}
if ((context.vendorId == 0x057e && context.productId == 0x2009) || // Switch Pro controller
// This mapping was adding in Android 10, then changed based on
// kernel changes (adding hid-nintendo) in Android 11. If we're
// on anything newer than Pie, just use the built-in mapping.
if ((context.vendorId == 0x057e && context.productId == 0x2009 && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) || // Switch Pro controller
(context.vendorId == 0x0f0d && context.productId == 0x00c1)) { // HORIPAD for Switch
switch (event.getScanCode()) {
case 0x130:
@@ -1249,7 +1314,64 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
}
}
private void rumbleVibrator(Vibrator vibrator, short lowFreqMotor, short highFreqMotor) {
@TargetApi(31)
private boolean hasDualAmplitudeControlledRumbleVibrators(VibratorManager vm) {
int[] vibratorIds = vm.getVibratorIds();
// There must be exactly 2 vibrators on this device
if (vibratorIds.length != 2) {
return false;
}
// Both vibrators must have amplitude control
for (int vid : vibratorIds) {
if (!vm.getVibrator(vid).hasAmplitudeControl()) {
return false;
}
}
return true;
}
// This must only be called if hasDualAmplitudeControlledRumbleVibrators() is true!
@TargetApi(31)
private void rumbleDualVibrators(VibratorManager vm, short lowFreqMotor, short highFreqMotor) {
// Normalize motor values to 0-255 amplitudes for VibrationManager
highFreqMotor = (short)((highFreqMotor >> 8) & 0xFF);
lowFreqMotor = (short)((lowFreqMotor >> 8) & 0xFF);
// If they're both zero, we can just call cancel().
if (lowFreqMotor == 0 && highFreqMotor == 0) {
vm.cancel();
return;
}
// There's no documentation that states that vibrators for FF_RUMBLE input devices will
// always be enumerated in this order, but it seems consistent between Xbox Series X (USB),
// PS3 (USB), and PS4 (USB+BT) controllers on Android 12 Beta 3.
int[] vibratorIds = vm.getVibratorIds();
int[] vibratorAmplitudes = new int[] { highFreqMotor, lowFreqMotor };
CombinedVibration.ParallelCombination combo = CombinedVibration.startParallel();
for (int i = 0; i < vibratorIds.length; i++) {
// It's illegal to create a VibrationEffect with an amplitude of 0.
// Simply excluding that vibrator from our ParallelCombination will turn it off.
if (vibratorAmplitudes[i] != 0) {
combo.addVibrator(vibratorIds[i], VibrationEffect.createOneShot(60000, vibratorAmplitudes[i]));
}
}
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) {
// Since we can only use a single amplitude value, compute the desired amplitude
// by taking 80% of the big motor and 33% of the small motor, then capping to 255.
// NB: This value is now 0-255 as required by VibrationEffect.
@@ -1271,10 +1393,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;
}
}
@@ -1284,7 +1414,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();
@@ -1305,9 +1441,19 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
if (deviceContext.controllerNumber == controllerNumber) {
foundMatchingDevice = true;
if (deviceContext.vibrator != null) {
// 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;
rumbleVibrator(deviceContext.vibrator, lowFreqMotor, highFreqMotor);
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);
}
}
}
@@ -1327,12 +1473,12 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
// controls that triggered the rumble. Vibrate the device if
// the user has requested that behavior.
if (!foundMatchingDevice && prefConfig.onscreenController && !prefConfig.onlyL3R3 && prefConfig.vibrateOsc) {
rumbleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
rumbleSingleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
}
else if (foundMatchingDevice && !vibrated && prefConfig.vibrateFallbackToDevice) {
// We found a device to vibrate but it didn't have rumble support. The user
// has requested us to vibrate the device in this case.
rumbleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
rumbleSingleVibrator(deviceVibrator, lowFreqMotor, highFreqMotor);
}
}
}
@@ -1356,13 +1502,21 @@ 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);
} catch (InterruptedException ignored) {}
Thread.sleep(ControllerHandler.MINIMUM_BUTTON_DOWN_TIME_MS - buttonDownTime);
} 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();
}
}
switch (keyCode) {
@@ -1375,7 +1529,7 @@ 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);
}
@@ -1428,11 +1582,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;
@@ -1468,10 +1622,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 ignored) {}
}
}
@@ -1486,10 +1636,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 ignored) {}
}
}
@@ -1527,7 +1673,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;
@@ -1618,7 +1764,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;
@@ -1641,7 +1787,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;
@@ -1769,7 +1915,9 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
class InputDeviceContext extends GenericControllerContext {
public String name;
public VibratorManager vibratorManager;
public Vibrator vibrator;
public InputDevice inputDevice;
public int leftStickXAxis = -1;
public int leftStickYAxis = -1;
@@ -1815,7 +1963,10 @@ public class ControllerHandler implements InputManager.InputDeviceListener, UsbD
public void destroy() {
super.destroy();
if (vibrator != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && vibratorManager != null) {
vibratorManager.cancel();
}
else if (vibrator != null) {
vibrator.cancel();
}
}
@@ -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,7 +2,9 @@ package com.limelight.binding.input.capture;
import android.annotation.TargetApi;
import android.app.Activity;
import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Handler;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
@@ -12,11 +14,13 @@ import android.view.View;
// pointer icon hiding behavior over our stream view just in case pointer capture
// is unavailable on this system (ex: DeX, ChromeOS)
@TargetApi(Build.VERSION_CODES.O)
public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptureProvider {
public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptureProvider implements InputManager.InputDeviceListener {
private InputManager inputManager;
private View targetView;
public AndroidNativePointerCaptureProvider(Activity activity, View targetView) {
super(activity, targetView);
this.inputManager = activity.getSystemService(InputManager.class);
this.targetView = targetView;
}
@@ -24,38 +28,133 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
}
// We only capture the pointer if we have a compatible InputDevice
// present. This is a workaround for an Android 12 regression causing
// incorrect mouse input when using the SPen.
// https://github.com/moonlight-stream/moonlight-android/issues/1030
private boolean hasCaptureCompatibleInputDevice() {
for (int id : InputDevice.getDeviceIds()) {
InputDevice device = InputDevice.getDevice(id);
if (device == null) {
continue;
}
// Skip touchscreens when considering compatible capture devices.
// Samsung devices on Android 12 will report a sec_touchpad device
// with SOURCE_TOUCHSCREEN, SOURCE_KEYBOARD, and SOURCE_MOUSE.
// Upon enabling pointer capture, that device will switch to
// SOURCE_KEYBOARD and SOURCE_TOUCHPAD.
if (device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
continue;
}
if (device.supportsSource(InputDevice.SOURCE_MOUSE) ||
device.supportsSource(InputDevice.SOURCE_MOUSE_RELATIVE) ||
device.supportsSource(InputDevice.SOURCE_TOUCHPAD)) {
return true;
}
}
return false;
}
@Override
public void enableCapture() {
super.enableCapture();
targetView.requestPointerCapture();
// Listen for device events to enable/disable capture
inputManager.registerInputDeviceListener(this, null);
// Capture now if we have a capture-capable device
if (hasCaptureCompatibleInputDevice()) {
targetView.requestPointerCapture();
}
}
@Override
public void disableCapture() {
super.disableCapture();
inputManager.unregisterInputDeviceListener(this);
targetView.releasePointerCapture();
}
@Override
public void onWindowFocusChanged(boolean focusActive) {
if (!focusActive || !isCapturing) {
return;
}
// Recapture the pointer if focus was regained. On Android Q,
// we have to delay a bit before requesting capture because otherwise
// we'll hit the "requestPointerCapture called for a window that has no focus"
// error and it will not actually capture the cursor.
Handler h = new Handler();
h.postDelayed(new Runnable() {
@Override
public void run() {
if (hasCaptureCompatibleInputDevice()) {
targetView.requestPointerCapture();
}
}
}, 500);
}
@Override
public boolean eventHasRelativeMouseAxes(MotionEvent event) {
return event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE;
// SOURCE_MOUSE_RELATIVE is how SOURCE_MOUSE appears when our view has pointer capture.
// SOURCE_TOUCHPAD will have relative axes populated iff our view has pointer capture.
// See https://developer.android.com/reference/android/view/View#requestPointerCapture()
int eventSource = event.getSource();
return (eventSource == InputDevice.SOURCE_MOUSE_RELATIVE && event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) ||
(eventSource == InputDevice.SOURCE_TOUCHPAD && targetView.hasPointerCapture());
}
@Override
public float getRelativeAxisX(MotionEvent event) {
float x = event.getX();
int axis = (event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) ?
MotionEvent.AXIS_X : MotionEvent.AXIS_RELATIVE_X;
float x = event.getAxisValue(axis);
for (int i = 0; i < event.getHistorySize(); i++) {
x += event.getHistoricalX(i);
x += event.getHistoricalAxisValue(axis, i);
}
return x;
}
@Override
public float getRelativeAxisY(MotionEvent event) {
float y = event.getY();
int axis = (event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE) ?
MotionEvent.AXIS_Y : MotionEvent.AXIS_RELATIVE_Y;
float y = event.getAxisValue(axis);
for (int i = 0; i < event.getHistorySize(); i++) {
y += event.getHistoricalY(i);
y += event.getHistoricalAxisValue(axis, i);
}
return y;
}
@Override
public void onInputDeviceAdded(int deviceId) {
// Check if we've added a capture-compatible device
if (!targetView.hasPointerCapture() && hasCaptureCompatibleInputDevice()) {
targetView.requestPointerCapture();
}
}
@Override
public void onInputDeviceRemoved(int deviceId) {
// Check if the capture-compatible device was removed
if (targetView.hasPointerCapture() && !hasCaptureCompatibleInputDevice()) {
targetView.releasePointerCapture();
}
}
@Override
public void onInputDeviceChanged(int deviceId) {
// Emulating a remove+add should be sufficient for our purposes.
//
// Note: This callback must be handled carefully because it can happen as a result of
// calling requestPointerCapture(). This can cause trackpad devices to gain SOURCE_MOUSE_RELATIVE
// and re-enter this callback.
onInputDeviceRemoved(deviceId);
onInputDeviceAdded(deviceId);
}
}
@@ -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);
}
@@ -33,4 +33,6 @@ public abstract class InputCaptureProvider {
public float getRelativeAxisY(MotionEvent event) {
return 0;
}
public void onWindowFocusChanged(boolean focusActive) {}
}
@@ -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;
@@ -37,7 +37,9 @@ public abstract class AbstractXboxController extends AbstractController {
// around when we call notifyDeviceAdded(), we won't be able to claim
// the controller number used by the original InputDevice.
Thread.sleep(1000);
} catch (InterruptedException e) {}
} catch (InterruptedException e) {
return;
}
// Report that we're added _before_ reporting input
notifyDeviceAdded();
@@ -56,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
@@ -64,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,15 +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. :(
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), 0));
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;
}
@@ -220,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()) {
@@ -240,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
@@ -255,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();
}
}
@@ -26,6 +26,7 @@ public class Xbox360Controller extends AbstractXboxController {
0x0f0d, // Hori
0x1038, // SteelSeries
0x11c9, // Nacon
0x1209, // Ardwiino
0x12ab, // Unknown
0x1430, // RedOctane
0x146b, // BigBen
@@ -33,8 +34,11 @@ public class Xbox360Controller extends AbstractXboxController {
0x15e4, // Numark
0x162e, // Joytech
0x1689, // Razer Onza
0x1949, // Lab126 (Amazon Luna)
0x1bad, // Harmonix
0x20d6, // PowerA
0x24c6, // PowerA
0x2f24, // GameSir
};
public static boolean canClaimDevice(UsbDevice device) {
@@ -21,7 +21,9 @@ public class XboxOneController extends AbstractXboxController {
0x0e6f, // Unknown
0x0f0d, // Hori
0x1532, // Razer Wildcat
0x20d6, // PowerA
0x24c6, // PowerA
0x2e24, // Hyperkin
};
private static final byte[] FW2015_INIT = {0x05, 0x20, 0x00, 0x01, 0x00};
@@ -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,6 +1,7 @@
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;
@@ -23,13 +24,20 @@ public class AbsoluteTouchContext implements TouchContext {
private boolean confirmedTap;
private Timer longPressTimer;
private Timer tapDownTimer;
private float accumulatedScrollDelta;
private final NvConnection conn;
private final int actionIndex;
private final View targetView;
private final Handler handler;
private static final int SCROLL_SPEED_DIVISOR = 20;
private final Runnable leftButtonUpRunnable = new Runnable() {
@Override
public void run() {
conn.sendMouseButtonUp(MouseButtonPacket.BUTTON_LEFT);
}
};
private static final int SCROLL_SPEED_FACTOR = 3;
private static final int LONG_PRESS_TIME_THRESHOLD = 650;
private static final int LONG_PRESS_DISTANCE_THRESHOLD = 30;
@@ -45,6 +53,7 @@ public class AbsoluteTouchContext implements TouchContext {
this.conn = conn;
this.actionIndex = actionIndex;
this.targetView = view;
this.handler = new Handler(Looper.getMainLooper());
}
@Override
@@ -54,7 +63,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
@@ -63,9 +72,8 @@ public class AbsoluteTouchContext implements TouchContext {
lastTouchLocationX = lastTouchDownX = eventX;
lastTouchLocationY = lastTouchDownY = eventY;
lastTouchDownTime = SystemClock.uptimeMillis();
lastTouchDownTime = eventTime;
cancelled = confirmedTap = confirmedLongPress = false;
accumulatedScrollDelta = 0;
if (actionIndex == 0) {
// Start the timers
@@ -92,7 +100,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;
@@ -115,17 +123,17 @@ 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 ignored) {}
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() {
@@ -209,7 +217,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;
@@ -228,11 +236,7 @@ public class AbsoluteTouchContext implements TouchContext {
}
}
else if (actionIndex == 1) {
accumulatedScrollDelta += (eventY - lastTouchLocationY) / (float)SCROLL_SPEED_DIVISOR;
if ((short)accumulatedScrollDelta != 0) {
conn.sendMouseHighResScroll((short)accumulatedScrollDelta);
accumulatedScrollDelta -= (short)accumulatedScrollDelta;
}
conn.sendMouseHighResScroll((short)((eventY - lastTouchLocationY) * SCROLL_SPEED_FACTOR));
}
lastTouchLocationX = eventX;
@@ -1,10 +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 com.limelight.preferences.PreferenceConfiguration;
import java.util.Timer;
import java.util.TimerTask;
@@ -30,22 +32,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;
// 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;
private static final int TAP_TIME_THRESHOLD = 250;
private static final int DRAG_TIME_THRESHOLD = 650;
private static final int SCROLL_SPEED_DIVISOR = 20;
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 +103,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 +116,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 +131,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 +142,7 @@ public class RelativeTouchContext implements TouchContext {
if (isNewFinger) {
maxPointerCountInGesture = pointerCount;
originalTouchTime = SystemClock.uptimeMillis();
originalTouchTime = eventTime;
cancelled = confirmedDrag = confirmedMove = confirmedScroll = false;
distanceMoved = 0;
@@ -115,7 +156,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,23 +171,23 @@ 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 ignored) {}
// 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
cancelDragTimer();
dragTimer = new Timer(true);
dragTimer.schedule(new TimerTask() {
@Override
@@ -157,6 +198,11 @@ public class RelativeTouchContext implements TouchContext {
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;
@@ -210,7 +256,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;
@@ -240,12 +286,19 @@ public class RelativeTouchContext implements TouchContext {
if (pointerCount == 2) {
if (confirmedScroll) {
deltaY /= SCROLL_SPEED_DIVISOR;
conn.sendMouseHighResScroll((short) deltaY);
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;
@@ -312,7 +311,7 @@ public class AnalogStick extends VirtualControllerElement {
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,7 +319,7 @@ public class AnalogStick extends VirtualControllerElement {
notifyOnClick();
}
// reset last click timestamp
timeLastClick = SystemClock.uptimeMillis();
timeLastClick = event.getEventTime();
// set item pressed and update
setPressed(true);
break;
@@ -335,7 +334,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();
@@ -177,6 +177,15 @@ 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);
@@ -200,9 +209,11 @@ 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;
}
}
@@ -9,12 +9,11 @@ import android.util.DisplayMetrics;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.limelight.LimeLog;
import com.limelight.R;
import com.limelight.binding.input.ControllerHandler;
import com.limelight.nvstream.NvConnection;
import java.util.ArrayList;
import java.util.List;
@@ -40,11 +39,10 @@ public class VirtualController {
private static final boolean _PRINT_DEBUG_INFORMATION = false;
private ControllerHandler controllerHandler;
private Context context = null;
private final ControllerHandler controllerHandler;
private final Context context;
private FrameLayout frame_layout = null;
private RelativeLayout relative_layout = null;
private Timer retransmitTimer;
@@ -60,10 +58,6 @@ public class VirtualController {
this.frame_layout = layout;
this.context = context;
relative_layout = new RelativeLayout(context);
frame_layout.addView(relative_layout);
buttonConfigure = new Button(context);
buttonConfigure.setAlpha(0.25f);
buttonConfigure.setFocusable(false);
@@ -87,7 +81,7 @@ public class VirtualController {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
relative_layout.invalidate();
buttonConfigure.invalidate();
for (VirtualControllerElement element : elements) {
element.invalidate();
@@ -99,11 +93,20 @@ public class VirtualController {
public void hide() {
retransmitTimer.cancel();
relative_layout.setVisibility(View.INVISIBLE);
for (VirtualControllerElement element : elements) {
element.setVisibility(View.INVISIBLE);
}
buttonConfigure.setVisibility(View.INVISIBLE);
}
public void show() {
relative_layout.setVisibility(View.VISIBLE);
for (VirtualControllerElement element : elements) {
element.setVisibility(View.VISIBLE);
}
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
@@ -120,9 +123,11 @@ public class VirtualController {
public void removeElements() {
for (VirtualControllerElement element : elements) {
relative_layout.removeView(element);
frame_layout.removeView(element);
}
elements.clear();
frame_layout.removeView(buttonConfigure);
}
public void setOpacity(int opacity) {
@@ -134,10 +139,10 @@ public class VirtualController {
public void addElement(VirtualControllerElement element, int x, int y, int width, int height) {
elements.add(element);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(width, height);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(width, height);
layoutParams.setMargins(x, y, 0, 0);
relative_layout.addView(element, layoutParams);
frame_layout.addView(element, layoutParams);
}
public List<VirtualControllerElement> getElements() {
@@ -146,23 +151,20 @@ public class VirtualController {
private static final void _DBG(String text) {
if (_PRINT_DEBUG_INFORMATION) {
System.out.println("VirtualController: " + text);
LimeLog.info("VirtualController: " + text);
}
}
public void refreshLayout() {
relative_layout.removeAllViews();
removeElements();
DisplayMetrics screen = context.getResources().getDisplayMetrics();
int buttonSize = (int)(screen.heightPixels*0.06f);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(buttonSize, buttonSize);
params.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(buttonSize, buttonSize);
params.leftMargin = 15;
params.topMargin = 15;
relative_layout.addView(buttonConfigure, params);
frame_layout.addView(buttonConfigure, params);
// Start with the default layout
VirtualControllerConfigurationLoader.createDefaultLayout(this, context);
@@ -12,7 +12,7 @@ import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.FrameLayout;
import org.json.JSONException;
import org.json.JSONObject;
@@ -72,7 +72,7 @@ public abstract class VirtualControllerElement extends View {
int newPos_x = (int) getX() + x - pressed_x;
int newPos_y = (int) getY() + y - pressed_y;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = newPos_x > 0 ? newPos_x : 0;
layoutParams.topMargin = newPos_y > 0 ? newPos_y : 0;
@@ -83,7 +83,7 @@ public abstract class VirtualControllerElement extends View {
}
protected void resizeElement(int pressed_x, int pressed_y, int width, int height) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
int newHeight = height + (startSize_y - pressed_y);
int newWidth = width + (startSize_x - pressed_x);
@@ -316,7 +316,7 @@ public abstract class VirtualControllerElement extends View {
public JSONObject getConfiguration() throws JSONException {
JSONObject configuration = new JSONObject();
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
configuration.put("LEFT", layoutParams.leftMargin);
configuration.put("TOP", layoutParams.topMargin);
@@ -327,7 +327,7 @@ public abstract class VirtualControllerElement extends View {
}
public void loadConfiguration(JSONObject configuration) throws JSONException {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = configuration.getInt("LEFT");
layoutParams.topMargin = configuration.getInt("TOP");
@@ -1,7 +1,9 @@
package com.limelight.binding.video;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.LinkedBlockingQueue;
import org.jcodec.codecs.h264.H264Utils;
import org.jcodec.codecs.h264.io.model.SeqParameterSet;
@@ -13,6 +15,7 @@ import com.limelight.nvstream.av.video.VideoDecoderRenderer;
import com.limelight.nvstream.jni.MoonBridge;
import com.limelight.preferences.PreferenceConfiguration;
import android.annotation.TargetApi;
import android.content.Context;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
@@ -20,11 +23,15 @@ import android.media.MediaFormat;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaCodec.CodecException;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.os.SystemClock;
import android.util.Range;
import android.view.Choreographer;
import android.view.SurfaceHolder;
public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
public class MediaCodecDecoderRenderer extends VideoDecoderRenderer implements Choreographer.FrameCallback {
private static final boolean USE_FRAME_RENDER_TIME = false;
private static final boolean FRAME_RENDER_TIME_ONLY = USE_FRAME_RENDER_TIME && false;
@@ -45,10 +52,10 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
private MediaCodec videoDecoder;
private Thread rendererThread;
private boolean needsSpsBitstreamFixup, isExynos4;
private boolean adaptivePlayback, directSubmit;
private boolean lowLatency;
private boolean adaptivePlayback, directSubmit, fusedIdrFrame;
private boolean constrainedHighProfile;
private boolean refFrameInvalidationAvc, refFrameInvalidationHevc;
private byte optimalSlicesPerFrame;
private boolean refFrameInvalidationActive;
private int initialWidth, initialHeight;
private int videoFormat;
@@ -59,7 +66,6 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
private int consecutiveCrashCount;
private String glRenderer;
private boolean foreground = true;
private boolean legacyFrameDropRendering = false;
private PerfOverlayListener perfListener;
private MediaFormat inputFormat;
@@ -82,9 +88,17 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
private int refreshRate;
private PreferenceConfiguration prefs;
private LinkedBlockingQueue<Integer> outputBufferQueue = new LinkedBlockingQueue<>();
private static final int OUTPUT_BUFFER_QUEUE_LIMIT = 2;
private long lastRenderedFrameTimeNanos;
private HandlerThread choreographerHandlerThread;
private Handler choreographerHandler;
private int numSpsIn;
private int numPpsIn;
private int numVpsIn;
private int numFramesIn;
private int numFramesOut;
private MediaCodecInfo findAvcDecoder() {
MediaCodecInfo decoder = MediaCodecHelper.findProbableSafeDecoder("video/avc", MediaCodecInfo.CodecProfileLevel.AVCProfileHigh);
@@ -94,8 +108,63 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return decoder;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private boolean decoderCanMeetPerformancePoint(MediaCodecInfo.VideoCapabilities caps, PreferenceConfiguration prefs) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaCodecInfo.VideoCapabilities.PerformancePoint targetPerfPoint = new MediaCodecInfo.VideoCapabilities.PerformancePoint(prefs.width, prefs.height, prefs.fps);
List<MediaCodecInfo.VideoCapabilities.PerformancePoint> perfPoints = caps.getSupportedPerformancePoints();
if (perfPoints != null) {
for (MediaCodecInfo.VideoCapabilities.PerformancePoint perfPoint : perfPoints) {
// If we find a performance point that covers our target, we're good to go
if (perfPoint.covers(targetPerfPoint)) {
return true;
}
}
// We had performance point data but none met the specified streaming settings
return false;
}
// Fall-through to try the Android M API if there's no performance point data
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
try {
// We'll ask the decoder what it can do for us at this resolution and see if our
// requested frame rate falls below or inside the range of achievable frame rates.
Range<Double> fpsRange = caps.getAchievableFrameRatesFor(prefs.width, prefs.height);
if (fpsRange != null) {
return prefs.fps <= fpsRange.getUpper();
}
// Fall-through to try the Android L API if there's no performance point data
} catch (IllegalArgumentException e) {
// Video size not supported at any frame rate
return false;
}
}
// As a last resort, we will use areSizeAndRateSupported() which is explicitly NOT a
// performance metric, but it can work at least for the purpose of determining if
// the codec is going to die when given a stream with the specified settings.
return caps.areSizeAndRateSupported(prefs.width, prefs.height, prefs.fps);
}
private boolean decoderCanMeetPerformancePointWithHevcAndNotAvc(MediaCodecInfo avcDecoderInfo, MediaCodecInfo hevcDecoderInfo, PreferenceConfiguration prefs) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
MediaCodecInfo.VideoCapabilities avcCaps = avcDecoderInfo.getCapabilitiesForType("video/avc").getVideoCapabilities();
MediaCodecInfo.VideoCapabilities hevcCaps = hevcDecoderInfo.getCapabilitiesForType("video/hevc").getVideoCapabilities();
return !decoderCanMeetPerformancePoint(avcCaps, prefs) && decoderCanMeetPerformancePoint(hevcCaps, prefs);
}
else {
// No performance data
return false;
}
}
private MediaCodecInfo findHevcDecoder(PreferenceConfiguration prefs, boolean meteredNetwork, boolean requestedHdr) {
// Don't return anything if H.265 is forced off
// Don't return anything if HEVC is forced off
if (prefs.videoFormat == PreferenceConfiguration.FORCE_H265_OFF) {
return null;
}
@@ -105,16 +174,26 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// We need HEVC Main profile, so we could pass that constant to findProbableSafeDecoder, however
// some decoders (at least Qualcomm's Snapdragon 805) don't properly report support
// for even required levels of HEVC.
MediaCodecInfo decoderInfo = MediaCodecHelper.findProbableSafeDecoder("video/hevc", -1);
if (decoderInfo != null) {
if (!MediaCodecHelper.decoderIsWhitelistedForHevc(decoderInfo.getName(), meteredNetwork)) {
LimeLog.info("Found HEVC decoder, but it's not whitelisted - "+decoderInfo.getName());
MediaCodecInfo hevcDecoderInfo = MediaCodecHelper.findProbableSafeDecoder("video/hevc", -1);
if (hevcDecoderInfo != null) {
if (!MediaCodecHelper.decoderIsWhitelistedForHevc(hevcDecoderInfo.getName(), meteredNetwork, prefs)) {
LimeLog.info("Found HEVC decoder, but it's not whitelisted - "+hevcDecoderInfo.getName());
// Force HEVC enabled if the user asked for it
if (prefs.videoFormat == PreferenceConfiguration.FORCE_H265_ON) {
LimeLog.info("Forcing HEVC enabled despite non-whitelisted decoder");
}
// HDR implies HEVC forced on, since HEVCMain10HDR10 is required for HDR.
else if (requestedHdr) {
LimeLog.info("Forcing HEVC enabled for HDR streaming");
}
// > 4K streaming also requires HEVC, so force it on there too.
if (prefs.videoFormat == PreferenceConfiguration.FORCE_H265_ON || requestedHdr ||
prefs.width > 4096 || prefs.height > 4096) {
LimeLog.info("Forcing H265 enabled despite non-whitelisted decoder");
else if (prefs.width > 4096 || prefs.height > 4096) {
LimeLog.info("Forcing HEVC enabled for over 4K streaming");
}
// Use HEVC if the H.264 decoder is unable to meet the performance point
else if (avcDecoder != null && decoderCanMeetPerformancePointWithHevcAndNotAvc(avcDecoder, hevcDecoderInfo, prefs)) {
LimeLog.info("Using non-whitelisted HEVC decoder to meet performance point");
}
else {
return null;
@@ -122,7 +201,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
}
return decoderInfo;
return hevcDecoderInfo;
}
public void setRenderTarget(SurfaceHolder renderTarget) {
@@ -164,18 +243,13 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// Set attributes that are queried in getCapabilities(). This must be done here
// because getCapabilities() may be called before setup() in current versions of the common
// library. The limitation of this is that we don't know whether we're using HEVC or AVC, so
// we just assume AVC. This isn't really a problem because the capabilities are usually
// shared between AVC and HEVC decoders on the same device.
// library. The limitation of this is that we don't know whether we're using HEVC or AVC.
int avcOptimalSlicesPerFrame = 0;
int hevcOptimalSlicesPerFrame = 0;
if (avcDecoder != null) {
directSubmit = MediaCodecHelper.decoderCanDirectSubmit(avcDecoder.getName());
refFrameInvalidationAvc = MediaCodecHelper.decoderSupportsRefFrameInvalidationAvc(avcDecoder.getName(), prefs.height);
refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(avcDecoder.getName());
if (consecutiveCrashCount % 2 == 1) {
refFrameInvalidationAvc = refFrameInvalidationHevc = false;
LimeLog.warning("Disabling RFI due to previous crash");
}
avcOptimalSlicesPerFrame = MediaCodecHelper.getDecoderOptimalSlicesPerFrame(avcDecoder.getName());
if (directSubmit) {
LimeLog.info("Decoder "+avcDecoder.getName()+" will use direct submit");
@@ -183,9 +257,27 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
if (refFrameInvalidationAvc) {
LimeLog.info("Decoder "+avcDecoder.getName()+" will use reference frame invalidation for AVC");
}
LimeLog.info("Decoder "+avcDecoder.getName()+" wants "+avcOptimalSlicesPerFrame+" slices per frame");
}
if (hevcDecoder != null) {
refFrameInvalidationHevc = MediaCodecHelper.decoderSupportsRefFrameInvalidationHevc(hevcDecoder.getName());
hevcOptimalSlicesPerFrame = MediaCodecHelper.getDecoderOptimalSlicesPerFrame(hevcDecoder.getName());
if (refFrameInvalidationHevc) {
LimeLog.info("Decoder "+avcDecoder.getName()+" will use reference frame invalidation for HEVC");
LimeLog.info("Decoder "+hevcDecoder.getName()+" will use reference frame invalidation for HEVC");
}
LimeLog.info("Decoder "+hevcDecoder.getName()+" wants "+hevcOptimalSlicesPerFrame+" slices per frame");
}
// Use the larger of the two slices per frame preferences
optimalSlicesPerFrame = (byte)Math.max(avcOptimalSlicesPerFrame, hevcOptimalSlicesPerFrame);
LimeLog.info("Requesting "+optimalSlicesPerFrame+" slices per frame");
if (consecutiveCrashCount % 2 == 1) {
refFrameInvalidationAvc = refFrameInvalidationHevc = false;
LimeLog.warning("Disabling RFI due to previous crash");
}
}
@@ -197,15 +289,6 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return avcDecoder != null;
}
public boolean isBlacklistedForFrameRate(int frameRate) {
return avcDecoder != null && MediaCodecHelper.decoderBlacklistedForFrameRate(avcDecoder.getName(), frameRate);
}
public void enableLegacyFrameDropRendering() {
LimeLog.info("Legacy frame drop rendering enabled");
legacyFrameDropRendering = true;
}
public boolean isHevcMain10Hdr10Supported() {
if (hevcDecoder == null) {
return false;
@@ -233,125 +316,32 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return this.videoFormat;
}
@Override
public int setup(int format, int width, int height, int redrawRate) {
this.initialWidth = width;
this.initialHeight = height;
this.videoFormat = format;
this.refreshRate = redrawRate;
String mimeType;
String selectedDecoderName;
if ((videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H264) != 0) {
mimeType = "video/avc";
selectedDecoderName = avcDecoder.getName();
if (avcDecoder == null) {
LimeLog.severe("No available AVC decoder!");
return -1;
}
if (width > 4096 || height > 4096) {
LimeLog.severe("> 4K streaming only supported on HEVC");
return -1;
}
// These fixups only apply to H264 decoders
needsSpsBitstreamFixup = MediaCodecHelper.decoderNeedsSpsBitstreamRestrictions(selectedDecoderName);
needsBaselineSpsHack = MediaCodecHelper.decoderNeedsBaselineSpsHack(selectedDecoderName);
constrainedHighProfile = MediaCodecHelper.decoderNeedsConstrainedHighProfile(selectedDecoderName);
isExynos4 = MediaCodecHelper.isExynos4Device();
if (needsSpsBitstreamFixup) {
LimeLog.info("Decoder "+selectedDecoderName+" needs SPS bitstream restrictions fixup");
}
if (needsBaselineSpsHack) {
LimeLog.info("Decoder "+selectedDecoderName+" needs baseline SPS hack");
}
if (constrainedHighProfile) {
LimeLog.info("Decoder "+selectedDecoderName+" needs constrained high profile");
}
if (isExynos4) {
LimeLog.info("Decoder "+selectedDecoderName+" is on Exynos 4");
}
refFrameInvalidationActive = refFrameInvalidationAvc;
lowLatency = MediaCodecHelper.decoderSupportsLowLatency(avcDecoder, mimeType);
adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(avcDecoder, mimeType);
}
else if ((videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H265) != 0) {
mimeType = "video/hevc";
selectedDecoderName = hevcDecoder.getName();
if (hevcDecoder == null) {
LimeLog.severe("No available HEVC decoder!");
return -2;
}
refFrameInvalidationActive = refFrameInvalidationHevc;
lowLatency = MediaCodecHelper.decoderSupportsLowLatency(hevcDecoder, mimeType);
adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(hevcDecoder, mimeType);
}
else {
// Unknown format
LimeLog.severe("Unknown format");
return -3;
}
// Codecs have been known to throw all sorts of crazy runtime exceptions
// due to implementation problems
try {
videoDecoder = MediaCodec.createByCodecName(selectedDecoderName);
} catch (Exception e) {
e.printStackTrace();
return -4;
}
MediaFormat videoFormat = MediaFormat.createVideoFormat(mimeType, width, height);
private MediaFormat createBaseMediaFormat(String mimeType) {
MediaFormat videoFormat = MediaFormat.createVideoFormat(mimeType, initialWidth, initialHeight);
// Avoid setting KEY_FRAME_RATE on Lollipop and earlier to reduce compatibility risk
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// We use prefs.fps instead of redrawRate here because the low latency hack in Game.java
// may leave us with an odd redrawRate value like 59 or 49 which might cause the decoder
// to puke. To be safe, we'll use the unmodified value.
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, prefs.fps);
videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, refreshRate);
}
// Adaptive playback can also be enabled by the whitelist on pre-KitKat devices
// so we don't fill these pre-KitKat
if (adaptivePlayback && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, width);
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, height);
videoFormat.setInteger(MediaFormat.KEY_MAX_WIDTH, initialWidth);
videoFormat.setInteger(MediaFormat.KEY_MAX_HEIGHT, initialHeight);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && lowLatency) {
videoFormat.setInteger(MediaFormat.KEY_LOW_LATENCY, 1);
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Set the Qualcomm vendor low latency extension if the Android R option is unavailable
if (MediaCodecHelper.decoderSupportsQcomVendorLowLatency(selectedDecoderName)) {
// 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
//
// 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);
}
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(selectedDecoderName)) {
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
}
}
configuredFormat = videoFormat;
LimeLog.info("Configuring with format: "+configuredFormat);
return videoFormat;
}
private boolean tryConfigureDecoder(MediaCodecInfo selectedDecoderInfo, MediaFormat format) {
try {
videoDecoder.configure(videoFormat, renderTarget.getSurface(), null, 0);
videoDecoder = MediaCodec.createByCodecName(selectedDecoderInfo.getName());
LimeLog.info("Configuring with format: "+format);
videoDecoder.configure(format, renderTarget.getSurface(), null, 0);
configuredFormat = format;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// This will contain the actual accepted input format attributes
@@ -375,7 +365,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}, null);
}
LimeLog.info("Using codec "+selectedDecoderName+" for hardware decoding "+mimeType);
LimeLog.info("Using codec "+selectedDecoderInfo.getName()+" for hardware decoding "+format.getString(MediaFormat.KEY_MIME));
// Start the decoder
videoDecoder.start();
@@ -384,9 +374,100 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
legacyInputBuffers = videoDecoder.getInputBuffers();
}
return true;
} catch (Exception e) {
e.printStackTrace();
return -5;
if (videoDecoder != null) {
videoDecoder.release();
videoDecoder = null;
}
return false;
}
}
@Override
public int setup(int format, int width, int height, int redrawRate) {
this.initialWidth = width;
this.initialHeight = height;
this.videoFormat = format;
this.refreshRate = redrawRate;
String mimeType;
MediaCodecInfo selectedDecoderInfo;
if ((videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H264) != 0) {
mimeType = "video/avc";
selectedDecoderInfo = avcDecoder;
if (avcDecoder == null) {
LimeLog.severe("No available AVC decoder!");
return -1;
}
if (width > 4096 || height > 4096) {
LimeLog.severe("> 4K streaming only supported on HEVC");
return -1;
}
// These fixups only apply to H264 decoders
needsSpsBitstreamFixup = MediaCodecHelper.decoderNeedsSpsBitstreamRestrictions(selectedDecoderInfo.getName());
needsBaselineSpsHack = MediaCodecHelper.decoderNeedsBaselineSpsHack(selectedDecoderInfo.getName());
constrainedHighProfile = MediaCodecHelper.decoderNeedsConstrainedHighProfile(selectedDecoderInfo.getName());
isExynos4 = MediaCodecHelper.isExynos4Device();
if (needsSpsBitstreamFixup) {
LimeLog.info("Decoder "+selectedDecoderInfo.getName()+" needs SPS bitstream restrictions fixup");
}
if (needsBaselineSpsHack) {
LimeLog.info("Decoder "+selectedDecoderInfo.getName()+" needs baseline SPS hack");
}
if (constrainedHighProfile) {
LimeLog.info("Decoder "+selectedDecoderInfo.getName()+" needs constrained high profile");
}
if (isExynos4) {
LimeLog.info("Decoder "+selectedDecoderInfo.getName()+" is on Exynos 4");
}
refFrameInvalidationActive = refFrameInvalidationAvc;
}
else if ((videoFormat & MoonBridge.VIDEO_FORMAT_MASK_H265) != 0) {
mimeType = "video/hevc";
selectedDecoderInfo = hevcDecoder;
if (hevcDecoder == null) {
LimeLog.severe("No available HEVC decoder!");
return -2;
}
refFrameInvalidationActive = refFrameInvalidationHevc;
}
else {
// Unknown format
LimeLog.severe("Unknown format");
return -3;
}
adaptivePlayback = MediaCodecHelper.decoderSupportsAdaptivePlayback(selectedDecoderInfo, mimeType);
fusedIdrFrame = MediaCodecHelper.decoderSupportsFusedIdrFrame(selectedDecoderInfo, mimeType);
for (int tryNumber = 0;; tryNumber++) {
LimeLog.info("Decoder configuration try: "+tryNumber);
MediaFormat mediaFormat = createBaseMediaFormat(mimeType);
// This will try low latency options until we find one that works (or we give up).
boolean newFormat = MediaCodecHelper.setDecoderLowLatencyOptions(mediaFormat, selectedDecoderInfo, tryNumber);
if (tryConfigureDecoder(selectedDecoderInfo, mediaFormat)) {
// Success!
break;
}
if (!newFormat) {
// We couldn't even configure a decoder without any low latency options
return -5;
}
}
return 0;
@@ -440,6 +521,66 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
}
@Override
public void doFrame(long frameTimeNanos) {
// Do nothing if we're stopping
if (stopping) {
return;
}
// Don't render unless a new frame is due. This prevents microstutter when streaming
// at a frame rate that doesn't match the display (such as 60 FPS on 120 Hz).
long actualFrameTimeDeltaNs = frameTimeNanos - lastRenderedFrameTimeNanos;
long expectedFrameTimeDeltaNs = 800000000 / refreshRate; // within 80% of the next frame
if (actualFrameTimeDeltaNs >= expectedFrameTimeDeltaNs) {
// Render up to one frame when in frame pacing mode.
//
// NB: Since the queue limit is 2, we won't starve the decoder of output buffers
// by holding onto them for too long. This also ensures we will have that 1 extra
// frame of buffer to smooth over network/rendering jitter.
Integer nextOutputBuffer = outputBufferQueue.poll();
if (nextOutputBuffer != null) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
videoDecoder.releaseOutputBuffer(nextOutputBuffer, frameTimeNanos);
}
else {
videoDecoder.releaseOutputBuffer(nextOutputBuffer, true);
}
lastRenderedFrameTimeNanos = frameTimeNanos;
activeWindowVideoStats.totalFramesRendered++;
} catch (Exception e) {
// This will leak nextOutputBuffer, but there's really nothing else we can do
handleDecoderException(e, null, 0, false);
}
}
}
// Request another callback for next frame
Choreographer.getInstance().postFrameCallback(this);
}
private void startChoreographerThread() {
if (prefs.framePacing != PreferenceConfiguration.FRAME_PACING_BALANCED) {
// Not using Choreographer in this pacing mode
return;
}
// We use a separate thread to avoid any main thread delays from delaying rendering
choreographerHandlerThread = new HandlerThread("Video - Choreographer", Process.THREAD_PRIORITY_DEFAULT + Process.THREAD_PRIORITY_MORE_FAVORABLE);
choreographerHandlerThread.start();
// Start the frame callbacks
choreographerHandler = new Handler(choreographerHandlerThread.getLooper());
choreographerHandler.post(new Runnable() {
@Override
public void run() {
Choreographer.getInstance().postFrameCallback(MediaCodecDecoderRenderer.this);
}
});
}
private void startRendererThread()
{
rendererThread = new Thread() {
@@ -454,35 +595,63 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
long presentationTimeUs = info.presentationTimeUs;
int lastIndex = outIndex;
// Get the last output buffer in the queue
while ((outIndex = videoDecoder.dequeueOutputBuffer(info, 0)) >= 0) {
videoDecoder.releaseOutputBuffer(lastIndex, false);
numFramesOut++;
lastIndex = outIndex;
presentationTimeUs = info.presentationTimeUs;
}
// Render the latest frame now if frame pacing isn't in balanced mode
if (prefs.framePacing != PreferenceConfiguration.FRAME_PACING_BALANCED) {
// Get the last output buffer in the queue
while ((outIndex = videoDecoder.dequeueOutputBuffer(info, 0)) >= 0) {
videoDecoder.releaseOutputBuffer(lastIndex, false);
// Render the last buffer
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (legacyFrameDropRendering) {
// Use a PTS that will cause this frame to be dropped if another comes in within
// the same V-sync period
videoDecoder.releaseOutputBuffer(lastIndex, System.nanoTime());
numFramesOut++;
lastIndex = outIndex;
presentationTimeUs = info.presentationTimeUs;
}
if (prefs.framePacing == PreferenceConfiguration.FRAME_PACING_MAX_SMOOTHNESS ||
prefs.framePacing == PreferenceConfiguration.FRAME_PACING_CAP_FPS) {
// In max smoothness or cap FPS mode, we want to never drop frames
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Use a PTS that will cause this frame to never be dropped
videoDecoder.releaseOutputBuffer(lastIndex, 0);
}
else {
videoDecoder.releaseOutputBuffer(lastIndex, true);
}
}
else {
// Use a PTS that will cause this frame to never be dropped if frame dropping
// is disabled
videoDecoder.releaseOutputBuffer(lastIndex, 0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// Use a PTS that will cause this frame to be dropped if another comes in within
// the same V-sync period
videoDecoder.releaseOutputBuffer(lastIndex, System.nanoTime());
}
else {
videoDecoder.releaseOutputBuffer(lastIndex, true);
}
}
activeWindowVideoStats.totalFramesRendered++;
}
else {
videoDecoder.releaseOutputBuffer(lastIndex, true);
// For balanced frame pacing case, the Choreographer callback will handle rendering.
// We just put all frames into the output buffer queue and let it handle things.
// Discard the oldest buffer if we've exceeded our limit.
//
// NB: We have to do this on the producer side because the consumer may not
// run for a while (if there is a huge mismatch between stream FPS and display
// refresh rate).
if (outputBufferQueue.size() == OUTPUT_BUFFER_QUEUE_LIMIT) {
videoDecoder.releaseOutputBuffer(outputBufferQueue.take(), false);
}
// Add this buffer
outputBufferQueue.add(lastIndex);
}
activeWindowVideoStats.totalFramesRendered++;
// Add delta time to the totals (excluding probable outliers)
long delta = MediaCodecHelper.getMonotonicMillis() - (presentationTimeUs / 1000);
long delta = SystemClock.uptimeMillis() - (presentationTimeUs / 1000);
if (delta >= 0 && delta < 1000) {
activeWindowVideoStats.decoderTimeMs += delta;
if (!USE_FRAME_RENDER_TIME) {
@@ -517,7 +686,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
int index = -1;
long startTime;
startTime = MediaCodecHelper.getMonotonicMillis();
startTime = SystemClock.uptimeMillis();
try {
while (index < 0 && !stopping) {
@@ -528,7 +697,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
return MediaCodec.INFO_TRY_AGAIN_LATER;
}
int deltaMs = (int)(MediaCodecHelper.getMonotonicMillis() - startTime);
int deltaMs = (int)(SystemClock.uptimeMillis() - startTime);
if (deltaMs >= 20) {
LimeLog.warning("Dequeue input buffer ran long: " + deltaMs + " ms");
@@ -554,6 +723,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
@Override
public void start() {
startRendererThread();
startChoreographerThread();
}
// !!! May be called even if setup()/start() fails !!!
@@ -565,6 +735,20 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
if (rendererThread != null) {
rendererThread.interrupt();
}
// Post a quit message to the Choreographer looper (if we have one)
if (choreographerHandler != null) {
choreographerHandler.post(new Runnable() {
@Override
public void run() {
// Don't allow any further messages to be queued
choreographerHandlerThread.quit();
// Deregister the frame callback (if registered)
Choreographer.getInstance().removeFrameCallback(MediaCodecDecoderRenderer.this);
}
});
}
}
@Override
@@ -572,10 +756,31 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// May be called already, but we'll call it now to be safe
prepareForStop();
// Wait for the Choreographer looper to shut down (if we have one)
if (choreographerHandlerThread != null) {
try {
choreographerHandlerThread.join();
} 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();
}
}
// Wait for the renderer thread to shut down
try {
rendererThread.join();
} catch (InterruptedException ignored) { }
} 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();
}
}
@Override
@@ -583,6 +788,11 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
videoDecoder.release();
}
@Override
public void setHdrMode(boolean enabled) {
// TODO: Set HDR metadata?
}
private boolean queueInputBuffer(int inputBufferIndex, int offset, int length, long timestampUs, int codecFlags) {
try {
videoDecoder.queueInputBuffer(inputBufferIndex,
@@ -638,7 +848,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
@SuppressWarnings("deprecation")
@Override
public int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
int frameNumber, long receiveTimeMs) {
int frameNumber, int frameType, long receiveTimeMs, long enqueueTimeMs) {
if (stopping) {
// Don't bother if we're stopping
return MoonBridge.DR_OK;
@@ -674,17 +884,18 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
float decodeTimeMs = (float)lastTwo.decoderTimeMs / lastTwo.totalFramesReceived;
String perfText = context.getString(
R.string.perf_overlay_text,
initialWidth + "x" + initialHeight,
decoder,
fps.totalFps,
fps.receivedFps,
fps.renderedFps,
(float)lastTwo.framesLost / lastTwo.totalFrames * 100,
((float)lastTwo.totalTimeMs / lastTwo.totalFramesReceived) - decodeTimeMs,
decodeTimeMs);
perfListener.onPerfUpdate(perfText);
long rttInfo = MoonBridge.getEstimatedRttInfo();
StringBuilder sb = new StringBuilder();
sb.append(context.getString(R.string.perf_overlay_streamdetails, initialWidth + "x" + initialHeight, fps.totalFps)).append('\n');
sb.append(context.getString(R.string.perf_overlay_decoder, decoder)).append('\n');
sb.append(context.getString(R.string.perf_overlay_incomingfps, fps.receivedFps)).append('\n');
sb.append(context.getString(R.string.perf_overlay_renderingfps, fps.renderedFps)).append('\n');
sb.append(context.getString(R.string.perf_overlay_netdrops,
(float)lastTwo.framesLost / lastTwo.totalFrames * 100)).append('\n');
sb.append(context.getString(R.string.perf_overlay_netlatency,
(int)(rttInfo >> 32), (int)rttInfo)).append('\n');
sb.append(context.getString(R.string.perf_overlay_dectime, decodeTimeMs));
perfListener.onPerfUpdate(sb.toString());
}
globalVideoStats.add(activeWindowVideoStats);
@@ -693,27 +904,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
activeWindowVideoStats.measurementStartTimestamp = SystemClock.uptimeMillis();
}
activeWindowVideoStats.totalFramesReceived++;
activeWindowVideoStats.totalFrames++;
int inputBufferIndex;
ByteBuffer buf;
long timestampUs = System.nanoTime() / 1000;
if (!FRAME_RENDER_TIME_ONLY) {
// Count time from first packet received to decode start
activeWindowVideoStats.totalTimeMs += (timestampUs / 1000) - receiveTimeMs;
}
if (timestampUs <= lastTimestampUs) {
// We can't submit multiple buffers with the same timestamp
// so bump it up by one before queuing
timestampUs = lastTimestampUs + 1;
}
lastTimestampUs = timestampUs;
long timestampUs;
int codecFlags = 0;
// H264 SPS
@@ -853,9 +1046,9 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
numPpsIn++;
// If this is the first CSD blob or we aren't supporting
// adaptive playback, we will submit the CSD blob in a
// fused IDR frames, we will submit the CSD blob in a
// separate input buffer.
if (!submittedCsd || !adaptivePlayback) {
if (!submittedCsd || !fusedIdrFrame) {
inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) {
// We're being torn down now
@@ -879,6 +1072,7 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// This is the CSD blob
codecFlags |= MediaCodec.BUFFER_FLAG_CODEC_CONFIG;
timestampUs = 0;
}
else {
// Batch this to submit together with the next I-frame
@@ -892,6 +1086,16 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
}
else {
activeWindowVideoStats.totalFramesReceived++;
activeWindowVideoStats.totalFrames++;
if (!FRAME_RENDER_TIME_ONLY) {
// Count time from first packet received to enqueue time as receive time
// We will count DU queue time as part of decoding, because it is directly
// caused by a slow decoder.
activeWindowVideoStats.totalTimeMs += enqueueTimeMs - receiveTimeMs;
}
inputBufferIndex = dequeueInputBuffer();
if (inputBufferIndex < 0) {
// We're being torn down now
@@ -917,6 +1121,22 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
submitCsdNextCall = false;
}
if (frameType == MoonBridge.FRAME_TYPE_IDR) {
codecFlags |= MediaCodec.BUFFER_FLAG_SYNC_FRAME;
}
timestampUs = enqueueTimeMs * 1000;
if (timestampUs <= lastTimestampUs) {
// We can't submit multiple buffers with the same timestamp
// so bump it up by one before queuing
timestampUs = lastTimestampUs + 1;
}
lastTimestampUs = timestampUs;
numFramesIn++;
}
if (decodeUnitLength > buf.limit() - buf.position()) {
@@ -986,16 +1206,15 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
// Queue the new SPS
return queueInputBuffer(inputIndex,
0, inputBuffer.position(),
System.nanoTime() / 1000,
MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
0, MediaCodec.BUFFER_FLAG_CODEC_CONFIG);
}
@Override
public int getCapabilities() {
int capabilities = 0;
// We always request 4 slices per frame to speed up decoding on some hardware
capabilities |= MoonBridge.CAPABILITY_SLICES_PER_FRAME((byte) 4);
// Request the optimal number of slices per frame for this decoder
capabilities |= MoonBridge.CAPABILITY_SLICES_PER_FRAME(optimalSlicesPerFrame);
// Enable reference frame invalidation on supported hardware
if (refFrameInvalidationAvc) {
@@ -1062,8 +1281,31 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
}
private String generateText(MediaCodecDecoderRenderer renderer, Exception originalException, ByteBuffer currentBuffer, int currentCodecFlags) {
String str = "";
String str;
if (renderer.numVpsIn == 0 && renderer.numSpsIn == 0 && renderer.numPpsIn == 0) {
str = "PreSPSError";
}
else if (renderer.numSpsIn > 0 && renderer.numPpsIn == 0) {
str = "PrePPSError";
}
else if (renderer.numPpsIn > 0 && renderer.numFramesIn == 0) {
str = "PreIFrameError";
}
else if (renderer.numFramesIn > 0 && renderer.outputFormat == null) {
str = "PreOutputConfigError";
}
else if (renderer.outputFormat != null && renderer.numFramesOut == 0) {
str = "PreOutputError";
}
else if (renderer.numFramesOut <= renderer.refreshRate * 30) {
str = "EarlyOutputError";
}
else {
str = "ErrorWhileStreaming";
}
str += ": 1\n";
str += "Format: "+String.format("%x", renderer.videoFormat)+"\n";
str += "AVC Decoder: "+((renderer.avcDecoder != null) ? renderer.avcDecoder.getName():"(none)")+"\n";
str += "HEVC Decoder: "+((renderer.hevcDecoder != null) ? renderer.hevcDecoder.getName():"(none)")+"\n";
@@ -1097,20 +1339,37 @@ public class MediaCodecDecoderRenderer extends VideoDecoderRenderer {
str += "Adaptive playback: "+renderer.adaptivePlayback+"\n";
str += "GL Renderer: "+renderer.glRenderer+"\n";
str += "Build fingerprint: "+Build.FINGERPRINT+"\n";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
str += "SOC: "+Build.SOC_MANUFACTURER+" - "+Build.SOC_MODEL+"\n";
str += "Performance class: "+Build.VERSION.MEDIA_PERFORMANCE_CLASS+"\n";
str += "Vendor params: ";
List<String> params = renderer.videoDecoder.getSupportedVendorParameters();
if (params.isEmpty()) {
str += "NONE";
}
else {
for (String param : params) {
str += param + " ";
}
}
str += "\n";
}
str += "Foreground: "+renderer.foreground+"\n";
str += "Consecutive crashes: "+renderer.consecutiveCrashCount+"\n";
str += "RFI active: "+renderer.refFrameInvalidationActive+"\n";
str += "Using modern SPS patching: "+(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)+"\n";
str += "Low latency mode: "+renderer.lowLatency+"\n";
str += "Fused IDR frames: "+renderer.fusedIdrFrame+"\n";
str += "Video dimensions: "+renderer.initialWidth+"x"+renderer.initialHeight+"\n";
str += "FPS target: "+renderer.refreshRate+"\n";
str += "Bitrate: "+renderer.prefs.bitrate+" Kbps \n";
str += "In stats: "+renderer.numVpsIn+", "+renderer.numSpsIn+", "+renderer.numPpsIn+"\n";
str += "CSD stats: "+renderer.numVpsIn+", "+renderer.numSpsIn+", "+renderer.numPpsIn+"\n";
str += "Frames in-out: "+renderer.numFramesIn+", "+renderer.numFramesOut+"\n";
str += "Total frames received: "+renderer.globalVideoStats.totalFramesReceived+"\n";
str += "Total frames rendered: "+renderer.globalVideoStats.totalFramesRendered+"\n";
str += "Frame losses: "+renderer.globalVideoStats.framesLost+" in "+renderer.globalVideoStats.frameLossEvents+" loss events\n";
str += "Average end-to-end client latency: "+renderer.getAverageEndToEndLatency()+"ms\n";
str += "Average hardware decoder latency: "+renderer.getAverageDecoderLatency()+"ms\n";
str += "Frame pacing mode: "+renderer.prefs.framePacing+"\n";
if (currentBuffer != null) {
str += "Current buffer: ";
@@ -18,9 +18,11 @@ import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaFormat;
import android.os.Build;
import com.limelight.LimeLog;
import com.limelight.preferences.PreferenceConfiguration;
public class MediaCodecHelper {
@@ -36,9 +38,13 @@ public class MediaCodecHelper {
private static final List<String> whitelistedHevcDecoders;
private static final List<String> refFrameInvalidationAvcPrefixes;
private static final List<String> refFrameInvalidationHevcPrefixes;
private static final List<String> blacklisted49FpsDecoderPrefixes;
private static final List<String> blacklisted59FpsDecoderPrefixes;
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;
public static final boolean IS_EMULATOR = Build.HARDWARE.equals("ranchu") || Build.HARDWARE.equals("cheets");
private static boolean isLowEndSnapdragon = false;
private static boolean isAdreno620 = false;
@@ -78,7 +84,7 @@ public class MediaCodecHelper {
// Blacklist software decoders that don't support H264 high profile,
// but exclude the official AOSP and CrOS emulator from this restriction.
if (!Build.HARDWARE.equals("ranchu") && !Build.HARDWARE.equals("cheets")) {
if (!IS_EMULATOR) {
blacklistedDecoderPrefixes.add("omx.google");
blacklistedDecoderPrefixes.add("AVCDecoder");
}
@@ -113,7 +119,7 @@ public class MediaCodecHelper {
// if adaptive playback was enabled so let's avoid it to be safe.
blacklistedAdaptivePlaybackPrefixes.add("omx.intel");
// The MediaTek decoder crashes at 1080p when adaptive playback is enabled
// on some Android TV devices with H.265 only.
// on some Android TV devices with HEVC only.
blacklistedAdaptivePlaybackPrefixes.add("omx.mtk");
constrainedHighProfilePrefixes = new LinkedList<>();
@@ -131,21 +137,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");
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.
@@ -155,11 +166,23 @@ 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.
//
// 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");
}
// Realtek SoCs are used inside many Android TV devices and can only do 4K60 with HEVC.
// We'll enable those HEVC decoders by default and see if anything breaks.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
whitelistedHevcDecoders.add("omx.realtek");
}
// These theoretically have good HEVC decoding capabilities (potentially better than
// their AVC decoders), but haven't been tested enough
//whitelistedHevcDecoders.add("omx.rk");
@@ -180,21 +203,15 @@ public class MediaCodecHelper {
}
static {
blacklisted49FpsDecoderPrefixes = new LinkedList<>();
blacklisted59FpsDecoderPrefixes = new LinkedList<>();
useFourSlicesPrefixes = new LinkedList<>();
// We see a bunch of crashes on MediaTek Android TVs running
// at 49 FPS (PAL 50 Hz - 1). Blacklist this frame rate for
// these devices and hope they fix it in Pie.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
blacklisted49FpsDecoderPrefixes.add("omx.mtk");
// 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");
// 59 FPS also seems to crash on the Sony Bravia TV ATV3 model.
// Blacklist that frame rate on these devices too.
if (Build.DEVICE.startsWith("BRAVIA_ATV3")) {
blacklisted59FpsDecoderPrefixes.add("omx.mtk");
}
}
// Old Qualcomm decoders are detected at runtime
}
static {
@@ -204,6 +221,27 @@ public class MediaCodecHelper {
qualcommDecoderPrefixes.add("c2.qti");
}
static {
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) {
return glRenderer.toLowerCase().contains("powervr");
}
@@ -262,6 +300,19 @@ 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")) {
whitelistedHevcDecoders.add("omx.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");
}
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
@@ -307,6 +358,9 @@ public class MediaCodecHelper {
}
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
@@ -346,11 +400,7 @@ public class MediaCodecHelper {
return false;
}
public static long getMonotonicMillis() {
return System.nanoTime() / 1000000L;
}
public static boolean decoderSupportsLowLatency(MediaCodecInfo decoderInfo, String mimeType) {
private static boolean decoderSupportsAndroidRLowLatency(MediaCodecInfo decoderInfo, String mimeType) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
if (decoderInfo.getCapabilitiesForType(mimeType).isFeatureSupported(CodecCapabilities.FEATURE_LowLatency)) {
@@ -366,7 +416,7 @@ public class MediaCodecHelper {
return false;
}
public static boolean decoderSupportsMaxOperatingRate(String decoderName) {
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)
// but that will actually result in the decoder crashing if it can't satisfy
@@ -381,6 +431,115 @@ public class MediaCodecHelper {
!isAdreno620;
}
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;
}
}
if (tryNumber < 2) {
// MediaTek decoders don't use vendor-defined keys for low latency mode. Instead, they have a modified
// version of AOSP's ACodec.cpp which supports the "vdec-lowlatency" option. This option is passed down
// to the decoder as OMX.MTK.index.param.video.LowLatencyDecode.
//
// This option is also plumbed for Amazon Amlogic-based devices like the Fire TV 3. Not only does it
// reduce latency on Amlogic, it fixes the HEVC bug that causes the decoder to not output any frames.
// 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
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;
}
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())) {
if (tryNumber < 3) {
// Exynos low latency option for H.264 decoder
videoFormat.setInteger("vendor.rtc-ext-dec-low-latency.enable", 1);
setNewOption = true;
}
}
else if (isDecoderInList(amlogicDecoderPrefixes, decoderInfo.getName())) {
if (tryNumber < 3) {
// 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) {
// Possibly enable adaptive playback on KitKat and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
@@ -406,13 +565,6 @@ public class MediaCodecHelper {
return false;
}
public static boolean decoderSupportsQcomVendorLowLatency(String decoderName) {
// MediaCodec vendor extension support was introduced in Android 8.0:
// https://cs.android.com/android/_/android/platform/frameworks/av/+/01c10f8cdcd58d1e7025f426a72e6e75ba5d7fc2
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
isDecoderInList(qualcommDecoderPrefixes, decoderName);
}
public static boolean decoderNeedsConstrainedHighProfile(String decoderName) {
return isDecoderInList(constrainedHighProfilePrefixes, decoderName);
}
@@ -429,15 +581,14 @@ public class MediaCodecHelper {
return isDecoderInList(baselineProfileHackPrefixes, decoderName);
}
public static boolean decoderBlacklistedForFrameRate(String decoderName, int fps) {
if (fps == 49) {
return isDecoderInList(blacklisted49FpsDecoderPrefixes, decoderName);
}
else if (fps == 59) {
return isDecoderInList(blacklisted59FpsDecoderPrefixes, 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 {
return false;
// 1 slice per frame produces the optimal encoding efficiency
return 1;
}
}
@@ -460,21 +611,7 @@ public class MediaCodecHelper {
return isDecoderInList(refFrameInvalidationHevcPrefixes, decoderName);
}
public static boolean decoderIsWhitelistedForHevc(String decoderName, boolean meteredData) {
// 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(String decoderName, boolean meteredData, PreferenceConfiguration prefs) {
// 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.
@@ -495,9 +632,10 @@ public class MediaCodecHelper {
// 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.
// 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) {
if (meteredData || (prefs.width == 3840 && prefs.height == 2160)) {
LimeLog.info("Selected deprioritized decoder");
return true;
}
@@ -564,13 +702,6 @@ public class MediaCodecHelper {
if (codecInfo.isEncoder()) {
continue;
}
// Skip compatibility aliases on Q+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (codecInfo.isAlias()) {
continue;
}
}
// Check for preferred decoders
if (preferredDecoder.equalsIgnoreCase(codecInfo.getName())) {
@@ -586,7 +717,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 (codecInfo.isSoftwareOnly()) {
if (!IS_EMULATOR && codecInfo.isSoftwareOnly()) {
LimeLog.info("Skipping software-only decoder: "+codecInfo.getName());
return true;
}
@@ -656,43 +787,57 @@ public class MediaCodecHelper {
// and we want to be sure all callers are handling this possibility
@SuppressWarnings("RedundantThrows")
private static MediaCodecInfo findKnownSafeDecoder(String mimeType, int requiredProfile) throws Exception {
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
// Skip encoders
if (codecInfo.isEncoder()) {
continue;
}
// Skip compatibility aliases on Q+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (codecInfo.isAlias()) {
// Some devices (Exynos devces, at least) have two sets of decoders.
// The first set of decoders are C2 which do not support FEATURE_LowLatency,
// but the second set of OMX decoders do support FEATURE_LowLatency. We want
// to pick the OMX decoders despite the fact that C2 is listed first.
// On some Qualcomm devices (like Pixel 4), there are separate low latency decoders
// (like c2.qti.hevc.decoder.low_latency) that advertise FEATURE_LowLatency while
// the standard ones (like c2.qti.hevc.decoder) do not. Like Exynos, the decoders
// with FEATURE_LowLatency support are listed after the standard ones.
for (int i = 0; i < 2; i++) {
for (MediaCodecInfo codecInfo : getMediaCodecList()) {
// Skip encoders
if (codecInfo.isEncoder()) {
continue;
}
}
// Find a decoder that supports the requested video format
for (String mime : codecInfo.getSupportedTypes()) {
if (mime.equalsIgnoreCase(mimeType)) {
LimeLog.info("Examining decoder capabilities of "+codecInfo.getName());
// Skip blacklisted codecs
if (isCodecBlacklisted(codecInfo)) {
// Skip compatibility aliases on Q+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (codecInfo.isAlias()) {
continue;
}
}
CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime);
// Find a decoder that supports the requested video format
for (String mime : codecInfo.getSupportedTypes()) {
if (mime.equalsIgnoreCase(mimeType)) {
LimeLog.info("Examining decoder capabilities of " + codecInfo.getName() + " (round " + (i + 1) + ")");
if (requiredProfile != -1) {
for (CodecProfileLevel profile : caps.profileLevels) {
if (profile.profile == requiredProfile) {
LimeLog.info("Decoder " + codecInfo.getName() + " supports required profile");
return codecInfo;
}
// Skip blacklisted codecs
if (isCodecBlacklisted(codecInfo)) {
continue;
}
LimeLog.info("Decoder " + codecInfo.getName() + " does NOT support required profile");
}
else {
return codecInfo;
CodecCapabilities caps = codecInfo.getCapabilitiesForType(mime);
if (i == 0 && !decoderSupportsAndroidRLowLatency(codecInfo, mime)) {
LimeLog.info("Skipping decoder that lacks FEATURE_LowLatency for round 1");
continue;
}
if (requiredProfile != -1) {
for (CodecProfileLevel profile : caps.profileLevels) {
if (profile.profile == requiredProfile) {
LimeLog.info("Decoder " + codecInfo.getName() + " supports required profile");
return codecInfo;
}
}
LimeLog.info("Decoder " + codecInfo.getName() + " does NOT support required profile");
} else {
return codecInfo;
}
}
}
}
@@ -5,8 +5,6 @@ import java.io.OutputStream;
import java.io.StringReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashSet;
import java.util.LinkedList;
@@ -49,8 +47,7 @@ public class ComputerManagerService extends Service {
private static final int APPLIST_POLLING_PERIOD_MS = 30000;
private static final int APPLIST_FAILED_POLLING_RETRY_MS = 2000;
private static final int MDNS_QUERY_PERIOD_MS = 1000;
private static final int FAST_POLL_TIMEOUT = 1000;
private static final int OFFLINE_POLL_TRIES = 5;
private static final int OFFLINE_POLL_TRIES = 3;
private static final int INITIAL_POLL_TRIES = 2;
private static final int EMPTY_LIST_THRESHOLD = 3;
private static final int POLL_DATA_TTL_MS = 30000;
@@ -232,7 +229,13 @@ public class ComputerManagerService extends Service {
// Wait for the bind notification
discoveryServiceConnection.wait(1000);
}
} catch (InterruptedException ignored) {
} 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();
}
}
}
@@ -241,11 +244,18 @@ public class ComputerManagerService extends Service {
while (activePolls.get() != 0) {
try {
Thread.sleep(250);
} catch (InterruptedException ignored) {}
} 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();
}
}
}
public boolean addComputerBlocking(ComputerDetails fakeDetails) {
public boolean addComputerBlocking(ComputerDetails fakeDetails) throws InterruptedException {
return ComputerManagerService.this.addComputerBlocking(fakeDetails);
}
@@ -399,9 +409,18 @@ public class ComputerManagerService extends Service {
details.ipv6Address = computer.getIpv6Address().getHostAddress();
}
// Kick off a serverinfo poll on this machine
if (!addComputerBlocking(details)) {
LimeLog.warning("Auto-discovered PC failed to respond: "+details);
try {
// Kick off a blocking serverinfo poll on this machine
if (!addComputerBlocking(details)) {
LimeLog.warning("Auto-discovered PC failed to respond: "+details);
}
} 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();
}
}
@@ -449,28 +468,25 @@ public class ComputerManagerService extends Service {
}
}
public boolean addComputerBlocking(ComputerDetails fakeDetails) {
public boolean addComputerBlocking(ComputerDetails fakeDetails) throws InterruptedException {
// Block while we try to fill the details
try {
// We cannot use runPoll() here because it will attempt to persist the state of the machine
// in the database, which would be bad because we don't have our pinned cert loaded yet.
if (pollComputer(fakeDetails)) {
// See if we have record of this PC to pull its pinned cert
synchronized (pollingTuples) {
for (PollingTuple tuple : pollingTuples) {
if (tuple.computer.uuid.equals(fakeDetails.uuid)) {
fakeDetails.serverCert = tuple.computer.serverCert;
break;
}
// We cannot use runPoll() here because it will attempt to persist the state of the machine
// in the database, which would be bad because we don't have our pinned cert loaded yet.
if (pollComputer(fakeDetails)) {
// See if we have record of this PC to pull its pinned cert
synchronized (pollingTuples) {
for (PollingTuple tuple : pollingTuples) {
if (tuple.computer.uuid.equals(fakeDetails.uuid)) {
fakeDetails.serverCert = tuple.computer.serverCert;
break;
}
}
// Poll again, possibly with the pinned cert, to get accurate pairing information.
// This will insert the host into the database too.
runPoll(fakeDetails, true, 0);
}
} catch (InterruptedException e) {
return false;
// Poll again, possibly with the pinned cert, to get accurate pairing information.
// This will insert the host into the database too.
runPoll(fakeDetails, true, 0);
}
// If the machine is reachable, it was successful
@@ -528,11 +544,6 @@ public class ComputerManagerService extends Service {
}
private ComputerDetails tryPollIp(ComputerDetails details, String address) {
// Fast poll this address first to determine if we can connect at the TCP layer
if (!fastPollIp(address)) {
return null;
}
try {
NvHTTP http = new NvHTTP(address, idManager.getUniqueId(), details.serverCert,
PlatformBinding.getCryptoProvider(ComputerManagerService.this));
@@ -551,146 +562,140 @@ public class ComputerManagerService extends Service {
return null;
}
// Set the new active address
newDetails.activeAddress = address;
return newDetails;
} catch (XmlPullParserException | IOException e) {
} catch (XmlPullParserException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
return null;
}
}
// Just try to establish a TCP connection to speculatively detect a running
// GFE server
private boolean fastPollIp(String address) {
if (address == null) {
// Don't bother if our address is null
return false;
private static class ParallelPollTuple {
public String address;
public ComputerDetails existingDetails;
public boolean complete;
public Thread pollingThread;
public ComputerDetails returnedDetails;
public ParallelPollTuple(String address, ComputerDetails existingDetails) {
this.address = address;
this.existingDetails = existingDetails;
}
Socket s = new Socket();
try {
s.connect(new InetSocketAddress(address, NvHTTP.HTTPS_PORT), FAST_POLL_TIMEOUT);
s.close();
return true;
} catch (IOException e) {
return false;
public void interrupt() {
if (pollingThread != null) {
pollingThread.interrupt();
}
}
}
private void startFastPollThread(final String address, final boolean[] info) {
Thread t = new Thread() {
private void startParallelPollThread(ParallelPollTuple tuple, HashSet<String> 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)) {
tuple.complete = true;
tuple.returnedDetails = null;
return;
}
tuple.pollingThread = new Thread() {
@Override
public void run() {
boolean pollRes = fastPollIp(address);
ComputerDetails details = tryPollIp(tuple.existingDetails, tuple.address);
synchronized (info) {
info[0] = true; // Done
info[1] = pollRes; // Polling result
synchronized (tuple) {
tuple.complete = true; // Done
tuple.returnedDetails = details; // Polling result
info.notify();
tuple.notify();
}
}
};
t.setName("Fast Poll - "+address);
t.start();
tuple.pollingThread.setName("Parallel Poll - "+tuple.address+" - "+tuple.existingDetails.name);
tuple.pollingThread.start();
}
private String fastPollPc(final String localAddress, final String remoteAddress, final String manualAddress, final String ipv6Address) throws InterruptedException {
final boolean[] remoteInfo = new boolean[2];
final boolean[] localInfo = new boolean[2];
final boolean[] manualInfo = new boolean[2];
final boolean[] ipv6Info = new boolean[2];
private ComputerDetails parallelPollPc(ComputerDetails details) throws InterruptedException {
ParallelPollTuple localInfo = new ParallelPollTuple(details.localAddress, details);
ParallelPollTuple manualInfo = new ParallelPollTuple(details.manualAddress, details);
ParallelPollTuple remoteInfo = new ParallelPollTuple(details.remoteAddress, details);
ParallelPollTuple ipv6Info = new ParallelPollTuple(details.ipv6Address, details);
startFastPollThread(localAddress, localInfo);
startFastPollThread(remoteAddress, remoteInfo);
startFastPollThread(manualAddress, manualInfo);
startFastPollThread(ipv6Address, ipv6Info);
// These must be started in order of precedence for the deduplication algorithm
// to result in the correct behavior.
HashSet<String> uniqueAddresses = new HashSet<>();
startParallelPollThread(localInfo, uniqueAddresses);
startParallelPollThread(manualInfo, uniqueAddresses);
startParallelPollThread(remoteInfo, uniqueAddresses);
startParallelPollThread(ipv6Info, uniqueAddresses);
// Check local first
synchronized (localInfo) {
while (!localInfo[0]) {
localInfo.wait(500);
try {
// Check local first
synchronized (localInfo) {
while (!localInfo.complete) {
localInfo.wait();
}
if (localInfo.returnedDetails != null) {
localInfo.returnedDetails.activeAddress = localInfo.address;
return localInfo.returnedDetails;
}
}
if (localInfo[1]) {
return localAddress;
}
}
// Now manual
synchronized (manualInfo) {
while (!manualInfo.complete) {
manualInfo.wait();
}
// Now manual
synchronized (manualInfo) {
while (!manualInfo[0]) {
manualInfo.wait(500);
if (manualInfo.returnedDetails != null) {
manualInfo.returnedDetails.activeAddress = manualInfo.address;
return manualInfo.returnedDetails;
}
}
if (manualInfo[1]) {
return manualAddress;
}
}
// Now remote IPv4
synchronized (remoteInfo) {
while (!remoteInfo.complete) {
remoteInfo.wait();
}
// Now remote IPv4
synchronized (remoteInfo) {
while (!remoteInfo[0]) {
remoteInfo.wait(500);
if (remoteInfo.returnedDetails != null) {
remoteInfo.returnedDetails.activeAddress = remoteInfo.address;
return remoteInfo.returnedDetails;
}
}
if (remoteInfo[1]) {
return remoteAddress;
}
}
// Now global IPv6
synchronized (ipv6Info) {
while (!ipv6Info.complete) {
ipv6Info.wait();
}
// Now global IPv6
synchronized (ipv6Info) {
while (!ipv6Info[0]) {
ipv6Info.wait(500);
}
if (ipv6Info[1]) {
return ipv6Address;
if (ipv6Info.returnedDetails != null) {
ipv6Info.returnedDetails.activeAddress = ipv6Info.address;
return ipv6Info.returnedDetails;
}
}
} finally {
// Stop any further polling if we've found a working address or we've been
// interrupted by an attempt to stop polling.
localInfo.interrupt();
manualInfo.interrupt();
remoteInfo.interrupt();
ipv6Info.interrupt();
}
return null;
}
private boolean pollComputer(ComputerDetails details) throws InterruptedException {
ComputerDetails polledDetails;
// Do a TCP-level connection to the HTTP server to see if it's listening.
// Do not write this address to details.activeAddress because:
// a) it's only a candidate and may be wrong (multiple PCs behind a single router)
// b) if it's null, it will be unexpectedly nulling the activeAddress of a possibly online PC
LimeLog.info("Starting fast poll for "+details.name+" ("+details.localAddress +", "+details.remoteAddress +", "+details.manualAddress+", "+details.ipv6Address+")");
String candidateAddress = fastPollPc(details.localAddress, details.remoteAddress, details.manualAddress, details.ipv6Address);
LimeLog.info("Fast poll for "+details.name+" returned candidate address: "+candidateAddress);
// If no connection could be established to either IP address, there's nothing we can do
if (candidateAddress == null) {
return false;
}
// Try using the active address from fast-poll
polledDetails = tryPollIp(details, candidateAddress);
if (polledDetails == null) {
// If that failed, try all unique addresses except what we've
// already tried
HashSet<String> uniqueAddresses = new HashSet<>();
uniqueAddresses.add(details.localAddress);
uniqueAddresses.add(details.manualAddress);
uniqueAddresses.add(details.remoteAddress);
uniqueAddresses.add(details.ipv6Address);
for (String addr : uniqueAddresses) {
if (addr == null || addr.equals(candidateAddress)) {
continue;
}
polledDetails = tryPollIp(details, addr);
if (polledDetails != null) {
break;
}
}
}
// Poll all addresses in parallel to speed up the process
LimeLog.info("Starting parallel poll for "+details.name+" ("+details.localAddress +", "+details.remoteAddress +", "+details.manualAddress+", "+details.ipv6Address+")");
ComputerDetails polledDetails = parallelPollPc(details);
LimeLog.info("Parallel poll for "+details.name+" returned address: "+details.activeAddress);
if (polledDetails != null) {
details.update(polledDetails);
@@ -128,6 +128,13 @@ public class CachedAppAssetLoader {
try {
Thread.sleep((int) (1000 + (Math.random() * 500)));
} 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();
return null;
}
}
@@ -15,6 +15,9 @@ public class ConnectionContext {
// This is the version quad from the appversion tag of /serverinfo
public String serverAppVersion;
public String serverGfeVersion;
// This is the sessionUrl0 tag from /resume and /launch
public String rtspSessionUrl;
public int negotiatedWidth, negotiatedHeight;
public boolean negotiatedHdr;
@@ -122,7 +122,7 @@ public class NvConnection {
}
else if ((context.streamConfig.getWidth() > 4096 || context.streamConfig.getHeight() > 4096) &&
!context.streamConfig.getHevcSupported()) {
context.connListener.displayMessage("Your streaming device must support H.265 to stream at resolutions above 4K.");
context.connListener.displayMessage("Your streaming device must support HEVC to stream at resolutions above 4K.");
return false;
}
else if (context.streamConfig.getHeight() >= 2160 && !h.supports4K(serverInfo)) {
@@ -275,7 +275,7 @@ public class NvConnection {
synchronized (MoonBridge.class) {
MoonBridge.setupBridge(videoDecoderRenderer, audioRenderer, connectionListener);
int ret = MoonBridge.startConnection(context.serverAddress,
context.serverAppVersion, context.serverGfeVersion,
context.serverAppVersion, context.serverGfeVersion, context.rtspSessionUrl,
context.negotiatedWidth, context.negotiatedHeight,
context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(),
context.streamConfig.getMaxPacketSize(),
@@ -284,6 +284,7 @@ public class NvConnection {
context.negotiatedHdr,
context.streamConfig.getHevcBitratePercentageMultiplier(),
context.streamConfig.getClientRefreshRateX100(),
context.streamConfig.getEncryptionFlags(),
context.riKey.getEncoded(), ib.array(),
context.videoCapabilities);
if (ret != 0) {
@@ -310,7 +311,14 @@ public class NvConnection {
MoonBridge.sendMousePosition(x, y, referenceWidth, referenceHeight);
}
}
public void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight)
{
if (!isMonkey) {
MoonBridge.sendMouseMoveAsMousePosition(deltaX, deltaY, referenceWidth, referenceHeight);
}
}
public void sendMouseButtonDown(final byte mouseButton)
{
if (!isMonkey) {
@@ -366,6 +374,12 @@ public class NvConnection {
}
}
public void sendUtf8Text(final String text) {
if (!isMonkey) {
MoonBridge.sendUtf8Text(text);
}
}
public static String findExternalAddressForMdns(String stunHostname, int stunPort) {
return MoonBridge.findExternalAddressIP4(stunHostname, stunPort);
}
@@ -13,4 +13,6 @@ public interface NvConnectionListener {
void displayTransientMessage(String message);
void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor);
void setHdrMode(boolean enabled);
}
@@ -26,6 +26,7 @@ public class StreamConfiguration {
private int hevcBitratePercentageMultiplier;
private boolean enableHdr;
private int attachedGamepadMask;
private int encryptionFlags;
public static class Builder {
private StreamConfiguration config = new StreamConfiguration();
@@ -110,7 +111,17 @@ public class StreamConfiguration {
config.clientRefreshRateX100 = refreshRateX100;
return this;
}
public StreamConfiguration.Builder setAudioEncryption(boolean enable) {
if (enable) {
config.encryptionFlags |= MoonBridge.ENCFLG_AUDIO;
}
else {
config.encryptionFlags &= ~MoonBridge.ENCFLG_AUDIO;
}
return this;
}
public StreamConfiguration.Builder setAudioConfiguration(MoonBridge.AudioConfiguration audioConfig) {
config.audioConfiguration = audioConfig;
return this;
@@ -211,4 +222,8 @@ public class StreamConfiguration {
public int getClientRefreshRateX100() {
return clientRefreshRateX100;
}
public int getEncryptionFlags() {
return encryptionFlags;
}
}
@@ -10,9 +10,11 @@ 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);
int frameNumber, int frameType, long receiveTimeMs, long enqueueTimeMs);
public abstract void cleanup();
public abstract int getCapabilities();
public abstract void setHdrMode(boolean enabled);
}
@@ -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,10 +9,8 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -53,6 +51,7 @@ import com.limelight.nvstream.ConnectionContext;
import com.limelight.nvstream.http.PairingManager.PairState;
import okhttp3.ConnectionPool;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
@@ -71,8 +70,8 @@ public class NvHTTP {
// Print URL and content to logcat on debug builds
private static boolean verbose = BuildConfig.DEBUG;
public String baseUrlHttps;
public String baseUrlHttp;
private HttpUrl baseUrlHttps;
private HttpUrl baseUrlHttp;
private OkHttpClient httpClient;
private OkHttpClient httpClientWithReadTimeout;
@@ -173,6 +172,7 @@ public class NvHTTP {
.hostnameVerifier(hv)
.readTimeout(0, TimeUnit.MILLISECONDS)
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.MILLISECONDS)
.proxy(Proxy.NO_PROXY)
.build();
httpClientWithReadTimeout = httpClient.newBuilder()
@@ -190,22 +190,26 @@ public class NvHTTP {
initializeHttpState(cryptoProvider);
try {
// The URI constructor takes care of escaping IPv6 literals
this.baseUrlHttps = new URI("https", null, address, HTTPS_PORT, null, null, null).toString();
this.baseUrlHttp = new URI("http", null, address, HTTP_PORT, null, null, null).toString();
} catch (URISyntaxException e) {
// Encapsulate URISyntaxException into IOException for callers to handle more easily
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)
.build();
} catch (IllegalArgumentException e) {
// Encapsulate IllegalArgumentException into IOException for callers to handle more easily
throw new IOException(e);
}
this.pm = new PairingManager(this, cryptoProvider);
}
String buildUniqueIdUuidString() {
return "uniqueid="+uniqueId+"&uuid="+UUID.randomUUID();
}
static String getXmlString(Reader r, String tagname) throws XmlPullParserException, IOException {
static String getXmlString(Reader r, String tagname, boolean throwIfMissing) throws XmlPullParserException, IOException {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
@@ -234,11 +238,19 @@ public class NvHTTP {
eventType = xpp.next();
}
if (throwIfMissing) {
// We throw an XmlPullParserException here for ease of handling in all the various callers.
// We could also throw an IOException, but some callers expect those in cases where the
// host may not be reachable. We want to distinguish unreachable hosts vs. hosts that
// are returning garbage XML to us, so we use XmlPullParserException instead.
throw new XmlPullParserException("Missing mandatory field in host response: "+tagname);
}
return null;
}
static String getXmlString(String str, String tagname) throws XmlPullParserException, IOException {
return getXmlString(new StringReader(str), tagname);
static String getXmlString(String str, String tagname, boolean throwIfMissing) throws XmlPullParserException, IOException {
return getXmlString(new StringReader(str), tagname, throwIfMissing);
}
private static void verifyResponseStatus(XmlPullParser xpp) throws GfeHttpResponseException {
@@ -272,7 +284,7 @@ public class NvHTTP {
if (serverCert != null) {
try {
try {
resp = openHttpConnectionToString(baseUrlHttps + "/serverinfo?"+buildUniqueIdUuidString(), true);
resp = openHttpConnectionToString(baseUrlHttps, "serverinfo", true);
} catch (SSLHandshakeException e) {
// Detect if we failed due to a server cert mismatch
if (e.getCause() instanceof CertificateException) {
@@ -292,7 +304,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(baseUrlHttp, "serverinfo", true);
}
// If it's not a cert validation error, throw it
@@ -303,7 +315,7 @@ public class NvHTTP {
}
else {
// No pinned cert, so use HTTP
return openHttpConnectionToString(baseUrlHttp + "/serverinfo", true);
return openHttpConnectionToString(baseUrlHttp , "serverinfo", true);
}
}
@@ -311,21 +323,21 @@ public class NvHTTP {
ComputerDetails details = new ComputerDetails();
String serverInfo = getServerInfo();
details.name = getXmlString(serverInfo, "hostname");
details.name = getXmlString(serverInfo, "hostname", false);
if (details.name == null || details.name.isEmpty()) {
details.name = "UNKNOWN";
}
details.uuid = getXmlString(serverInfo, "uniqueid");
details.macAddress = getXmlString(serverInfo, "mac");
details.localAddress = getXmlString(serverInfo, "LocalIP");
// UUID is mandatory to determine which machine is responding
details.uuid = getXmlString(serverInfo, "uniqueid", true);
// This may be null, but that's okay
details.remoteAddress = getXmlString(serverInfo, "ExternalIP");
details.macAddress = getXmlString(serverInfo, "mac", false);
details.localAddress = getXmlString(serverInfo, "LocalIP", false);
// This is missing on on recent GFE versions
details.remoteAddress = getXmlString(serverInfo, "ExternalIP", false);
// This has some extra logic to always report unpaired if the pinned cert isn't there
details.pairState = getPairState(serverInfo);
details.runningGameId = getCurrentGame(serverInfo);
// We could reach it so it's online
@@ -357,12 +369,26 @@ public class NvHTTP {
}
}
private HttpUrl getCompleteUrl(HttpUrl baseUrl, String path, String query) {
return baseUrl.newBuilder()
.addPathSegment(path)
.query(query)
.addQueryParameter("uniqueid", uniqueId)
.addQueryParameter("uuid", UUID.randomUUID().toString())
.build();
}
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
return openHttpConnection(baseUrl, path, null, enableReadTimeout);
}
// 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(String url, boolean enableReadTimeout) throws IOException {
Request request = new Request.Builder().url(url).get().build();
private ResponseBody openHttpConnection(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
HttpUrl completeUrl = getCompleteUrl(baseUrl, path, query);
Request request = new Request.Builder().url(completeUrl).get().build();
Response response;
if (enableReadTimeout) {
@@ -384,30 +410,31 @@ public class NvHTTP {
}
if (response.code() == 404) {
throw new FileNotFoundException(url);
throw new FileNotFoundException(completeUrl.toString());
}
else {
throw new GfeHttpResponseException(response.code(), response.message());
}
}
String openHttpConnectionToString(String url, boolean enableReadTimeout) throws IOException {
try {
if (verbose) {
LimeLog.info("Requesting URL: "+url);
}
ResponseBody resp = openHttpConnection(url, enableReadTimeout);
private String openHttpConnectionToString(HttpUrl baseUrl, String path, boolean enableReadTimeout) throws IOException {
return openHttpConnectionToString(baseUrl, path, null, enableReadTimeout);
}
private String openHttpConnectionToString(HttpUrl baseUrl, String path, String query, boolean enableReadTimeout) throws IOException {
try {
ResponseBody resp = openHttpConnection(baseUrl, path, query, enableReadTimeout);
String respString = resp.string();
resp.close();
if (verbose) {
LimeLog.info(url+" -> "+respString);
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();
}
@@ -416,7 +443,8 @@ public class NvHTTP {
}
public String getServerVersion(String serverInfo) throws XmlPullParserException, IOException {
return getXmlString(serverInfo, "appversion");
// appversion is present in all supported GFE versions
return getXmlString(serverInfo, "appversion", true);
}
public PairingManager.PairState getPairState() throws IOException, XmlPullParserException {
@@ -424,15 +452,14 @@ public class NvHTTP {
}
public PairingManager.PairState getPairState(String serverInfo) throws IOException, XmlPullParserException {
if (!NvHTTP.getXmlString(serverInfo, "PairStatus").equals("1")) {
return PairState.NOT_PAIRED;
}
return PairState.PAIRED;
// appversion is present in all supported GFE versions
return NvHTTP.getXmlString(serverInfo, "PairStatus", true).equals("1") ?
PairState.PAIRED : PairState.NOT_PAIRED;
}
public long getMaxLumaPixelsH264(String serverInfo) throws XmlPullParserException, IOException {
String str = getXmlString(serverInfo, "MaxLumaPixelsH264");
// MaxLumaPixelsH264 wasn't present on old GFE versions
String str = getXmlString(serverInfo, "MaxLumaPixelsH264", false);
if (str != null) {
return Long.parseLong(str);
} else {
@@ -441,7 +468,8 @@ public class NvHTTP {
}
public long getMaxLumaPixelsHEVC(String serverInfo) throws XmlPullParserException, IOException {
String str = getXmlString(serverInfo, "MaxLumaPixelsHEVC");
// MaxLumaPixelsHEVC wasn't present on old GFE versions
String str = getXmlString(serverInfo, "MaxLumaPixelsHEVC", false);
if (str != null) {
return Long.parseLong(str);
} else {
@@ -458,7 +486,8 @@ public class NvHTTP {
// Bit 10: HEVC Main10 4:4:4
// Bit 11: ???
public long getServerCodecModeSupport(String serverInfo) throws XmlPullParserException, IOException {
String str = getXmlString(serverInfo, "ServerCodecModeSupport");
// ServerCodecModeSupport wasn't present on old GFE versions
String str = getXmlString(serverInfo, "ServerCodecModeSupport", false);
if (str != null) {
return Long.parseLong(str);
} else {
@@ -467,16 +496,18 @@ public class NvHTTP {
}
public String getGpuType(String serverInfo) throws XmlPullParserException, IOException {
return getXmlString(serverInfo, "gputype");
// ServerCodecModeSupport wasn't present on old GFE versions
return getXmlString(serverInfo, "gputype", false);
}
public String getGfeVersion(String serverInfo) throws XmlPullParserException, IOException {
return getXmlString(serverInfo, "GfeVersion");
// ServerCodecModeSupport wasn't present on old GFE versions
return getXmlString(serverInfo, "GfeVersion", false);
}
public boolean supports4K(String serverInfo) throws XmlPullParserException, IOException {
// Only allow 4K on GFE 3.x
String gfeVersionStr = getXmlString(serverInfo, "GfeVersion");
// Only allow 4K on GFE 3.x. GfeVersion wasn't present on very old versions of GFE.
String gfeVersionStr = getXmlString(serverInfo, "GfeVersion", false);
if (gfeVersionStr == null || gfeVersionStr.startsWith("2.")) {
return false;
}
@@ -488,10 +519,8 @@ public class NvHTTP {
// GFE 2.8 started keeping currentgame set to the last game played. As a result, it no longer
// has the semantics that its name would indicate. To contain the effects of this change as much
// as possible, we'll force the current game to zero if the server isn't in a streaming session.
String serverState = getXmlString(serverInfo, "state");
if (serverState != null && serverState.endsWith("_SERVER_BUSY")) {
String game = getXmlString(serverInfo, "currentgame");
return Integer.parseInt(game);
if (getXmlString(serverInfo, "state", true).endsWith("_SERVER_BUSY")) {
return Integer.parseInt(getXmlString(serverInfo, "currentgame", true));
}
else {
return 0;
@@ -588,8 +617,8 @@ public class NvHTTP {
return appList;
}
public String getAppListRaw() throws MalformedURLException, IOException {
return openHttpConnectionToString(baseUrlHttps + "/applist?"+buildUniqueIdUuidString(), true);
public String getAppListRaw() throws IOException {
return openHttpConnectionToString(baseUrlHttps, "applist", true);
}
public LinkedList<NvApp> getAppList() throws GfeHttpResponseException, IOException, XmlPullParserException {
@@ -598,20 +627,31 @@ public class NvHTTP {
return getAppListByReader(new StringReader(getAppListRaw()));
}
else {
ResponseBody resp = openHttpConnection(baseUrlHttps + "/applist?" + buildUniqueIdUuidString(), true);
ResponseBody resp = openHttpConnection(baseUrlHttps, "applist", true);
LinkedList<NvApp> appList = getAppListByReader(new InputStreamReader(resp.byteStream()));
resp.close();
return appList;
}
}
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws GfeHttpResponseException, IOException {
return openHttpConnectionToString(baseUrlHttp, "pair",
"devicename=roth&updateState=1&" + additionalArguments,
enableReadTimeout);
}
String executePairingChallenge() throws GfeHttpResponseException, IOException {
return openHttpConnectionToString(baseUrlHttps, "pair",
"devicename=roth&updateState=1&phrase=pairchallenge",
true);
}
public void unpair() throws IOException {
openHttpConnectionToString(baseUrlHttp + "/unpair?"+buildUniqueIdUuidString(), true);
openHttpConnectionToString(baseUrlHttp, "unpair", true);
}
public InputStream getBoxArt(NvApp app) throws IOException {
ResponseBody resp = openHttpConnection(baseUrlHttps + "/appasset?"+ buildUniqueIdUuidString() +
"&appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0", true);
ResponseBody resp = openHttpConnection(baseUrlHttps, "appasset", "appid=" + app.getAppId() + "&AssetType=2&AssetIdx=0", true);
return resp.byteStream();
}
@@ -666,9 +706,8 @@ public class NvHTTP {
enableSops = false;
}
String xmlStr = openHttpConnectionToString(baseUrlHttps +
"/launch?" + buildUniqueIdUuidString() +
"&appid=" + appId +
String xmlStr = openHttpConnectionToString(baseUrlHttps, "launch",
"appid=" + appId +
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
"&rikey="+bytesToHex(context.riKey.getEncoded()) +
@@ -679,24 +718,35 @@ public class NvHTTP {
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""),
false);
String gameSession = getXmlString(xmlStr, "gamesession");
return gameSession != null && !gameSession.equals("0");
if (!getXmlString(xmlStr, "gamesession", true).equals("0")) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
return true;
}
else {
return false;
}
}
public boolean resumeApp(ConnectionContext context) throws IOException, XmlPullParserException {
String xmlStr = openHttpConnectionToString(baseUrlHttps + "/resume?" + buildUniqueIdUuidString() +
"&rikey="+bytesToHex(context.riKey.getEncoded()) +
String xmlStr = openHttpConnectionToString(baseUrlHttps, "resume",
"rikey="+bytesToHex(context.riKey.getEncoded()) +
"&rikeyid="+context.riKeyId +
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo(),
false);
String resume = getXmlString(xmlStr, "resume");
return Integer.parseInt(resume) != 0;
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
// sessionUrl0 will be missing for older GFE versions
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
return true;
}
else {
return false;
}
}
public boolean quitApp() throws IOException, XmlPullParserException {
String xmlStr = openHttpConnectionToString(baseUrlHttps + "/cancel?" + buildUniqueIdUuidString(), false);
String cancel = getXmlString(xmlStr, "cancel");
if (Integer.parseInt(cancel) == 0) {
String xmlStr = openHttpConnectionToString(baseUrlHttps, "cancel", false);
if (getXmlString(xmlStr, "cancel", true).equals("0")) {
return false;
}
@@ -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;
@@ -68,7 +67,8 @@ public class PairingManager {
private X509Certificate extractPlainCert(String text) throws XmlPullParserException, IOException
{
String certText = NvHTTP.getXmlString(text, "plaincert");
// Plaincert may be null if another client is already trying to pair
String certText = NvHTTP.getXmlString(text, "plaincert", false);
if (certText != null) {
byte[] certBytes = hexToBytes(certText);
@@ -124,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) {
@@ -199,16 +191,14 @@ 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
String getCert = http.openHttpConnectionToString(http.baseUrlHttp +
"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&phrase=getservercert&salt="+
String getCert = http.executePairingCommand("phrase=getservercert&salt="+
bytesToHex(salt)+"&clientcert="+bytesToHex(pemCertBytes),
false);
if (!NvHTTP.getXmlString(getCert, "paired").equals("1")) {
if (!NvHTTP.getXmlString(getCert, "paired", true).equals("1")) {
return PairState.FAILED;
}
@@ -217,7 +207,7 @@ public class PairingManager {
if (serverCert == null) {
// Attempting to pair while another device is pairing will cause GFE
// to give an empty cert in the response.
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
http.unpair();
return PairState.ALREADY_IN_PROGRESS;
}
@@ -229,16 +219,14 @@ public class PairingManager {
byte[] encryptedChallenge = encryptAes(randomChallenge, aesKey);
// Send the encrypted challenge to the server
String challengeResp = http.openHttpConnectionToString(http.baseUrlHttp +
"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&clientchallenge="+bytesToHex(encryptedChallenge),
true);
if (!NvHTTP.getXmlString(challengeResp, "paired").equals("1")) {
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
String challengeResp = http.executePairingCommand("clientchallenge="+bytesToHex(encryptedChallenge), true);
if (!NvHTTP.getXmlString(challengeResp, "paired", true).equals("1")) {
http.unpair();
return PairState.FAILED;
}
// Decode the server's response and subsequent challenge
byte[] encServerChallengeResponse = hexToBytes(NvHTTP.getXmlString(challengeResp, "challengeresponse"));
byte[] encServerChallengeResponse = hexToBytes(NvHTTP.getXmlString(challengeResp, "challengeresponse", true));
byte[] decServerChallengeResponse = decryptAes(encServerChallengeResponse, aesKey);
byte[] serverResponse = Arrays.copyOfRange(decServerChallengeResponse, 0, hashAlgo.getHashLength());
@@ -248,23 +236,21 @@ public class PairingManager {
byte[] clientSecret = generateRandomBytes(16);
byte[] challengeRespHash = hashAlgo.hashData(concatBytes(concatBytes(serverChallenge, cert.getSignature()), clientSecret));
byte[] challengeRespEncrypted = encryptAes(challengeRespHash, aesKey);
String secretResp = http.openHttpConnectionToString(http.baseUrlHttp +
"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&serverchallengeresp="+bytesToHex(challengeRespEncrypted),
true);
if (!NvHTTP.getXmlString(secretResp, "paired").equals("1")) {
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
String secretResp = http.executePairingCommand("serverchallengeresp="+bytesToHex(challengeRespEncrypted), true);
if (!NvHTTP.getXmlString(secretResp, "paired", true).equals("1")) {
http.unpair();
return PairState.FAILED;
}
// Get the server's signed secret
byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret"));
byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret", true));
byte[] serverSecret = Arrays.copyOfRange(serverSecretResp, 0, 16);
byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, 272);
// Ensure the authenticity of the data
if (!verifySignature(serverSecret, serverSignature, serverCert)) {
// Cancel the pairing process
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
http.unpair();
// Looks like a MITM
return PairState.FAILED;
@@ -274,7 +260,7 @@ public class PairingManager {
byte[] serverChallengeRespHash = hashAlgo.hashData(concatBytes(concatBytes(randomChallenge, serverCert.getSignature()), serverSecret));
if (!Arrays.equals(serverChallengeRespHash, serverResponse)) {
// Cancel the pairing process
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
http.unpair();
// Probably got the wrong PIN
return PairState.PIN_WRONG;
@@ -282,19 +268,16 @@ public class PairingManager {
// Send the server our signed secret
byte[] clientPairingSecret = concatBytes(clientSecret, signData(clientSecret, pk));
String clientSecretResp = http.openHttpConnectionToString(http.baseUrlHttp +
"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&clientpairingsecret="+bytesToHex(clientPairingSecret),
true);
if (!NvHTTP.getXmlString(clientSecretResp, "paired").equals("1")) {
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
String clientSecretResp = http.executePairingCommand("clientpairingsecret="+bytesToHex(clientPairingSecret), true);
if (!NvHTTP.getXmlString(clientSecretResp, "paired", true).equals("1")) {
http.unpair();
return PairState.FAILED;
}
// Do the initial challenge (seems neccessary for us to show as paired)
String pairChallenge = http.openHttpConnectionToString(http.baseUrlHttps +
"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&phrase=pairchallenge", true);
if (!NvHTTP.getXmlString(pairChallenge, "paired").equals("1")) {
http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
// Do the initial challenge (seems necessary for us to show as paired)
String pairChallenge = http.executePairingChallenge();
if (!NvHTTP.getXmlString(pairChallenge, "paired", true).equals("1")) {
http.unpair();
return PairState.FAILED;
}
@@ -18,11 +18,18 @@ public class MoonBridge {
public static final int VIDEO_FORMAT_MASK_H264 = 0x00FF;
public static final int VIDEO_FORMAT_MASK_H265 = 0xFF00;
public static final int ENCFLG_NONE = 0;
public static final int ENCFLG_AUDIO = 1;
public static final int ENCFLG_ALL = 0xFFFFFFFF;
public static final int BUFFER_TYPE_PICDATA = 0;
public static final int BUFFER_TYPE_SPS = 1;
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 CAPABILITY_DIRECT_SUBMIT = 1;
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC = 2;
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC = 4;
@@ -37,6 +44,7 @@ public class MoonBridge {
public static final int ML_ERROR_NO_VIDEO_TRAFFIC = -100;
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_PORT_INDEX_TCP_47984 = 0;
public static final int ML_PORT_INDEX_TCP_47989 = 1;
@@ -148,12 +156,12 @@ public class MoonBridge {
}
}
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength,
int decodeUnitType,
int frameNumber, long receiveTimeMs) {
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);
decodeUnitType, frameNumber, frameType, receiveTimeMs, enqueueTimeMs);
}
else {
return DR_OK;
@@ -235,6 +243,12 @@ public class MoonBridge {
}
}
public static void bridgeClSetHdrMode(boolean enabled) {
if (connectionListener != null) {
connectionListener.setHdrMode(enabled);
}
}
public static void setupBridge(VideoDecoderRenderer videoRenderer, AudioRenderer audioRenderer, NvConnectionListener connectionListener) {
MoonBridge.videoRenderer = videoRenderer;
MoonBridge.audioRenderer = audioRenderer;
@@ -248,12 +262,14 @@ public class MoonBridge {
}
public static native int startConnection(String address, String appVersion, String gfeVersion,
String rtspSessionUrl,
int width, int height, int fps,
int bitrate, int packetSize, int streamingRemotely,
int audioConfiguration, boolean supportsHevc,
boolean enableHdr,
int hevcBitratePercentageMultiplier,
int clientRefreshRateX100,
int encryptionFlags,
byte[] riAesKey, byte[] riAesIv,
int videoCapabilities);
@@ -265,6 +281,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,
@@ -284,6 +302,8 @@ public class MoonBridge {
public static native void sendMouseHighResScroll(short scrollAmount);
public static native void sendUtf8Text(String text);
public static native String getStageName(int stage);
public static native String findExternalAddressIP4(String stunHostName, int stunPort);
@@ -300,5 +320,8 @@ public class MoonBridge {
public static native String stringifyPortFlags(int portFlags, String separator);
// The RTT is in the top 32 bits, and the RTT variance is in the bottom 32 bits
public static native long getEstimatedRttInfo();
public static native void init();
}
@@ -88,15 +88,15 @@ public class AddComputerManually extends Activity {
// Couldn't find a matching interface
return true;
} catch (SocketException e) {
} catch (Exception e) {
// Catch all exceptions because some broken Android devices
// will throw an NPE from inside getNetworkInterfaces().
e.printStackTrace();
return false;
} catch (UnknownHostException e) {
return false;
}
}
private void doAddPc(String host) {
private void doAddPc(String host) throws InterruptedException {
boolean wrongSiteLocal = false;
boolean success;
int portTestResult;
@@ -108,12 +108,18 @@ public class AddComputerManually extends Activity {
ComputerDetails details = new ComputerDetails();
details.manualAddress = host;
success = managerBinder.addComputerBlocking(details);
} catch (InterruptedException e) {
// Propagate the InterruptedException to the caller for proper handling
dialog.dismiss();
throw e;
} catch (IllegalArgumentException e) {
// This can be thrown from OkHttp if the host fails to canonicalize to a valid name.
// https://github.com/square/okhttp/blob/okhttp_27/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java#L705
e.printStackTrace();
success = false;
}
// Keep the SpinnerDialog open while testing connectivity
if (!success){
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
}
@@ -162,15 +168,12 @@ public class AddComputerManually extends Activity {
@Override
public void run() {
while (!isInterrupted()) {
String computer;
try {
computer = computersToAdd.take();
String computer = computersToAdd.take();
doAddPc(computer);
} catch (InterruptedException e) {
return;
}
doAddPc(computer);
}
}
};
@@ -184,7 +187,14 @@ public class AddComputerManually extends Activity {
try {
addThread.join();
} catch (InterruptedException ignored) {}
} 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();
}
addThread = null;
}
@@ -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();
}
}
@@ -30,7 +30,7 @@ public class PreferenceConfiguration {
private static final String VIDEO_FORMAT_PREF_STRING = "video_format";
private static final String ONSCREEN_CONTROLLER_PREF_STRING = "checkbox_show_onscreen_controls";
private static final String ONLY_L3_R3_PREF_STRING = "checkbox_only_show_L3R3";
private static final String DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
private static final String ENABLE_HDR_PREF_STRING = "checkbox_enable_hdr";
private static final String ENABLE_PIP_PREF_STRING = "checkbox_enable_pip";
private static final String ENABLE_PERF_OVERLAY_STRING = "checkbox_enable_perf_overlay";
@@ -43,6 +43,9 @@ public class PreferenceConfiguration {
private static final String FLIP_FACE_BUTTONS_PREF_STRING = "checkbox_flip_face_buttons";
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
private static final String 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";
static final String DEFAULT_RESOLUTION = "1280x720";
static final String DEFAULT_FPS = "60";
@@ -50,7 +53,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;
@@ -58,7 +61,6 @@ public class PreferenceConfiguration {
private static final String DEFAULT_VIDEO_FORMAT = "auto";
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
private static final boolean ONLY_L3_R3_DEFAULT = false;
private static final boolean DEFAULT_DISABLE_FRAME_DROP = false;
private static final boolean DEFAULT_ENABLE_HDR = false;
private static final boolean DEFAULT_ENABLE_PIP = false;
private static final boolean DEFAULT_ENABLE_PERF_OVERLAY = false;
@@ -72,11 +74,19 @@ public class PreferenceConfiguration {
private static final boolean DEFAULT_TOUCHSCREEN_TRACKPAD = true;
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;
public static final int FORCE_H265_ON = -1;
public static final int AUTOSELECT_H265 = 0;
public static final int FORCE_H265_OFF = 1;
public static final int FRAME_PACING_MIN_LATENCY = 0;
public static final int FRAME_PACING_BALANCED = 1;
public static final int FRAME_PACING_CAP_FPS = 2;
public static final int FRAME_PACING_MAX_SMOOTHNESS = 3;
public static final String RES_360P = "640x360";
public static final String RES_480P = "854x480";
public static final String RES_720P = "1280x720";
@@ -95,7 +105,6 @@ public class PreferenceConfiguration {
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
public boolean onscreenController;
public boolean onlyL3R3;
public boolean disableFrameDrop;
public boolean enableHdr;
public boolean enablePip;
public boolean enablePerfOverlay;
@@ -108,6 +117,33 @@ public class PreferenceConfiguration {
public boolean vibrateFallbackToDevice;
public boolean touchscreenTrackpad;
public MoonBridge.AudioConfiguration audioConfiguration;
public int framePacing;
public boolean absoluteMouseMode;
public boolean enableAudioFx;
public static boolean isNativeResolution(int width, int height) {
// It's not a native resolution if it matches an existing resolution option
if (width == 640 && height == 360) {
return false;
}
else if (width == 854 && height == 480) {
return false;
}
else if (width == 1280 && height == 720) {
return false;
}
else if (width == 1920 && height == 1080) {
return false;
}
else if (width == 2560 && height == 1440) {
return false;
}
else if (width == 3840 && height == 2160) {
return false;
}
return true;
}
private static String convertFromLegacyResolutionString(String resString) {
if (resString.equalsIgnoreCase("360p")) {
@@ -240,6 +276,37 @@ public class PreferenceConfiguration {
}
}
private static int getFramePacingValue(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
// Migrate legacy never drop frames option to the new location
if (prefs.contains(LEGACY_DISABLE_FRAME_DROP_PREF_STRING)) {
boolean legacyNeverDropFrames = prefs.getBoolean(LEGACY_DISABLE_FRAME_DROP_PREF_STRING, false);
prefs.edit()
.remove(LEGACY_DISABLE_FRAME_DROP_PREF_STRING)
.putString(FRAME_PACING_PREF_STRING, legacyNeverDropFrames ? "balanced" : "latency")
.apply();
}
String str = prefs.getString(FRAME_PACING_PREF_STRING, DEFAULT_FRAME_PACING);
if (str.equals("latency")) {
return FRAME_PACING_MIN_LATENCY;
}
else if (str.equals("balanced")) {
return FRAME_PACING_BALANCED;
}
else if (str.equals("cap-fps")) {
return FRAME_PACING_CAP_FPS;
}
else if (str.equals("smoothness")) {
return FRAME_PACING_MAX_SMOOTHNESS;
}
else {
// Should never get here
return FRAME_PACING_MIN_LATENCY;
}
}
public static void resetStreamingSettings(Context context) {
// We consider resolution, FPS, bitrate, HDR, and video format as "streaming settings" here
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
@@ -255,6 +322,19 @@ public class PreferenceConfiguration {
.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();
@@ -363,6 +443,7 @@ public class PreferenceConfiguration {
}
config.videoFormat = getVideoFormatValue(context);
config.framePacing = getFramePacingValue(context);
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
@@ -380,8 +461,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.disableFrameDrop = prefs.getBoolean(DISABLE_FRAME_DROP_PREF_STRING, DEFAULT_DISABLE_FRAME_DROP);
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);
@@ -393,6 +473,8 @@ 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);
return config;
}
@@ -3,23 +3,28 @@ package com.limelight.preferences;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
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;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.DisplayMetrics;
import android.util.Range;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import com.limelight.LimeLog;
import com.limelight.PcView;
@@ -28,15 +33,19 @@ import com.limelight.binding.video.MediaCodecHelper;
import com.limelight.utils.Dialog;
import com.limelight.utils.UiHelper;
import java.lang.reflect.Method;
import java.util.Arrays;
public class StreamSettings extends Activity {
private PreferenceConfiguration previousPrefs;
// HACK for Android 9
static DisplayCutout displayCutoutP;
void reloadSettings() {
getFragmentManager().beginTransaction().replace(
R.id.stream_settings, new SettingsFragment()
).commit();
).commitAllowingStateLoss();
}
@Override
@@ -48,27 +57,48 @@ public class StreamSettings extends Activity {
UiHelper.setLocale(this);
setContentView(R.layout.activity_stream_settings);
reloadSettings();
UiHelper.notifyNewRootView(this);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
// We have to use this hack on Android 9 because we don't have Display.getCutout()
// which was added in Android 10.
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
// Insets can be null when the activity is recreated on screen rotation
// https://stackoverflow.com/questions/61241255/windowinsets-getdisplaycutout-is-null-everywhere-except-within-onattachedtowindo
WindowInsets insets = getWindow().getDecorView().getRootWindowInsets();
if (insets != null) {
displayCutoutP = insets.getDisplayCutout();
}
}
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);
}
}
}
public static class SettingsFragment extends PreferenceFragment {
private boolean nativeResolutionOptionPresent = false;
private int nativeResolutionStartIndex = Integer.MAX_VALUE;
private void setValue(String preferenceKey, String value) {
ListPreference pref = (ListPreference) findPreference(preferenceKey);
@@ -76,36 +106,45 @@ public class StreamSettings extends Activity {
pref.setValue(value);
}
private void updateNativeResolutionEntry(int nativeWidth, int nativeHeight) {
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
String nameSuffix = " ("+nativeWidth+"x"+nativeHeight+")";
String newName;
if (insetsRemoved) {
newName = getResources().getString(R.string.resolution_prefix_native_fullscreen);
}
else {
newName = getResources().getString(R.string.resolution_prefix_native);
}
newName += " ("+nativeWidth+"x"+nativeHeight+")";
String newValue = nativeWidth+"x"+nativeHeight;
CharSequence[] entries = pref.getEntries();
CharSequence[] values = pref.getEntryValues();
// Check if the native resolution is already present
for (CharSequence value : values) {
if (newValue.equals(value.toString())) {
// It is present in the default list, so remove the native option
nativeResolutionOptionPresent = false;
pref.setEntries(Arrays.copyOf(entries, entries.length - 1));
pref.setEntryValues(Arrays.copyOf(values, values.length - 1));
// It is present in the default list, so don't add it again
return;
}
}
// Add the name suffix to the native option
entries[entries.length - 1] = entries[entries.length - 1].toString() + nameSuffix;
values[values.length - 1] = newValue;
CharSequence[] newEntries = Arrays.copyOf(pref.getEntries(), pref.getEntries().length + 1);
CharSequence[] newValues = Arrays.copyOf(values, values.length + 1);
pref.setEntries(entries);
pref.setEntryValues(values);
// Add the new native option
newEntries[newEntries.length - 1] = newName;
newValues[newValues.length - 1] = newValue;
nativeResolutionOptionPresent = true;
pref.setEntries(newEntries);
pref.setEntryValues(newValues);
if (newValues.length - 1 < nativeResolutionStartIndex) {
nativeResolutionStartIndex = newValues.length - 1;
}
}
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
@@ -174,7 +213,7 @@ public class StreamSettings extends Activity {
// hide on-screen controls category on non touch screen devices
if (!getActivity().getPackageManager().
hasSystemFeature("android.hardware.touchscreen")) {
hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
{
PreferenceCategory category =
(PreferenceCategory) findPreference("category_onscreen_controls");
@@ -188,6 +227,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 ||
@@ -198,6 +246,13 @@ public class StreamSettings extends Activity {
category.removePreference(findPreference("checkbox_enable_pip"));
}
// Fire TV apps are not allowed to use WebViews or browsers, so hide the Help category
/*if (getActivity().getPackageManager().hasSystemFeature("amazon.hardware.fire_tv")) {
PreferenceCategory category =
(PreferenceCategory) findPreference("category_help");
screen.removePreference(category);
}*/
// Remove the vibration options if the device can't vibrate
if (!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
PreferenceCategory category =
@@ -219,6 +274,38 @@ public class StreamSettings extends Activity {
int maxSupportedResW = 0;
// Add a native resolution with any insets included for users that don't want content
// behind the notch of their display
boolean hasInsets = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
DisplayCutout cutout;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
// Use the much nicer Display.getCutout() API on Android 10+
cutout = display.getCutout();
}
else {
// Android 9 only
cutout = displayCutoutP;
}
if (cutout != null) {
int widthInsets = cutout.getSafeInsetLeft() + cutout.getSafeInsetRight();
int heightInsets = cutout.getSafeInsetBottom() + cutout.getSafeInsetTop();
if (widthInsets != 0 || heightInsets != 0) {
DisplayMetrics metrics = new DisplayMetrics();
display.getRealMetrics(metrics);
int width = Math.max(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
int height = Math.min(metrics.widthPixels - widthInsets, metrics.heightPixels - heightInsets);
addNativeResolutionEntry(width, height, false);
hasInsets = true;
}
}
}
// Always allow resolutions that are smaller or equal to the active
// display resolution because decoders can report total non-sense to us.
// For example, a p201 device reports:
@@ -226,7 +313,6 @@ public class StreamSettings extends Activity {
// HEVC Decoder: OMX.amlogic.hevc.decoder.awesome
// AVC supported width range: 64 - 384
// HEVC supported width range: 64 - 544
int nativeWidth = 0, nativeHeight = 0;
for (Display.Mode candidate : display.getSupportedModes()) {
// Some devices report their dimensions in the portrait orientation
// where height > width. Normalize these to the conventional width > height
@@ -235,11 +321,11 @@ public class StreamSettings extends Activity {
int width = Math.max(candidate.getPhysicalWidth(), candidate.getPhysicalHeight());
int height = Math.min(candidate.getPhysicalWidth(), candidate.getPhysicalHeight());
if (width > nativeWidth) {
nativeWidth = width;
}
if (height > nativeHeight) {
nativeHeight = height;
// Some TVs report strange values here, so let's avoid native resolutions on a TV
// unless they report greater than 4K resolutions.
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION) ||
(width > 3840 || height > 2160)) {
addNativeResolutionEntry(width, height, hasInsets);
}
if ((width >= 3840 || height >= 2160) && maxSupportedResW < 3840) {
@@ -257,8 +343,6 @@ public class StreamSettings extends Activity {
}
}
updateNativeResolutionEntry(nativeWidth, nativeHeight);
// This must be called to do runtime initialization before calling functions that evaluate
// decoder lists.
MediaCodecHelper.initialize(getContext(), GlPreferences.readPreferences(getContext()).glRenderer);
@@ -343,11 +427,29 @@ public class StreamSettings extends Activity {
// Never remove 720p
}
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// On Android 4.2 and later, we can get the true metrics via the
// getRealMetrics() function (unlike the lies that getWidth() and getHeight()
// tell to us).
DisplayMetrics metrics = new DisplayMetrics();
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);
}
else {
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
// to get the real screen dimensions.
Display display = getActivity().getWindowManager().getDefaultDisplay();
int width = Math.max(display.getWidth(), display.getHeight());
int height = Math.min(display.getWidth(), display.getHeight());
updateNativeResolutionEntry(width, height);
try {
Method getRawHeightFunc = Display.class.getMethod("getRawHeight");
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
int width = (Integer) getRawWidthFunc.invoke(display);
int height = (Integer) getRawHeightFunc.invoke(display);
addNativeResolutionEntry(Math.max(width, height), Math.min(width, height), false);
} catch (Exception e) {
e.printStackTrace();
}
}
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
@@ -448,6 +550,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
@@ -458,25 +569,23 @@ public class StreamSettings extends Activity {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
String valueStr = (String) newValue;
if (nativeResolutionOptionPresent) {
// Detect if this value is the native resolution option
CharSequence[] values = ((ListPreference)preference).getEntryValues();
boolean isNativeRes = true;
for (int i = 0; i < values.length; i++) {
// If get a match prior to the end, it's not native res
if (valueStr.equals(values[i].toString()) && i < values.length - 1) {
isNativeRes = false;
break;
}
// Detect if this value is the native resolution option
CharSequence[] values = ((ListPreference)preference).getEntryValues();
boolean isNativeRes = true;
for (int i = 0; i < values.length; i++) {
// Look for a match prior to the start of the native resolution entries
if (valueStr.equals(values[i].toString()) && i < nativeResolutionStartIndex) {
isNativeRes = false;
break;
}
}
// If this is native resolution, show the warning dialog
if (isNativeRes) {
Dialog.displayDialog(getActivity(),
getResources().getString(R.string.title_native_res_dialog),
getResources().getString(R.string.text_native_res_dialog),
false);
}
// If this is native resolution, show the warning dialog
if (isNativeRes) {
Dialog.displayDialog(getActivity(),
getResources().getString(R.string.title_native_res_dialog),
getResources().getString(R.string.text_native_res_dialog),
false);
}
// Write the new bitrate value
@@ -0,0 +1,45 @@
package com.limelight.preferences;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.preference.Preference;
import android.util.AttributeSet;
import com.limelight.utils.HelpLauncher;
public class WebLauncherPreference extends Preference {
private String url;
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initialize(attrs);
}
public WebLauncherPreference(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(attrs);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initialize(attrs);
}
private void initialize(AttributeSet attrs) {
if (attrs == null) {
throw new IllegalStateException("WebLauncherPreference must have attributes!");
}
url = attrs.getAttributeValue(null, "url");
if (url == null) {
throw new IllegalStateException("WebLauncherPreference must have 'url' attribute!");
}
}
@Override
public void onClick() {
HelpLauncher.launchUrl(getContext(), url);
}
}
@@ -1,5 +1,5 @@
package com.limelight.ui;
public interface GameGestures {
void showKeyboard();
void toggleKeyboard();
}
@@ -8,7 +8,7 @@ import android.net.Uri;
import com.limelight.HelpActivity;
public class HelpLauncher {
private static void launchUrl(Context context, String url) {
public static void launchUrl(Context context, String url) {
// Try to launch the default browser
try {
Intent i = new Intent(Intent.ACTION_VIEW);
@@ -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 String getCurrentAddressFromComputer(ComputerDetails computer) throws IOException {
if (computer.activeAddress == null) {
throw new IOException("No active address for "+computer.name);
}
return computer.activeAddress;
}
@@ -53,7 +56,7 @@ 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);
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 +75,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;
}
@@ -39,7 +39,7 @@ public class ShortcutHelper {
@TargetApi(Build.VERSION_CODES.N_MR1)
private void reapShortcutsForDynamicAdd() {
List<ShortcutInfo> dynamicShortcuts = sm.getDynamicShortcuts();
while (dynamicShortcuts.size() >= sm.getMaxShortcutCountPerActivity()) {
while (!dynamicShortcuts.isEmpty() && dynamicShortcuts.size() >= sm.getMaxShortcutCountPerActivity()) {
ShortcutInfo maxRankShortcut = dynamicShortcuts.get(0);
for (ShortcutInfo scut : dynamicShortcuts) {
if (maxRankShortcut.getRank() < scut.getRank()) {
@@ -118,8 +118,16 @@ public class ShortcutHelper {
// To avoid a random carousel of shortcuts popping in and out based on polling status,
// we only add shortcuts if it's not at the limit or the user made a conscious action
// to interact with this PC.
if (forceAdd || sm.getDynamicShortcuts().size() < sm.getMaxShortcutCountPerActivity()) {
if (forceAdd) {
// This should free an entry for us to add one below
reapShortcutsForDynamicAdd();
}
// We still need to check the maximum shortcut count even after reaping,
// because there's a possibility that it could be zero.
if (sm.getDynamicShortcuts().size() < sm.getMaxShortcutCountPerActivity()) {
// Add a shortcut if there is room
sm.addDynamicShortcuts(Collections.singletonList(sinfo));
}
}
@@ -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.
//
+3 -2
View File
@@ -18,9 +18,10 @@ LOCAL_SRC_FILES := moonlight-common-c/src/AudioStream.c \
moonlight-common-c/src/LinkedBlockingQueue.c \
moonlight-common-c/src/Misc.c \
moonlight-common-c/src/Platform.c \
moonlight-common-c/src/PlatformCrypto.c \
moonlight-common-c/src/PlatformSockets.c \
moonlight-common-c/src/RtpFecQueue.c \
moonlight-common-c/src/RtpReorderQueue.c \
moonlight-common-c/src/RtpAudioQueue.c \
moonlight-common-c/src/RtpVideoQueue.c \
moonlight-common-c/src/RtspConnection.c \
moonlight-common-c/src/RtspParser.c \
moonlight-common-c/src/SdpGenerator.c \
+27
View File
@@ -0,0 +1,27 @@
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"
set -e
./Configure android-arm $BASE_ARGS -D__ANDROID_API__=16
make clean
make build_libs -j`nproc`
cp lib*.a $OUTPUT_DIR/armeabi-v7a/
./Configure android-arm64 $BASE_ARGS -D__ANDROID_API__=21
make clean
make build_libs -j`nproc`
cp lib*.a $OUTPUT_DIR/arm64-v8a/
./Configure android-x86 $BASE_ARGS -D__ANDROID_API__=16
make clean
make build_libs -j`nproc`
cp lib*.a $OUTPUT_DIR/x86/
./Configure android-x86_64 $BASE_ARGS -D__ANDROID_API__=21
make clean
make build_libs -j`nproc`
cp lib*.a $OUTPUT_DIR/x86_64/
cp -R include/ $OUTPUT_DIR/include
+26 -5
View File
@@ -32,6 +32,7 @@ static jmethodID BridgeClConnectionStartedMethod;
static jmethodID BridgeClConnectionTerminatedMethod;
static jmethodID BridgeClRumbleMethod;
static jmethodID BridgeClConnectionStatusUpdateMethod;
static jmethodID BridgeClSetHdrModeMethod;
static jbyteArray DecodedFrameBuffer;
static jshortArray DecodedAudioBuffer;
@@ -79,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", "([BIIIJ)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");
@@ -92,6 +93,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
BridgeClConnectionTerminatedMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionTerminated", "(I)V");
BridgeClRumbleMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClRumble", "(SSS)V");
BridgeClConnectionStatusUpdateMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionStatusUpdate", "(I)V");
BridgeClSetHdrModeMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetHdrMode", "(Z)V");
}
int BridgeDrSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
@@ -157,7 +159,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, currentEntry->length, currentEntry->bufferType,
decodeUnit->frameNumber, (jlong)decodeUnit->receiveTimeMs);
decodeUnit->frameNumber, decodeUnit->frameType,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
@@ -177,8 +180,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
DecodedFrameBuffer, offset, BUFFER_TYPE_PICDATA,
decodeUnit->frameNumber,
(jlong)decodeUnit->receiveTimeMs);
decodeUnit->frameNumber, decodeUnit->frameType,
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
@@ -325,6 +328,16 @@ void BridgeClConnectionStatusUpdate(int connectionStatus) {
}
}
void BridgeClSetHdrMode(bool enabled) {
JNIEnv* env = GetThreadEnv();
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetHdrModeMethod, enabled);
if ((*env)->ExceptionCheck(env)) {
// We will crash here
(*JVM)->DetachCurrentThread(JVM);
}
}
void BridgeClLogMessage(const char* format, ...) {
va_list va;
va_start(va, format);
@@ -358,23 +371,27 @@ static CONNECTION_LISTENER_CALLBACKS BridgeConnListenerCallbacks = {
.logMessage = BridgeClLogMessage,
.rumble = BridgeClRumble,
.connectionStatusUpdate = BridgeClConnectionStatusUpdate,
.setHdrMode = BridgeClSetHdrMode,
};
JNIEXPORT jint JNICALL
Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass clazz,
jstring address, jstring appVersion, jstring gfeVersion,
jstring rtspSessionUrl,
jint width, jint height, jint fps,
jint bitrate, jint packetSize, jint streamingRemotely,
jint audioConfiguration, jboolean supportsHevc,
jboolean enableHdr,
jint hevcBitratePercentageMultiplier,
jint clientRefreshRateX100,
jint encryptionFlags,
jbyteArray riAesKey, jbyteArray riAesIv,
jint videoCapabilities) {
SERVER_INFORMATION serverInfo = {
.address = (*env)->GetStringUTFChars(env, address, 0),
.serverInfoAppVersion = (*env)->GetStringUTFChars(env, appVersion, 0),
.serverInfoGfeVersion = gfeVersion ? (*env)->GetStringUTFChars(env, gfeVersion, 0) : NULL,
.rtspSessionUrl = rtspSessionUrl ? (*env)->GetStringUTFChars(env, rtspSessionUrl, 0) : NULL,
};
STREAM_CONFIGURATION streamConfig = {
.width = width,
@@ -387,7 +404,8 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
.supportsHevc = supportsHevc,
.enableHdr = enableHdr,
.hevcBitratePercentageMultiplier = hevcBitratePercentageMultiplier,
.clientRefreshRateX100 = clientRefreshRateX100
.clientRefreshRateX100 = clientRefreshRateX100,
.encryptionFlags = encryptionFlags,
};
jbyte* riAesKeyBuf = (*env)->GetByteArrayElements(env, riAesKey, NULL);
@@ -413,6 +431,9 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
if (gfeVersion != NULL) {
(*env)->ReleaseStringUTFChars(env, gfeVersion, serverInfo.serverInfoGfeVersion);
}
if (rtspSessionUrl != NULL) {
(*env)->ReleaseStringUTFChars(env, rtspSessionUrl, serverInfo.rtspSessionUrl);
}
return ret;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2016-2020 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
@@ -8,9 +8,15 @@
*/
/*
* This file is only used by HP C on VMS, and is included automatically
* This file is only used by HP C/C++ on VMS, and is included automatically
* after each header file from this directory
*/
/*
* The C++ compiler doesn't understand these pragmas, even though it
* understands the corresponding command line qualifier.
*/
#ifndef __cplusplus
/* restore state. Must correspond to the save in __decc_include_prologue.h */
#pragma names restore
# pragma names restore
#endif
@@ -1,5 +1,5 @@
/*
* Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2016-2020 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
@@ -8,13 +8,19 @@
*/
/*
* This file is only used by HP C on VMS, and is included automatically
* This file is only used by HP C/C++ on VMS, and is included automatically
* after each header file from this directory
*/
/*
* The C++ compiler doesn't understand these pragmas, even though it
* understands the corresponding command line qualifier.
*/
#ifndef __cplusplus
/* save state */
#pragma names save
# pragma names save
/* have the compiler shorten symbols larger than 31 chars to 23 chars
* followed by a 8 hex char CRC
*/
#pragma names as_is,shortened
# pragma names as_is,shortened
#endif
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2020 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
@@ -11,6 +11,8 @@
#ifndef HEADER_ASN1ERR_H
# define HEADER_ASN1ERR_H
# include <openssl/symhacks.h>
# ifdef __cplusplus
extern "C"
# endif
@@ -49,6 +51,7 @@ int ERR_load_ASN1_strings(void);
# define ASN1_F_ASN1_ITEM_DUP 191
# define ASN1_F_ASN1_ITEM_EMBED_D2I 120
# define ASN1_F_ASN1_ITEM_EMBED_NEW 121
# define ASN1_F_ASN1_ITEM_EX_I2D 144
# define ASN1_F_ASN1_ITEM_FLAGS_I2D 118
# define ASN1_F_ASN1_ITEM_I2D_BIO 192
# define ASN1_F_ASN1_ITEM_I2D_FP 193
@@ -141,6 +144,7 @@ int ERR_load_ASN1_strings(void);
# define ASN1_R_ASN1_SIG_PARSE_ERROR 204
# define ASN1_R_AUX_ERROR 100
# define ASN1_R_BAD_OBJECT_HEADER 102
# define ASN1_R_BAD_TEMPLATE 230
# define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 214
# define ASN1_R_BN_LIB 105
# define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_ASYNCERR_H
# define HEADER_ASYNCERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2020 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
@@ -20,10 +20,6 @@
# include <openssl/crypto.h>
# include <openssl/bioerr.h>
# ifndef OPENSSL_NO_SCTP
# include <openssl/e_os2.h>
# endif
#ifdef __cplusplus
extern "C" {
#endif
@@ -173,6 +169,7 @@ extern "C" {
*/
# define BIO_FLAGS_MEM_RDONLY 0x200
# define BIO_FLAGS_NONCLEAR_RST 0x400
# define BIO_FLAGS_IN_EOF 0x800
typedef union bio_addr_st BIO_ADDR;
typedef struct bio_addrinfo_st BIO_ADDRINFO;
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_BIOERR_H
# define HEADER_BIOERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2020 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
@@ -56,7 +56,7 @@ extern "C" {
* avoid leaking exponent information through timing,
* BN_mod_exp_mont() will call BN_mod_exp_mont_consttime,
* BN_div() will call BN_div_no_branch,
* BN_mod_inverse() will call BN_mod_inverse_no_branch.
* BN_mod_inverse() will call bn_mod_inverse_no_branch.
*/
# define BN_FLG_CONSTTIME 0x04
# define BN_FLG_SECURE 0x08
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_BNERR_H
# define HEADER_BNERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_BUFERR_H
# define HEADER_BUFERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -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) */
@@ -1,5 +1,5 @@
/*
* Copyright 2008-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2008-2019 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
@@ -284,8 +284,6 @@ int CMS_unsigned_add1_attr_by_txt(CMS_SignerInfo *si,
void *CMS_unsigned_get0_data_by_OBJ(CMS_SignerInfo *si, ASN1_OBJECT *oid,
int lastpos, int type);
# ifdef HEADER_X509V3_H
int CMS_get1_ReceiptRequest(CMS_SignerInfo *si, CMS_ReceiptRequest **prr);
CMS_ReceiptRequest *CMS_ReceiptRequest_create0(unsigned char *id, int idlen,
int allorfirst,
@@ -298,7 +296,6 @@ void CMS_ReceiptRequest_get0_values(CMS_ReceiptRequest *rr,
int *pallorfirst,
STACK_OF(GENERAL_NAMES) **plist,
STACK_OF(GENERAL_NAMES) **prto);
# endif
int CMS_RecipientInfo_kari_get0_alg(CMS_RecipientInfo *ri,
X509_ALGOR **palg,
ASN1_OCTET_STRING **pukm);
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_CMSERR_H
# define HEADER_CMSERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_CMS
@@ -101,6 +105,7 @@ int ERR_load_CMS_strings(void);
# define CMS_F_CMS_SIGNERINFO_VERIFY_CERT 153
# define CMS_F_CMS_SIGNERINFO_VERIFY_CONTENT 154
# define CMS_F_CMS_SIGN_RECEIPT 163
# define CMS_F_CMS_SI_CHECK_ATTRIBUTES 183
# define CMS_F_CMS_STREAM 155
# define CMS_F_CMS_UNCOMPRESS 156
# define CMS_F_CMS_VERIFY 157
@@ -110,6 +115,7 @@ int ERR_load_CMS_strings(void);
* CMS reason codes.
*/
# define CMS_R_ADD_SIGNER_ERROR 99
# define CMS_R_ATTRIBUTE_ERROR 161
# define CMS_R_CERTIFICATE_ALREADY_PRESENT 175
# define CMS_R_CERTIFICATE_HAS_NO_KEYID 160
# define CMS_R_CERTIFICATE_VERIFY_ERROR 100
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_COMPERR_H
# define HEADER_COMPERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_COMP
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_CONFERR_H
# define HEADER_CONFERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -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,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,12 +11,13 @@
#ifndef HEADER_CRYPTOERR_H
# define HEADER_CRYPTOERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
# include <openssl/symhacks.h>
int ERR_load_CRYPTO_strings(void);
/*
@@ -463,8 +463,6 @@ __owur int CTLOG_STORE_load_file(CTLOG_STORE *store, const char *file);
/*
* Loads the default CT log list into a |store|.
* See internal/cryptlib.h for the environment variable and file path that are
* consulted to find the default file.
* Returns 1 if loading is successful, or 0 otherwise.
*/
__owur int CTLOG_STORE_load_default_file(CTLOG_STORE *store);
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_CTERR_H
# define HEADER_CTERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_CT
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_DHERR_H
# define HEADER_DHERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_DH
@@ -162,6 +162,12 @@ DH *DSA_dup_DH(const DSA *r);
# define EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx, nbits) \
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
EVP_PKEY_CTRL_DSA_PARAMGEN_BITS, nbits, NULL)
# define EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx, qbits) \
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS, qbits, NULL)
# define EVP_PKEY_CTX_set_dsa_paramgen_md(ctx, md) \
EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DSA, EVP_PKEY_OP_PARAMGEN, \
EVP_PKEY_CTRL_DSA_PARAMGEN_MD, 0, (void *)(md))
# define EVP_PKEY_CTRL_DSA_PARAMGEN_BITS (EVP_PKEY_ALG_CTRL + 1)
# define EVP_PKEY_CTRL_DSA_PARAMGEN_Q_BITS (EVP_PKEY_ALG_CTRL + 2)
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_DSAERR_H
# define HEADER_DSAERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_DSA
@@ -57,6 +61,7 @@ int ERR_load_DSA_strings(void);
# define DSA_R_INVALID_DIGEST_TYPE 106
# define DSA_R_INVALID_PARAMETERS 112
# define DSA_R_MISSING_PARAMETERS 101
# define DSA_R_MISSING_PRIVATE_KEY 111
# define DSA_R_MODULUS_TOO_LARGE 103
# define DSA_R_NO_PARAMETERS_SET 107
# define DSA_R_PARAMETER_ENCODING_ERROR 105
@@ -43,7 +43,7 @@ extern "C" {
# define DTLS1_AL_HEADER_LENGTH 2
/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
/* Timeout multipliers */
# define DTLS1_TMO_READ_COUNT 2
# define DTLS1_TMO_WRITE_COUNT 2
@@ -1,5 +1,5 @@
/*
* 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
@@ -241,7 +241,7 @@ typedef UINT64 uint64_t;
defined(__osf__) || defined(__sgi) || defined(__hpux) || \
defined(OPENSSL_SYS_VMS) || defined (__OpenBSD__)
# include <inttypes.h>
# elif defined(_MSC_VER) && _MSC_VER<=1500
# elif defined(_MSC_VER) && _MSC_VER<1600
/*
* minimally required typdefs for systems not supporting inttypes.h or
* stdint.h: currently just older VC++
@@ -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-2018 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
@@ -142,7 +142,7 @@ const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group);
*/
int EC_METHOD_get_field_type(const EC_METHOD *meth);
/** Sets the generator and it's order/cofactor of a EC_GROUP object.
/** Sets the generator and its order/cofactor of a EC_GROUP object.
* \param group EC_GROUP object
* \param generator EC_POINT object with the generator.
* \param order the order of the group generated by the generator.
@@ -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
@@ -829,6 +832,8 @@ void EC_KEY_set_flags(EC_KEY *key, int flags);
void EC_KEY_clear_flags(EC_KEY *key, int flags);
int EC_KEY_decoded_from_explicit_params(const EC_KEY *key);
/** Creates a new EC_KEY object using a named curve as underlying
* EC_GROUP object.
* \param nid NID of the named curve.
@@ -1138,7 +1143,8 @@ void ECDSA_SIG_free(ECDSA_SIG *sig);
* (*pp += length of the DER encoded signature)).
* \param sig pointer to the ECDSA_SIG object
* \param pp pointer to a unsigned char pointer for the output or NULL
* \return the length of the DER encoded ECDSA_SIG object or 0
* \return the length of the DER encoded ECDSA_SIG object or a negative value
* on error
*/
int i2d_ECDSA_SIG(const ECDSA_SIG *sig, unsigned char **pp);
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2020 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
@@ -11,6 +11,10 @@
#ifndef HEADER_ECERR_H
# define HEADER_ECERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_EC
@@ -239,6 +243,7 @@ int ERR_load_EC_strings(void);
# define EC_R_LADDER_POST_FAILURE 136
# define EC_R_LADDER_PRE_FAILURE 153
# define EC_R_LADDER_STEP_FAILURE 162
# define EC_R_MISSING_OID 167
# define EC_R_MISSING_PARAMETERS 124
# define EC_R_MISSING_PRIVATE_KEY 125
# define EC_R_NEED_NEW_SETUP_VALUES 157
@@ -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; }
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_ENGINEERR_H
# define HEADER_ENGINEERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# include <openssl/opensslconf.h>
# ifndef OPENSSL_NO_ENGINE
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -37,6 +37,7 @@ extern "C" {
# define ERR_TXT_STRING 0x02
# define ERR_FLAG_MARK 0x01
# define ERR_FLAG_CLEAR 0x02
# define ERR_NUM_ERRORS 16
typedef struct err_state_st {
@@ -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
@@ -180,7 +180,7 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd,
* if the following flag is set.
*/
# define EVP_MD_CTX_FLAG_FINALISE 0x0200
/* NOTE: 0x0400 is reserved for internal usage in evp_int.h */
/* NOTE: 0x0400 is reserved for internal usage */
EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);
EVP_CIPHER *EVP_CIPHER_meth_dup(const EVP_CIPHER *cipher);
@@ -260,6 +260,8 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
# define EVP_CIPH_RAND_KEY 0x200
/* cipher has its own additional copying logic */
# define EVP_CIPH_CUSTOM_COPY 0x400
/* Don't use standard iv length function */
# define EVP_CIPH_CUSTOM_IV_LENGTH 0x800
/* Allow use default ASN1 get/set iv */
# define EVP_CIPH_FLAG_DEFAULT_ASN1 0x1000
/* Buffer length in bits not bytes: CFB1 mode only */
@@ -349,6 +351,8 @@ int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
/* Set the input buffer lengths to use for a pipelined operation */
# define EVP_CTRL_SET_PIPELINE_INPUT_LENS 0x24
# define EVP_CTRL_GET_IVLEN 0x25
/* Padding modes */
#define EVP_PADDING_PKCS7 1
#define EVP_PADDING_ISO7816_4 2
@@ -995,6 +999,7 @@ int EVP_PKEY_set_type_str(EVP_PKEY *pkey, const char *str, int len);
int EVP_PKEY_set_alias_type(EVP_PKEY *pkey, int type);
# ifndef OPENSSL_NO_ENGINE
int EVP_PKEY_set1_engine(EVP_PKEY *pkey, ENGINE *e);
ENGINE *EVP_PKEY_get0_engine(const EVP_PKEY *pkey);
# endif
int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key);
void *EVP_PKEY_get0(const EVP_PKEY *pkey);
@@ -1507,6 +1512,20 @@ void EVP_PKEY_meth_set_ctrl(EVP_PKEY_METHOD *pmeth,
const char *type,
const char *value));
void EVP_PKEY_meth_set_digestsign(EVP_PKEY_METHOD *pmeth,
int (*digestsign) (EVP_MD_CTX *ctx,
unsigned char *sig,
size_t *siglen,
const unsigned char *tbs,
size_t tbslen));
void EVP_PKEY_meth_set_digestverify(EVP_PKEY_METHOD *pmeth,
int (*digestverify) (EVP_MD_CTX *ctx,
const unsigned char *sig,
size_t siglen,
const unsigned char *tbs,
size_t tbslen));
void EVP_PKEY_meth_set_check(EVP_PKEY_METHOD *pmeth,
int (*check) (EVP_PKEY *pkey));
@@ -1612,6 +1631,20 @@ void EVP_PKEY_meth_get_ctrl(const EVP_PKEY_METHOD *pmeth,
const char *type,
const char *value));
void EVP_PKEY_meth_get_digestsign(EVP_PKEY_METHOD *pmeth,
int (**digestsign) (EVP_MD_CTX *ctx,
unsigned char *sig,
size_t *siglen,
const unsigned char *tbs,
size_t tbslen));
void EVP_PKEY_meth_get_digestverify(EVP_PKEY_METHOD *pmeth,
int (**digestverify) (EVP_MD_CTX *ctx,
const unsigned char *sig,
size_t siglen,
const unsigned char *tbs,
size_t tbslen));
void EVP_PKEY_meth_get_check(const EVP_PKEY_METHOD *pmeth,
int (**pcheck) (EVP_PKEY *pkey));
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 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
@@ -11,6 +11,8 @@
#ifndef HEADER_EVPERR_H
# define HEADER_EVPERR_H
# include <openssl/symhacks.h>
# ifdef __cplusplus
extern "C"
# endif
@@ -20,11 +22,14 @@ int ERR_load_EVP_strings(void);
* EVP function codes.
*/
# define EVP_F_AESNI_INIT_KEY 165
# define EVP_F_AESNI_XTS_INIT_KEY 207
# define EVP_F_AES_GCM_CTRL 196
# define EVP_F_AES_INIT_KEY 133
# define EVP_F_AES_OCB_CIPHER 169
# define EVP_F_AES_T4_INIT_KEY 178
# define EVP_F_AES_T4_XTS_INIT_KEY 208
# define EVP_F_AES_WRAP_CIPHER 170
# define EVP_F_AES_XTS_INIT_KEY 209
# define EVP_F_ALG_MODULE_INIT 177
# define EVP_F_ARIA_CCM_INIT_KEY 175
# define EVP_F_ARIA_GCM_CTRL 197
@@ -115,6 +120,7 @@ int ERR_load_EVP_strings(void);
# define EVP_F_PKEY_SET_TYPE 158
# define EVP_F_RC2_MAGIC_TO_METH 109
# define EVP_F_RC5_CTRL 125
# define EVP_F_R_32_12_16_INIT_KEY 242
# define EVP_F_S390X_AES_GCM_CTRL 201
# define EVP_F_UPDATE 173
@@ -124,6 +130,7 @@ int ERR_load_EVP_strings(void);
# define EVP_R_AES_KEY_SETUP_FAILED 143
# define EVP_R_ARIA_KEY_SETUP_FAILED 176
# define EVP_R_BAD_DECRYPT 100
# define EVP_R_BAD_KEY_LENGTH 195
# define EVP_R_BUFFER_TOO_SMALL 155
# define EVP_R_CAMELLIA_KEY_SETUP_FAILED 157
# define EVP_R_CIPHER_PARAMETER_ERROR 122
@@ -151,6 +158,7 @@ int ERR_load_EVP_strings(void);
# define EVP_R_INPUT_NOT_INITIALIZED 111
# define EVP_R_INVALID_DIGEST 152
# define EVP_R_INVALID_FIPS_MODE 168
# define EVP_R_INVALID_IV_LENGTH 194
# define EVP_R_INVALID_KEY 163
# define EVP_R_INVALID_KEY_LENGTH 130
# define EVP_R_INVALID_OPERATION 148
@@ -169,6 +177,7 @@ int ERR_load_EVP_strings(void);
# define EVP_R_ONLY_ONESHOT_SUPPORTED 177
# define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 150
# define EVP_R_OPERATON_NOT_INITIALIZED 151
# define EVP_R_OUTPUT_WOULD_OVERFLOW 184
# define EVP_R_PARTIALLY_OVERLAPPING 162
# define EVP_R_PBKDF2_ERROR 181
# define EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED 179
@@ -190,5 +199,6 @@ int ERR_load_EVP_strings(void);
# define EVP_R_UNSUPPORTED_SALT_TYPE 126
# define EVP_R_WRAP_MODE_NOT_ALLOWED 170
# define EVP_R_WRONG_FINAL_BLOCK_LENGTH 109
# define EVP_R_XTS_DUPLICATED_KEYS 183
#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
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_KDFERR_H
# define HEADER_KDFERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif
@@ -1,5 +1,5 @@
/*
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2020 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
@@ -120,9 +120,8 @@ void OPENSSL_LH_node_usage_stats_bio(const OPENSSL_LHASH *lh, BIO *out);
# define DEFINE_LHASH_OF(type) \
LHASH_OF(type) { union lh_##type##_dummy { void* d1; unsigned long d2; int d3; } dummy; }; \
static ossl_inline LHASH_OF(type) * \
lh_##type##_new(unsigned long (*hfn)(const type *), \
int (*cfn)(const type *, const type *)) \
static ossl_unused ossl_inline LHASH_OF(type) *lh_##type##_new(unsigned long (*hfn)(const type *), \
int (*cfn)(const type *, const type *)) \
{ \
return (LHASH_OF(type) *) \
OPENSSL_LH_new((OPENSSL_LH_HASHFUNC)hfn, (OPENSSL_LH_COMPFUNC)cfn); \
@@ -2,7 +2,7 @@
* WARNING: do not edit!
* Generated by crypto/objects/objects.pl
*
* Copyright 2000-2019 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
@@ -1290,12 +1290,12 @@
#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
#define SN_ms_smartcard_login "msSmartcardLogin"
#define LN_ms_smartcard_login "Microsoft Smartcardlogin"
#define LN_ms_smartcard_login "Microsoft Smartcard Login"
#define NID_ms_smartcard_login 648
#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L
#define SN_ms_upn "msUPN"
#define LN_ms_upn "Microsoft Universal Principal Name"
#define LN_ms_upn "Microsoft User Principal Name"
#define NID_ms_upn 649
#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L
@@ -4280,7 +4280,7 @@
#define SN_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15 "id-tc26-wrap-gostr3412-2015-kuznyechik-kexp15"
#define NID_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15 1183
#define OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15 OBJ_id_tc26_wrap_gostr3412_2015_magma,1L
#define OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik_kexp15 OBJ_id_tc26_wrap_gostr3412_2015_kuznyechik,1L
#define SN_id_tc26_constants "id-tc26-constants"
#define NID_id_tc26_constants 994
@@ -1,6 +1,6 @@
/*
* Generated by util/mkerr.pl DO NOT EDIT
* Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 1995-2019 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
@@ -11,6 +11,10 @@
#ifndef HEADER_OBJERR_H
# define HEADER_OBJERR_H
# ifndef HEADER_SYMHACKS_H
# include <openssl/symhacks.h>
# endif
# ifdef __cplusplus
extern "C"
# endif

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