mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2026-10-12 03:24:05 +00:00
Compare commits
366
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
852b7d91a2 | ||
|
|
9ac73b277d | ||
|
|
9ab512da53 | ||
|
|
702303aced | ||
|
|
4d532bbc14 | ||
|
|
c630ba9f93 | ||
|
|
001bda3c02 | ||
|
|
bac33afa9c | ||
|
|
90c9034fbe | ||
|
|
8cab75926a | ||
|
|
5c0c2390b2 | ||
|
|
b55b4b6d68 | ||
|
|
4dc95b563c | ||
|
|
31b700304a | ||
|
|
ddb674a9b9 | ||
|
|
abde6021e8 | ||
|
|
ad8614907c | ||
|
|
8974dcda6e | ||
|
|
6d4c64a575 | ||
|
|
68adf9ecc9 | ||
|
|
3df0103a8c | ||
|
|
8d720748c1 | ||
|
|
578f38f6a5 | ||
|
|
280454fdb0 | ||
|
|
0711e236c0 | ||
|
|
b9c5edddef | ||
|
|
3c6a0d12f5 | ||
|
|
583f662a87 | ||
|
|
3f114ac76c | ||
|
|
4b2221d374 | ||
|
|
c2e224ebf8 | ||
|
|
0dc4c4fe67 | ||
|
|
9221a0ca3a | ||
|
|
b3a7e32a08 | ||
|
|
1fa0e2a0f9 | ||
|
|
9d8b073ca5 | ||
|
|
03bdf30d0a | ||
|
|
6e15cc5fa3 | ||
|
|
9d26550264 | ||
|
|
7ffde1e8fc | ||
|
|
30d234d71e | ||
|
|
a75104f13d | ||
|
|
73d3180d20 | ||
|
|
f51be309a0 | ||
|
|
a7a424cf27 | ||
|
|
19dc67eb47 | ||
|
|
9869f3125f | ||
|
|
8a8efc0dcf | ||
|
|
54e1f2a124 | ||
|
|
f827e96e1a | ||
|
|
5835fb832c | ||
|
|
9484275ab6 | ||
|
|
2a0ccb88bb | ||
|
|
d3eb327f63 | ||
|
|
c122bcd45b | ||
|
|
16b6cf6edb | ||
|
|
325bc3349e | ||
|
|
7416477763 | ||
|
|
bcd8c8f77d | ||
|
|
d44432ed81 | ||
|
|
d46f5d4353 | ||
|
|
27ded2add8 | ||
|
|
9b0bfaf079 | ||
|
|
522d61d7e2 | ||
|
|
8550e99463 | ||
|
|
2f6deb72b3 | ||
|
|
10941746e4 | ||
|
|
4827b0e6de | ||
|
|
f10085f552 | ||
|
|
eb7f0887bf | ||
|
|
34a9132d60 | ||
|
|
24d3fb000a | ||
|
|
b7b6adaff7 | ||
|
|
85ed72802f | ||
|
|
e1fcb19b23 | ||
|
|
2df69bcdea | ||
|
|
454b443b81 | ||
|
|
f97704764a | ||
|
|
9ef23038ab | ||
|
|
e48c38f47a | ||
|
|
cf64d102de | ||
|
|
2716c68c7a | ||
|
|
f54f8c83e7 | ||
|
|
124bfdf418 | ||
|
|
01507d9995 | ||
|
|
070c82bc44 | ||
|
|
17df15293f | ||
|
|
6551076613 | ||
|
|
1b1b100e63 | ||
|
|
d73b9e16da | ||
|
|
cc788e4410 | ||
|
|
e70014bb28 | ||
|
|
082cc84a71 | ||
|
|
2ba7f0d989 | ||
|
|
9a7381b35f | ||
|
|
613ecfff44 | ||
|
|
f638548a02 | ||
|
|
224bab68bf | ||
|
|
6aca18bd76 | ||
|
|
3c58e2fbba | ||
|
|
aaaebde05e | ||
|
|
8ff9f70bd7 | ||
|
|
523ca862b9 | ||
|
|
78b8d1e9f3 | ||
|
|
83c698b36d | ||
|
|
27fe37f221 | ||
|
|
3722106daf | ||
|
|
3ea9ef1ef2 | ||
|
|
fcd27b48b2 | ||
|
|
6ff37a17ec | ||
|
|
f2c6e9e32e | ||
|
|
dbf1b88a3d | ||
|
|
3aab9eb13b | ||
|
|
3f9f8f7b3b | ||
|
|
f7520ba40c | ||
|
|
7b13f12817 | ||
|
|
57e19d75e2 | ||
|
|
4330a223c6 | ||
|
|
69387c32ad | ||
|
|
a102ec4ee8 | ||
|
|
2a094437dd | ||
|
|
4142907376 | ||
|
|
e63dc9a93b | ||
|
|
1fe19e912e | ||
|
|
56ad48446e | ||
|
|
a18aa26985 | ||
|
|
5443cc014a | ||
|
|
7d77e1c1f2 | ||
|
|
ca82cd9752 | ||
|
|
dbd86bb861 | ||
|
|
0af56b4981 | ||
|
|
f1be5365bb | ||
|
|
c356862ac1 | ||
|
|
fc77322f59 | ||
|
|
032e944d49 | ||
|
|
0da47da8d8 | ||
|
|
ebfe843299 | ||
|
|
827d2362b7 | ||
|
|
4fa1eb4088 | ||
|
|
885b59fd52 | ||
|
|
ff5d9f72aa | ||
|
|
030bb91789 | ||
|
|
34788b2808 | ||
|
|
abc4123c52 | ||
|
|
26f8c0842e | ||
|
|
d430d83ba8 | ||
|
|
a52f189fb1 | ||
|
|
dc1045b69e | ||
|
|
3a89dbf4ab | ||
|
|
d69b4eca1e | ||
|
|
568bba82f0 | ||
|
|
b52e6c88ec | ||
|
|
720595091e | ||
|
|
fe929c8e58 | ||
|
|
9ecec1eb3c | ||
|
|
79532f6f14 | ||
|
|
b400ba385e | ||
|
|
9915007f30 | ||
|
|
0168a55596 | ||
|
|
229eff49fb | ||
|
|
0e3b472f78 | ||
|
|
5f29b30d34 | ||
|
|
9480363362 | ||
|
|
5dd80edde4 | ||
|
|
2243cf2017 | ||
|
|
d7791c8543 | ||
|
|
30822c1ba5 | ||
|
|
d250f4dc60 | ||
|
|
bc27492206 | ||
|
|
2b63203a5b | ||
|
|
dc9a26f57b | ||
|
|
6f2d7464ba | ||
|
|
6996c101b4 | ||
|
|
99dc773c7a | ||
|
|
6ec3f9455a | ||
|
|
6589a568e2 | ||
|
|
55da48e28c | ||
|
|
081cca48fb | ||
|
|
6b6a93725c | ||
|
|
c280a52d33 | ||
|
|
b659439f0b | ||
|
|
6453b3c45c | ||
|
|
978a879c43 | ||
|
|
833ef3630b | ||
|
|
024b8c93bc | ||
|
|
d32c4f86a7 | ||
|
|
cafc4450b2 | ||
|
|
7d69b53958 | ||
|
|
4d3e883e49 | ||
|
|
8f9a687872 | ||
|
|
08d509d831 | ||
|
|
b06dec8449 | ||
|
|
28c93b934b | ||
|
|
394a57a26d | ||
|
|
3856b57a6f | ||
|
|
9a3a076890 | ||
|
|
314dfcddcf | ||
|
|
1a85bda997 | ||
|
|
e8b30d5a88 | ||
|
|
96bd1a7799 | ||
|
|
cb0a1f13bc | ||
|
|
e92fdeef47 | ||
|
|
62bae62386 | ||
|
|
2636d79b86 | ||
|
|
c9c1ef91fd | ||
|
|
ce7bba3e09 | ||
|
|
bfd53f39bd | ||
|
|
554fee037c | ||
|
|
67b2853ef0 | ||
|
|
0e29e13d03 | ||
|
|
35f2a238e9 | ||
|
|
fcb34ab6ee | ||
|
|
3fbf682785 | ||
|
|
16086a6d3f | ||
|
|
18b6aae381 | ||
|
|
642c353164 | ||
|
|
42f64e5e88 | ||
|
|
6af748b2cc | ||
|
|
4fe97b69c7 | ||
|
|
04d46272dd | ||
|
|
1c0290dc7a | ||
|
|
38588402e3 | ||
|
|
dfe3b8888d | ||
|
|
e8f4022f1e | ||
|
|
e37bb32c82 | ||
|
|
1f72c82acb | ||
|
|
e6876926a4 | ||
|
|
2b8a43ab13 | ||
|
|
8737466368 | ||
|
|
83916fa43e | ||
|
|
1fe5a12a45 | ||
|
|
fa7f3115ed | ||
|
|
4dc6143440 | ||
|
|
f1503aa56c | ||
|
|
67f344b755 | ||
|
|
f1bcc217a9 | ||
|
|
458460515d | ||
|
|
3a78095574 | ||
|
|
d6bbfa1af1 | ||
|
|
4e1b778f31 | ||
|
|
5f4496036c | ||
|
|
d4079940b4 | ||
|
|
803ad116fb | ||
|
|
27701eda49 | ||
|
|
71c831b02d | ||
|
|
0d72a0e009 | ||
|
|
69a4502f90 | ||
|
|
daaa7f4e63 | ||
|
|
d1579e9b0d | ||
|
|
5890fff240 | ||
|
|
d6f6307050 | ||
|
|
6bf9c31860 | ||
|
|
a2e628f3f8 | ||
|
|
8f5416ff31 | ||
|
|
db86f18133 | ||
|
|
419e4e656e | ||
|
|
eed4327d26 | ||
|
|
5c6eaf2602 | ||
|
|
71169ed740 | ||
|
|
dca8d93aa8 | ||
|
|
6cb152f602 | ||
|
|
ddefda3afa | ||
|
|
7f15f45beb | ||
|
|
46f887efec | ||
|
|
90afecd766 | ||
|
|
388343c3ee | ||
|
|
c8df37e89e | ||
|
|
cc85d5c343 | ||
|
|
f8437cdb8f | ||
|
|
c99a210905 | ||
|
|
e33673c9e9 | ||
|
|
79283e93cb | ||
|
|
a60e85a3a4 | ||
|
|
80910ed38d | ||
|
|
825a338474 | ||
|
|
19b6e94824 | ||
|
|
0b581011c5 | ||
|
|
6b7669bb75 | ||
|
|
67bcc56c6d | ||
|
|
7d8cfa3c6a | ||
|
|
f659af29da | ||
|
|
94b202f7b6 | ||
|
|
ca86fdafab | ||
|
|
370dbb1a10 | ||
|
|
f77543cd9b | ||
|
|
7104e0d725 | ||
|
|
230a67cac0 | ||
|
|
a695f38974 | ||
|
|
151c09f098 | ||
|
|
8200f5690d | ||
|
|
77a8cf2704 | ||
|
|
fe424961e1 | ||
|
|
b668cb78ff | ||
|
|
48278419b0 | ||
|
|
632da03667 | ||
|
|
d36b73fc1b | ||
|
|
292ed35555 | ||
|
|
02d0ad496f | ||
|
|
eb2fc7af40 | ||
|
|
6550deedbb | ||
|
|
80acd9b9eb | ||
|
|
b961636f02 | ||
|
|
f4df0714b5 | ||
|
|
91dd7b7049 | ||
|
|
121bef7d2d | ||
|
|
3a9eabf50b | ||
|
|
c8198b4091 | ||
|
|
e4538e4a51 | ||
|
|
b47f3ef397 | ||
|
|
6e096c0ac3 | ||
|
|
ee3b4686bf | ||
|
|
759b77eafe | ||
|
|
de15ec666f | ||
|
|
3de86f15af | ||
|
|
1b9dff719c | ||
|
|
abcf4e3d4a | ||
|
|
9823abe686 | ||
|
|
723e08f69b | ||
|
|
daf0a0891e | ||
|
|
49dc68f77f | ||
|
|
f81a1c36cc | ||
|
|
9a11a771dd | ||
|
|
b56a4b8b49 | ||
|
|
1aa963992b | ||
|
|
1b601324d0 | ||
|
|
1aea723ef0 | ||
|
|
1e828a10b9 | ||
|
|
970423f873 | ||
|
|
2d7493fd1e | ||
|
|
fa7eb1c4b1 | ||
|
|
4916af3697 | ||
|
|
8484bf1cb9 | ||
|
|
005afb3c73 | ||
|
|
84b0d004b9 | ||
|
|
aa41bf8d97 | ||
|
|
fba9a125bf | ||
|
|
27312bd146 | ||
|
|
8f0c267ab8 | ||
|
|
a15d6a6b42 | ||
|
|
8f9061b250 | ||
|
|
ec57499e08 | ||
|
|
381598c5b6 | ||
|
|
452d020da5 | ||
|
|
b5f875c2e5 | ||
|
|
a31daeda96 | ||
|
|
437f52f53a | ||
|
|
33f0f7ecf0 | ||
|
|
6777e79e70 | ||
|
|
16d1e6181b | ||
|
|
a6c8db6c2c | ||
|
|
24aa0fecbe | ||
|
|
1a776b1990 | ||
|
|
27df265c81 | ||
|
|
84c0372719 | ||
|
|
3879e57c4c | ||
|
|
dcc3dcdaba | ||
|
|
d166635c7b | ||
|
|
33d484b7d1 | ||
|
|
26bff28e4d | ||
|
|
56eddff8d6 | ||
|
|
37b9133eb6 | ||
|
|
4a64967b1f | ||
|
|
23152b1264 | ||
|
|
c11338039f | ||
|
|
e712669d32 | ||
|
|
3768ae33b7 |
@@ -1,48 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Follow the troubleshooting guide before reporting a bug
|
||||
|
||||
---
|
||||
**READ ME FIRST!**
|
||||
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
|
||||
|
||||
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Steps to reproduce**
|
||||
Any special steps that are required for the bug to appear.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
|
||||
|
||||
**Affected games**
|
||||
List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
|
||||
|
||||
**Other Moonlight clients**
|
||||
- Does the issue occur when using Moonlight on PC or iOS?
|
||||
|
||||
**Moonlight settings (please complete the following information)**
|
||||
- Have any settings been adjusted from defaults?
|
||||
- If so, which settings have been changed?
|
||||
- Does the problem still occur after reverting settings back to default?
|
||||
|
||||
**Gamepad-related issues (please complete if problem is gamepad-related)**
|
||||
- Do you have any gamepads connected to your host PC directly?
|
||||
- If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
|
||||
- Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
|
||||
- Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
|
||||
|
||||
**Device details (please complete the following information)**
|
||||
- Android version: [e.g. Android 10]
|
||||
- Device model: [e.g. Samsung Galaxy S21]
|
||||
|
||||
**Server PC details (please complete the following information)**
|
||||
- OS: [e.g. Windows 10 1809]
|
||||
- GeForce Experience version: [e.g. 3.16.0.140]
|
||||
- Nvidia GPU driver: [e.g. 417.35]
|
||||
- Antivirus and firewall software: [e.g. Windows Defender and Windows Firewall]
|
||||
|
||||
**Additional context**
|
||||
Anything else you think may be relevant to the issue or special about your specific setup.
|
||||
@@ -0,0 +1,176 @@
|
||||
name: Bug report
|
||||
description: Follow the troubleshooting guide before reporting a bug
|
||||
title: "[Issue]: "
|
||||
labels: bug
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to fill out this bug form!
|
||||
|
||||
**READ ME FIRST!**
|
||||
If you're here because something basic is not working (like gamepad input, video, or similar), it's probably something specific to your setup, so make sure you've gone through the Troubleshooting Guide first: https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting
|
||||
|
||||
If you still have trouble with basic functionality after following the guide, join our Discord server where there are many other volunteers who can help (or direct you back here if it looks like a Moonlight bug after all). https://moonlight-stream.org/discord
|
||||
- type: textarea
|
||||
id: describe-bug
|
||||
attributes:
|
||||
label: Describe the bug
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps-reproduce
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Any special steps that are required for the bug to appear.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: affected-games
|
||||
attributes:
|
||||
label: Affected games
|
||||
description: List the games you've tried that exhibit the issue. To see if the issue is game-specific, try streaming Steam Big Picture with Moonlight and see if the issue persists there.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: other-clients
|
||||
attributes:
|
||||
label: Other Moonlight clients
|
||||
description: Does the issue occur when using Moonlight on PC or iOS?
|
||||
options:
|
||||
- "PC"
|
||||
- "iOS"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: settings-adjusted
|
||||
attributes:
|
||||
label: Moonlight adjusted settings
|
||||
description: Have any settings been adjusted from defaults?
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: settings-adjusted-settings
|
||||
attributes:
|
||||
label: Moonlight adjusted settings (please complete the following information)
|
||||
description: If the settings have been adjusted, which settings have been changed?
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: settings-default
|
||||
attributes:
|
||||
label: Moonlight default settings
|
||||
description: Does the problem still occur after reverting settings back to default?
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: gamepad-connected
|
||||
attributes:
|
||||
label: Gamepad-related connection issue
|
||||
description: Do you have any gamepads connected to your host PC directly?
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: gamepad-on-screen
|
||||
attributes:
|
||||
label: Gamepad-related input issue
|
||||
description: If gamepad input is not working, does it work if you use Moonlight's on-screen controls?
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: gamepad-test
|
||||
attributes:
|
||||
label: Gamepad-related streaming issue
|
||||
description: |
|
||||
Does the problem still remain if you stream the desktop and use https://html5gamepad.com to test your gamepad?
|
||||
Instructions for streaming the desktop can be found here: https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide
|
||||
options:
|
||||
- "Yes"
|
||||
- "No"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: android
|
||||
attributes:
|
||||
label: Android version
|
||||
description: What is the Android version?
|
||||
placeholder: e.g. Android 10
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: device
|
||||
attributes:
|
||||
label: Device model
|
||||
description: What is the device model?
|
||||
placeholder: e.g. Samsung Galaxy S21
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-os
|
||||
attributes:
|
||||
label: Server PC OS version
|
||||
description: What is the PC OS version?
|
||||
placeholder: e.g. Windows 10 1809
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-geforce
|
||||
attributes:
|
||||
label: Server PC GeForce Experience version
|
||||
description: What is the GeForce Experience version?
|
||||
placeholder: e.g. 3.16.0.140
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-driver
|
||||
attributes:
|
||||
label: Server PC Nvidia GPU driver version
|
||||
description: What is the Nvidia GPU driver version?
|
||||
placeholder: e.g. 417.35
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server-antivirus
|
||||
attributes:
|
||||
label: Server PC antivirus and firewall software
|
||||
description: Which antivirus and firewall software are installed on the Server PC?
|
||||
placeholder: e.g. Windows Defender and Windows Firewall
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: If applicable, add screenshots to help explain your problem. If the issue is related to video glitching or poor quality, please include screenshots.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: |
|
||||
Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: Shell
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Anything else you think may be relevant to the issue or special about your specific setup.
|
||||
validations:
|
||||
required: false
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
title: "[Feature request]: "
|
||||
labels: enhancement
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thank you for taking the time to fill out this feature form!
|
||||
- type: textarea
|
||||
id: feature
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: screenshots
|
||||
attributes:
|
||||
label: Screenshots
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
validations:
|
||||
required: false
|
||||
@@ -3,7 +3,7 @@
|
||||
[](https://ci.appveyor.com/project/cgutman/moonlight-android/branch/master)
|
||||
[](https://hosted.weblate.org/projects/moonlight/moonlight-android/)
|
||||
|
||||
[Moonlight for Android](https://moonlight-stream.org) is an open source client for NVIDIA GameStream, as used by the NVIDIA Shield.
|
||||
[Moonlight for Android](https://moonlight-stream.org) is an open source client for NVIDIA GameStream and [Sunshine](https://github.com/LizardByte/Sunshine).
|
||||
|
||||
Moonlight for Android will allow you to stream your full collection of games from your Windows PC to your Android device,
|
||||
whether in your own home or over the internet.
|
||||
|
||||
+29
-20
@@ -1,16 +1,18 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
ndkVersion "23.2.8568313"
|
||||
ndkVersion "29.0.14206865"
|
||||
|
||||
compileSdk 33
|
||||
compileSdk 37
|
||||
|
||||
namespace 'com.limelight'
|
||||
|
||||
defaultConfig {
|
||||
minSdk 16
|
||||
targetSdk 33
|
||||
minSdk 21
|
||||
targetSdk 36
|
||||
|
||||
versionName "10.10"
|
||||
versionCode = 298
|
||||
versionName "12.1"
|
||||
versionCode = 314
|
||||
|
||||
// Generate native debug symbols to allow Google Play to symbolicate our native crashes
|
||||
ndk.debugSymbolLevel = 'FULL'
|
||||
@@ -18,6 +20,11 @@ android {
|
||||
|
||||
flavorDimensions.add("root")
|
||||
|
||||
buildFeatures {
|
||||
buildConfig = true
|
||||
resValues = true
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
root {
|
||||
// Android O has native mouse capture, so don't show the rooted
|
||||
@@ -50,8 +57,8 @@ android {
|
||||
|
||||
compileOptions {
|
||||
encoding "UTF-8"
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
lint {
|
||||
@@ -78,9 +85,6 @@ android {
|
||||
applicationIdSuffix ".debug"
|
||||
resValue "string", "app_label", "Moonlight (Debug)"
|
||||
resValue "string", "app_label_root", "Moonlight (Root Debug)"
|
||||
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
release {
|
||||
// To whomever is releasing/using an APK in release mode with
|
||||
@@ -118,7 +122,7 @@ android {
|
||||
resValue "string", "app_label_root", "Moonlight (Root)"
|
||||
|
||||
minifyEnabled true
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,15 +131,20 @@ android {
|
||||
path "src/main/jni/Android.mk"
|
||||
}
|
||||
}
|
||||
|
||||
packaging {
|
||||
resources {
|
||||
// BouncyCastle includes duplicate LICENSE.md files
|
||||
excludes += '/META-INF/*.md'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
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.13'
|
||||
implementation 'com.squareup.okio:okio:1.17.5'
|
||||
// 3.5.8 requires minSdk 19, uses StandardCharsets.UTF_8 internally
|
||||
implementation 'org.jmdns:jmdns:3.5.7'
|
||||
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0'
|
||||
implementation 'org.bouncycastle:bcprov-jdk18on:1.85.2'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk18on:1.85'
|
||||
implementation 'org.jcodec:jcodec:0.2.5'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||
implementation 'org.jmdns:jmdns:3.6.3'
|
||||
implementation 'com.github.cgutman:ShieldControllerExtensions:1.0.1'
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.limelight">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.CAPTURE_KEYBOARD" />
|
||||
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA"/>
|
||||
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA"/>
|
||||
|
||||
<!-- We don't need a MulticastLock on API level 34+ because we use NsdManager for mDNS -->
|
||||
<uses-permission
|
||||
android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
|
||||
android:maxSdkVersion="33" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false" />
|
||||
@@ -26,6 +30,12 @@
|
||||
<uses-feature
|
||||
android:name="android.software.leanback"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.accelerometer"
|
||||
android:required="false" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.sensor.gyroscope"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Disable legacy input emulation on ChromeOS -->
|
||||
<uses-feature
|
||||
@@ -41,7 +51,6 @@
|
||||
android:banner="@drawable/atv_banner"
|
||||
android:appCategory="game"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:installLocation="auto"
|
||||
android:gwpAsanMode="always"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
@@ -68,6 +77,11 @@
|
||||
<meta-data
|
||||
android:name="com.android.graphics.intervention.wm.allowDownscale"
|
||||
android:value="false"/>
|
||||
|
||||
<!-- Game Mode configuration -->
|
||||
<meta-data
|
||||
android:name="android.game_mode_config"
|
||||
android:resource="@xml/game_mode_config" />
|
||||
|
||||
<!-- Samsung DeX support requires explicit placement of android:resizeableActivity="true"
|
||||
in each activity even though it is implied by targeting API 24+ -->
|
||||
@@ -76,7 +90,12 @@
|
||||
android:name=".PcView"
|
||||
android:exported="true"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
@@ -92,37 +111,37 @@
|
||||
android:noHistory="true"
|
||||
android:exported="true"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".AppView"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".preferences.StreamSettings"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
||||
android:label="Streaming Settings">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".preferences.AddComputerManually"
|
||||
android:resizeableActivity="true"
|
||||
android:windowSoftInputMode="stateVisible"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection"
|
||||
android:label="Add Computer Manually">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".Game"
|
||||
@@ -130,13 +149,14 @@
|
||||
android:noHistory="true"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="false"
|
||||
android:launchMode="singleTask"
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@style/StreamTheme"
|
||||
android:preferMinimalPostProcessing="true">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.AppView" />
|
||||
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
|
||||
<!-- Special metadata for NVIDIA Shield devices to prevent input buffering
|
||||
and most importantly, opt out of mouse acceleration while streaming -->
|
||||
@@ -161,10 +181,10 @@
|
||||
<activity
|
||||
android:name=".HelpActivity"
|
||||
android:resizeableActivity="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:configChanges="mcc|mnc|touchscreen|keyboard|keyboardHidden|navigation|screenLayout|fontScale|uiMode|orientation|screenSize|smallestScreenSize|layoutDirection">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="com.limelight.PcView" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="system-default" />
|
||||
<meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="landscape" />
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,12 +71,6 @@ public class HelpActivity extends Activity {
|
||||
|
||||
refreshBackDispatchState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String url) {
|
||||
return !(url.toUpperCase().startsWith("https://github.com/moonlight-stream/moonlight-docs/wiki/".toUpperCase()) ||
|
||||
url.toUpperCase().startsWith("http://github.com/moonlight-stream/moonlight-docs/wiki/".toUpperCase()));
|
||||
}
|
||||
});
|
||||
|
||||
webView.loadUrl(getIntent().getData().toString());
|
||||
|
||||
@@ -118,6 +118,7 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
private final static int VIEW_DETAILS_ID = 8;
|
||||
private final static int FULL_APP_LIST_ID = 9;
|
||||
private final static int TEST_NETWORK_ID = 10;
|
||||
private final static int GAMESTREAM_EOL_ID = 11;
|
||||
|
||||
private void initializeViews() {
|
||||
setContentView(R.layout.activity_pc_view);
|
||||
@@ -259,6 +260,11 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
updateComputer(details);
|
||||
}
|
||||
});
|
||||
|
||||
// Add a launcher shortcut for this PC (off the main thread to prevent ANRs)
|
||||
if (details.pairState == PairState.PAIRED) {
|
||||
shortcutHelper.createAppViewShortcutForOnlineHost(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -352,9 +358,13 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
if (computer.details.state == ComputerDetails.State.OFFLINE ||
|
||||
computer.details.state == ComputerDetails.State.UNKNOWN) {
|
||||
menu.add(Menu.NONE, WOL_ID, 1, getResources().getString(R.string.pcview_menu_send_wol));
|
||||
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 2, getResources().getString(R.string.pcview_menu_eol));
|
||||
}
|
||||
else if (computer.details.pairState != PairState.PAIRED) {
|
||||
menu.add(Menu.NONE, PAIR_ID, 1, getResources().getString(R.string.pcview_menu_pair_pc));
|
||||
if (computer.details.nvidiaServer) {
|
||||
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 2, getResources().getString(R.string.pcview_menu_eol));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (computer.details.runningGameId != 0) {
|
||||
@@ -362,6 +372,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
menu.add(Menu.NONE, QUIT_ID, 2, getResources().getString(R.string.applist_menu_quit));
|
||||
}
|
||||
|
||||
if (computer.details.nvidiaServer) {
|
||||
menu.add(Menu.NONE, GAMESTREAM_EOL_ID, 3, getResources().getString(R.string.pcview_menu_eol));
|
||||
}
|
||||
|
||||
menu.add(Menu.NONE, FULL_APP_LIST_ID, 4, getResources().getString(R.string.pcview_menu_app_list));
|
||||
}
|
||||
|
||||
@@ -412,7 +426,8 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
|
||||
// Spin the dialog off in a thread because it blocks
|
||||
Dialog.displayDialog(PcView.this, getResources().getString(R.string.pair_pairing_title),
|
||||
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr, false);
|
||||
getResources().getString(R.string.pair_pairing_msg)+" "+pinStr+"\n\n"+
|
||||
getResources().getString(R.string.pair_pairing_help), false);
|
||||
|
||||
PairingManager pm = httpConn.getPairingManager();
|
||||
|
||||
@@ -656,6 +671,10 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
ServerHelper.doNetworkTest(PcView.this);
|
||||
return true;
|
||||
|
||||
case GAMESTREAM_EOL_ID:
|
||||
HelpLauncher.launchGameStreamEolFaq(PcView.this);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
@@ -706,11 +725,6 @@ public class PcView extends Activity implements AdapterFragmentCallbacks {
|
||||
}
|
||||
}
|
||||
|
||||
// Add a launcher shortcut for this PC
|
||||
if (details.pairState == PairState.PAIRED) {
|
||||
shortcutHelper.createAppViewShortcutForOnlineHost(details);
|
||||
}
|
||||
|
||||
if (existingEntry != null) {
|
||||
// Replace the information in the existing entry
|
||||
existingEntry.details = details;
|
||||
|
||||
@@ -8,19 +8,26 @@ import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import com.limelight.computers.ComputerDatabaseManager;
|
||||
import com.limelight.computers.ComputerManagerListener;
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.nvstream.http.PairingManager;
|
||||
import com.limelight.nvstream.wol.WakeOnLanSender;
|
||||
import com.limelight.utils.CacheHelper;
|
||||
import com.limelight.utils.Dialog;
|
||||
import com.limelight.utils.ServerHelper;
|
||||
import com.limelight.utils.SpinnerDialog;
|
||||
import com.limelight.utils.UiHelper;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ShortcutTrampoline extends Activity {
|
||||
@@ -33,6 +40,7 @@ public class ShortcutTrampoline extends Activity {
|
||||
private SpinnerDialog blockingLoadSpinner;
|
||||
|
||||
private ComputerManagerService.ComputerManagerBinder managerBinder;
|
||||
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||
final ComputerManagerService.ComputerManagerBinder localBinder =
|
||||
@@ -214,9 +222,9 @@ public class ShortcutTrampoline extends Activity {
|
||||
}
|
||||
};
|
||||
|
||||
protected boolean validateInput(String uuidString, String appIdString) {
|
||||
// Validate UUID
|
||||
if (uuidString == null) {
|
||||
protected boolean validateInput(String uuidString, String appIdString, String nameString) {
|
||||
// Validate PC UUID/Name
|
||||
if (uuidString == null && nameString == null) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_uuid),
|
||||
@@ -224,14 +232,25 @@ public class ShortcutTrampoline extends Activity {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
UUID.fromString(uuidString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_uuid),
|
||||
true);
|
||||
return false;
|
||||
if (uuidString != null && !uuidString.isEmpty()) {
|
||||
try {
|
||||
UUID.fromString(uuidString);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_uuid),
|
||||
true);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// UUID is null, so fallback to Name
|
||||
if (nameString == null || nameString.isEmpty()) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_uuid),
|
||||
true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate App ID (if provided)
|
||||
@@ -255,24 +274,93 @@ public class ShortcutTrampoline extends Activity {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
UiHelper.notifyNewRootView(this);
|
||||
ComputerDatabaseManager dbManager = new ComputerDatabaseManager(this);
|
||||
ComputerDetails _computer = null;
|
||||
|
||||
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
||||
// PC arguments, both are optional, but at least one must be provided
|
||||
uuidString = getIntent().getStringExtra(AppView.UUID_EXTRA);
|
||||
String nameString = getIntent().getStringExtra(AppView.NAME_EXTRA);
|
||||
|
||||
if (validateInput(uuidString, appIdString)) {
|
||||
if (appIdString != null && !appIdString.isEmpty()) {
|
||||
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
||||
Integer.parseInt(appIdString),
|
||||
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||
// App arguments, both are optional, but one must be provided in order to start an app
|
||||
String appIdString = getIntent().getStringExtra(Game.EXTRA_APP_ID);
|
||||
String appNameString = getIntent().getStringExtra(Game.EXTRA_APP_NAME);
|
||||
|
||||
if (!validateInput(uuidString, appIdString, nameString)) {
|
||||
// Invalid input, so just return
|
||||
return;
|
||||
}
|
||||
|
||||
if (uuidString == null || uuidString.isEmpty()) {
|
||||
// Use nameString to find the corresponding UUID
|
||||
_computer = dbManager.getComputerByName(nameString);
|
||||
|
||||
if (_computer == null) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_pc_not_found),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind to the computer manager service
|
||||
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
||||
Service.BIND_AUTO_CREATE);
|
||||
uuidString = _computer.uuid;
|
||||
|
||||
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
||||
getResources().getString(R.string.applist_connect_msg), true);
|
||||
// Set the AppView UUID intent, since it wasn't provided
|
||||
setIntent(new Intent(getIntent()).putExtra(AppView.UUID_EXTRA, uuidString));
|
||||
}
|
||||
|
||||
if (appIdString != null && !appIdString.isEmpty()) {
|
||||
app = new NvApp(getIntent().getStringExtra(Game.EXTRA_APP_NAME),
|
||||
Integer.parseInt(appIdString),
|
||||
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||
}
|
||||
else if (appNameString != null && !appNameString.isEmpty()) {
|
||||
// Use appNameString to find the corresponding AppId
|
||||
try {
|
||||
int appId = -1;
|
||||
String rawAppList = CacheHelper.readInputStreamToString(CacheHelper.openCacheFileForInput(getCacheDir(), "applist", uuidString));
|
||||
|
||||
if (rawAppList.isEmpty()) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_app_id),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
List<NvApp> applist = NvHTTP.getAppListByReader(new StringReader(rawAppList));
|
||||
|
||||
for (NvApp _app : applist) {
|
||||
if (_app.getAppName().equals(appNameString)) {
|
||||
appId = _app.getAppId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (appId < 0) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_app_id),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
setIntent(new Intent(getIntent()).putExtra(Game.EXTRA_APP_ID, appId));
|
||||
app = new NvApp(
|
||||
appNameString,
|
||||
appId,
|
||||
getIntent().getBooleanExtra(Game.EXTRA_APP_HDR, false));
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
Dialog.displayDialog(ShortcutTrampoline.this,
|
||||
getResources().getString(R.string.conn_error_title),
|
||||
getResources().getString(R.string.scut_invalid_app_id),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Bind to the computer manager service
|
||||
bindService(new Intent(this, ComputerManagerService.class), serviceConnection,
|
||||
Service.BIND_AUTO_CREATE);
|
||||
|
||||
blockingLoadSpinner = SpinnerDialog.displayDialog(this, getResources().getString(R.string.conn_establishing_title),
|
||||
getResources().getString(R.string.applist_connect_msg), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -26,51 +26,41 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
||||
}
|
||||
|
||||
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,
|
||||
sampleRate,
|
||||
channelConfig,
|
||||
AudioFormat.ENCODING_PCM_16BIT,
|
||||
bufferSize,
|
||||
AudioTrack.MODE_STREAM);
|
||||
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_GAME);
|
||||
AudioFormat format = new AudioFormat.Builder()
|
||||
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
||||
.setSampleRate(sampleRate)
|
||||
.setChannelMask(channelConfig)
|
||||
.build();
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
// Use FLAG_LOW_LATENCY on L through N
|
||||
if (lowLatency) {
|
||||
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
||||
.setAudioFormat(format)
|
||||
.setAudioAttributes(attributesBuilder.build())
|
||||
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||
.setBufferSizeInBytes(bufferSize);
|
||||
|
||||
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
||||
if (lowLatency) {
|
||||
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
||||
}
|
||||
|
||||
return trackBuilder.build();
|
||||
}
|
||||
else {
|
||||
AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder()
|
||||
.setUsage(AudioAttributes.USAGE_GAME);
|
||||
AudioFormat format = new AudioFormat.Builder()
|
||||
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
|
||||
.setSampleRate(sampleRate)
|
||||
.setChannelMask(channelConfig)
|
||||
.build();
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
// Use FLAG_LOW_LATENCY on L through N
|
||||
if (lowLatency) {
|
||||
attributesBuilder.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
AudioTrack.Builder trackBuilder = new AudioTrack.Builder()
|
||||
.setAudioFormat(format)
|
||||
.setAudioAttributes(attributesBuilder.build())
|
||||
.setTransferMode(AudioTrack.MODE_STREAM)
|
||||
.setBufferSizeInBytes(bufferSize);
|
||||
|
||||
// Use PERFORMANCE_MODE_LOW_LATENCY on O and later
|
||||
if (lowLatency) {
|
||||
trackBuilder.setPerformanceMode(AudioTrack.PERFORMANCE_MODE_LOW_LATENCY);
|
||||
}
|
||||
|
||||
return trackBuilder.build();
|
||||
}
|
||||
else {
|
||||
return new AudioTrack(attributesBuilder.build(),
|
||||
format,
|
||||
bufferSize,
|
||||
AudioTrack.MODE_STREAM,
|
||||
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
||||
}
|
||||
return new AudioTrack(attributesBuilder.build(),
|
||||
format,
|
||||
bufferSize,
|
||||
AudioTrack.MODE_STREAM,
|
||||
AudioManager.AUDIO_SESSION_ID_GENERATE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,20 +81,10 @@ public class AndroidAudioRenderer implements AudioRenderer {
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
|
||||
break;
|
||||
case 8:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
||||
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
||||
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
||||
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
||||
}
|
||||
else {
|
||||
// On KitKat and lower, creation of the AudioTrack will fail if we specify
|
||||
// CHANNEL_OUT_SIDE_LEFT or CHANNEL_OUT_SIDE_RIGHT. That leaves us with
|
||||
// the old CHANNEL_OUT_7POINT1 which uses left-of-center and right-of-center
|
||||
// speakers instead of side-left and side-right. This non-standard layout
|
||||
// is probably not what the user wants, but we don't really have a choice.
|
||||
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1;
|
||||
}
|
||||
// AudioFormat.CHANNEL_OUT_7POINT1_SURROUND isn't available until Android 6.0,
|
||||
// yet the CHANNEL_OUT_SIDE_LEFT and CHANNEL_OUT_SIDE_RIGHT constants were added
|
||||
// in 5.0, so just hardcode the constant so we can work on Lollipop.
|
||||
channelConfig = 0x000018fc; // AudioFormat.CHANNEL_OUT_7POINT1_SURROUND
|
||||
break;
|
||||
default:
|
||||
LimeLog.severe("Decoder returned unhandled channel count");
|
||||
|
||||
@@ -12,12 +12,12 @@ import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.util.Calendar;
|
||||
@@ -48,7 +48,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
private final File keyFile;
|
||||
|
||||
private X509Certificate cert;
|
||||
private RSAPrivateKey key;
|
||||
private PrivateKey key;
|
||||
private byte[] pemCertBytes;
|
||||
|
||||
private static final Object globalCryptoLock = new Object();
|
||||
@@ -94,7 +94,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(certBytes));
|
||||
pemCertBytes = certBytes;
|
||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA", bcProvider);
|
||||
key = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
||||
key = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
|
||||
} catch (CertificateException e) {
|
||||
// May happen if the cert is corrupt
|
||||
LimeLog.warning("Corrupted certificate");
|
||||
@@ -144,7 +144,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
try {
|
||||
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256withRSA").setProvider(bcProvider).build(keyPair.getPrivate());
|
||||
cert = new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(sigGen));
|
||||
key = (RSAPrivateKey) keyPair.getPrivate();
|
||||
key = keyPair.getPrivate();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -215,7 +215,7 @@ public class AndroidCryptoProvider implements LimelightCryptoProvider {
|
||||
}
|
||||
}
|
||||
|
||||
public RSAPrivateKey getClientPrivateKey() {
|
||||
public PrivateKey getClientPrivateKey() {
|
||||
// Use a lock here to ensure only one guy will be generating or loading
|
||||
// the certificate and key at a time
|
||||
synchronized (globalCryptoLock) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
package com.limelight.binding.input;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.os.Build;
|
||||
@@ -34,6 +35,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
public static final int VK_EQUALS = 61;
|
||||
public static final int VK_ESCAPE = 27;
|
||||
public static final int VK_F1 = 112;
|
||||
public static final int VK_F13 = 0x7C;
|
||||
public static final int VK_END = 35;
|
||||
public static final int VK_HOME = 36;
|
||||
public static final int VK_NUM_LOCK = 144;
|
||||
@@ -104,18 +106,20 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean needsShift(int keycode) {
|
||||
switch (keycode)
|
||||
{
|
||||
case KeyEvent.KEYCODE_AT:
|
||||
case KeyEvent.KEYCODE_POUND:
|
||||
case KeyEvent.KEYCODE_PLUS:
|
||||
case KeyEvent.KEYCODE_STAR:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
public boolean hasNormalizedMapping(int keycode, int deviceId) {
|
||||
if (deviceId >= 0) {
|
||||
KeyboardMapping mapping = keyboardMappings.get(deviceId);
|
||||
if (mapping != null) {
|
||||
// Try to map this device-specific keycode onto a QWERTY layout.
|
||||
// GFE assumes incoming keycodes are from a QWERTY keyboard.
|
||||
int qwertyKeyCode = mapping.getQwertyKeyCodeForDeviceKeyCode(keycode);
|
||||
if (qwertyKeyCode != KeyEvent.KEYCODE_UNKNOWN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,6 +128,7 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
* @param deviceId InputDevice.getId() or -1 if unknown
|
||||
* @return a GFE keycode for the given keycode
|
||||
*/
|
||||
@SuppressLint("InlinedApi")
|
||||
public short translate(int keycode, int deviceId) {
|
||||
int translated;
|
||||
|
||||
@@ -159,6 +164,10 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
keycode <= KeyEvent.KEYCODE_F12) {
|
||||
translated = (keycode - KeyEvent.KEYCODE_F1) + VK_F1;
|
||||
}
|
||||
else if (keycode >= KeyEvent.KEYCODE_F13 &&
|
||||
keycode <= KeyEvent.KEYCODE_F24) {
|
||||
translated = (keycode - KeyEvent.KEYCODE_F13) + VK_F13;
|
||||
}
|
||||
else {
|
||||
switch (keycode) {
|
||||
case KeyEvent.KEYCODE_ALT_LEFT:
|
||||
@@ -230,6 +239,10 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
translated = 0x5c;
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_MENU:
|
||||
translated = 0x5d;
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_MINUS:
|
||||
translated = 0xbd;
|
||||
break;
|
||||
@@ -343,20 +356,15 @@ public class KeyboardTranslator implements InputManager.InputDeviceListener {
|
||||
translated = 0x6E;
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_AT:
|
||||
translated = 2 + VK_0;
|
||||
case KeyEvent.KEYCODE_PRINT:
|
||||
translated = 0x2A;
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_POUND:
|
||||
translated = 3 + VK_0;
|
||||
break;
|
||||
|
||||
case KeyEvent.KEYCODE_STAR:
|
||||
translated = 8 + VK_0;
|
||||
case KeyEvent.KEYCODE_SCREENSHOT:
|
||||
translated = 0x2C;
|
||||
break;
|
||||
|
||||
default:
|
||||
System.out.println("No key for "+keycode);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
+23
-13
@@ -15,8 +15,8 @@ import android.view.View;
|
||||
// is unavailable on this system (ex: DeX, ChromeOS)
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptureProvider implements InputManager.InputDeviceListener {
|
||||
private InputManager inputManager;
|
||||
private View targetView;
|
||||
private final InputManager inputManager;
|
||||
private final View targetView;
|
||||
|
||||
public AndroidNativePointerCaptureProvider(Activity activity, View targetView) {
|
||||
super(activity, targetView);
|
||||
@@ -44,7 +44,10 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
|
||||
// with SOURCE_TOUCHSCREEN, SOURCE_KEYBOARD, and SOURCE_MOUSE.
|
||||
// Upon enabling pointer capture, that device will switch to
|
||||
// SOURCE_KEYBOARD and SOURCE_TOUCHPAD.
|
||||
if (device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
|
||||
// Only skip on non ChromeOS devices cause the ChromeOS pointer else
|
||||
// gets disabled removing relative mouse capabilities
|
||||
// on Chromebooks with touchscreens
|
||||
if (device.supportsSource(InputDevice.SOURCE_TOUCHSCREEN) && !targetView.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -59,8 +62,19 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableCapture() {
|
||||
super.enableCapture();
|
||||
public void showCursor() {
|
||||
super.showCursor();
|
||||
|
||||
// It is important to unregister the listener *before* releasing pointer capture,
|
||||
// because releasing pointer capture can cause an onInputDeviceChanged() callback
|
||||
// for devices with a touchpad (like a DS4 controller).
|
||||
inputManager.unregisterInputDeviceListener(this);
|
||||
targetView.releasePointerCapture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideCursor() {
|
||||
super.hideCursor();
|
||||
|
||||
// Listen for device events to enable/disable capture
|
||||
inputManager.registerInputDeviceListener(this, null);
|
||||
@@ -71,16 +85,12 @@ public class AndroidNativePointerCaptureProvider extends AndroidPointerIconCaptu
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableCapture() {
|
||||
super.disableCapture();
|
||||
inputManager.unregisterInputDeviceListener(this);
|
||||
targetView.releasePointerCapture();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean focusActive) {
|
||||
if (!focusActive || !isCapturing) {
|
||||
// NB: We have to check cursor visibility here because Android pointer capture
|
||||
// doesn't support capturing the cursor while it's visible. Enabling pointer
|
||||
// capture implicitly hides the cursor.
|
||||
if (!focusActive || !isCapturing || isCursorVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+6
-7
@@ -4,14 +4,13 @@ import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
import android.view.View;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
public class AndroidPointerIconCaptureProvider extends InputCaptureProvider {
|
||||
private View targetView;
|
||||
private Context context;
|
||||
private final View targetView;
|
||||
private final Context context;
|
||||
|
||||
public AndroidPointerIconCaptureProvider(Activity activity, View targetView) {
|
||||
this.context = activity;
|
||||
@@ -23,14 +22,14 @@ public class AndroidPointerIconCaptureProvider extends InputCaptureProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableCapture() {
|
||||
super.enableCapture();
|
||||
public void hideCursor() {
|
||||
super.hideCursor();
|
||||
targetView.setPointerIcon(PointerIcon.getSystemIcon(context, PointerIcon.TYPE_NULL));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableCapture() {
|
||||
super.disableCapture();
|
||||
public void showCursor() {
|
||||
super.showCursor();
|
||||
targetView.setPointerIcon(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ import android.view.MotionEvent;
|
||||
|
||||
public abstract class InputCaptureProvider {
|
||||
protected boolean isCapturing;
|
||||
protected boolean isCursorVisible;
|
||||
|
||||
public void enableCapture() {
|
||||
isCapturing = true;
|
||||
hideCursor();
|
||||
}
|
||||
public void disableCapture() {
|
||||
isCapturing = false;
|
||||
showCursor();
|
||||
}
|
||||
|
||||
public void destroy() {}
|
||||
@@ -22,6 +25,14 @@ public abstract class InputCaptureProvider {
|
||||
return isCapturing;
|
||||
}
|
||||
|
||||
public void showCursor() {
|
||||
isCursorVisible = true;
|
||||
}
|
||||
|
||||
public void hideCursor() {
|
||||
isCursorVisible = false;
|
||||
}
|
||||
|
||||
public boolean eventHasRelativeMouseAxes(MotionEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ShieldCaptureProvider extends InputCaptureProvider {
|
||||
private static int AXIS_RELATIVE_X;
|
||||
private static int AXIS_RELATIVE_Y;
|
||||
|
||||
private Context context;
|
||||
private final Context context;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -62,14 +62,14 @@ public class ShieldCaptureProvider extends InputCaptureProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableCapture() {
|
||||
super.enableCapture();
|
||||
public void hideCursor() {
|
||||
super.hideCursor();
|
||||
setCursorVisibility(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableCapture() {
|
||||
super.disableCapture();
|
||||
public void showCursor() {
|
||||
super.showCursor();
|
||||
setCursorVisibility(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ public abstract class AbstractController {
|
||||
|
||||
private UsbDriverListener listener;
|
||||
|
||||
protected short buttonFlags;
|
||||
protected int buttonFlags, supportedButtonFlags;
|
||||
protected float leftTrigger, rightTrigger;
|
||||
protected float rightStickX, rightStickY;
|
||||
protected float leftStickX, leftStickY;
|
||||
protected short capabilities;
|
||||
protected byte type;
|
||||
|
||||
public int getControllerId() {
|
||||
return deviceId;
|
||||
@@ -25,6 +27,18 @@ public abstract class AbstractController {
|
||||
return productId;
|
||||
}
|
||||
|
||||
public int getSupportedButtonFlags() {
|
||||
return supportedButtonFlags;
|
||||
}
|
||||
|
||||
public short getCapabilities() {
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
public byte getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
protected void setButtonFlag(int buttonFlag, int data) {
|
||||
if (data != 0) {
|
||||
buttonFlags |= buttonFlag;
|
||||
@@ -51,6 +65,8 @@ public abstract class AbstractController {
|
||||
|
||||
public abstract void rumble(short lowFreqMotor, short highFreqMotor);
|
||||
|
||||
public abstract void rumbleTriggers(short leftTrigger, short rightTrigger);
|
||||
|
||||
protected void notifyDeviceRemoved() {
|
||||
listener.deviceRemoved(this);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import android.hardware.usb.UsbInterface;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.input.ControllerPacket;
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
@@ -25,6 +27,14 @@ public abstract class AbstractXboxController extends AbstractController {
|
||||
super(deviceId, listener, device.getVendorId(), device.getProductId());
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
this.type = MoonBridge.LI_CTYPE_XBOX;
|
||||
this.capabilities = MoonBridge.LI_CCAP_ANALOG_TRIGGERS | MoonBridge.LI_CCAP_RUMBLE;
|
||||
this.buttonFlags =
|
||||
ControllerPacket.A_FLAG | ControllerPacket.B_FLAG | ControllerPacket.X_FLAG | ControllerPacket.Y_FLAG |
|
||||
ControllerPacket.UP_FLAG | ControllerPacket.DOWN_FLAG | ControllerPacket.LEFT_FLAG | ControllerPacket.RIGHT_FLAG |
|
||||
ControllerPacket.LB_FLAG | ControllerPacket.RB_FLAG |
|
||||
ControllerPacket.LS_CLK_FLAG | ControllerPacket.RS_CLK_FLAG |
|
||||
ControllerPacket.BACK_FLAG | ControllerPacket.PLAY_FLAG | ControllerPacket.SPECIAL_BUTTON_FLAG;
|
||||
}
|
||||
|
||||
private Thread createInputThread() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.limelight.binding.input.driver;
|
||||
|
||||
public interface UsbDriverListener {
|
||||
void reportControllerState(int controllerId, short buttonFlags,
|
||||
void reportControllerState(int controllerId, int buttonFlags,
|
||||
float leftStickX, float leftStickY,
|
||||
float rightStickX, float rightStickY,
|
||||
float leftTrigger, float rightTrigger);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.limelight.binding.input.driver;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -20,6 +21,7 @@ import com.limelight.LimeLog;
|
||||
import com.limelight.R;
|
||||
import com.limelight.preferences.PreferenceConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
@@ -41,7 +43,8 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
private int nextDeviceId;
|
||||
|
||||
@Override
|
||||
public void reportControllerState(int controllerId, short buttonFlags, float leftStickX, float leftStickY, float rightStickX, float rightStickY, float leftTrigger, float rightTrigger) {
|
||||
public void reportControllerState(int controllerId, int buttonFlags, float leftStickX, float leftStickY,
|
||||
float rightStickX, float rightStickY, float leftTrigger, float rightTrigger) {
|
||||
// Call through to the client's listener
|
||||
if (listener != null) {
|
||||
listener.reportControllerState(controllerId, buttonFlags, leftStickX, leftStickY, rightStickX, rightStickY, leftTrigger, rightTrigger);
|
||||
@@ -157,7 +160,12 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
// just returning a false result or returning 0 enumerated devices,
|
||||
// they throw an undocumented SecurityException from this call, crashing
|
||||
// the whole app. :(
|
||||
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, new Intent(ACTION_USB_PERMISSION), intentFlags));
|
||||
|
||||
// Use an explicit intent to activate our unexported broadcast receiver, as required on Android 14+
|
||||
Intent i = new Intent(ACTION_USB_PERMISSION);
|
||||
i.setPackage(getPackageName());
|
||||
|
||||
usbManager.requestPermission(device, PendingIntent.getBroadcast(UsbDriverService.this, 0, i, intentFlags));
|
||||
} catch (SecurityException e) {
|
||||
Toast.makeText(this, this.getText(R.string.error_usb_prohibited), Toast.LENGTH_LONG).show();
|
||||
if (stateListener != null) {
|
||||
@@ -183,6 +191,9 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
else if (Xbox360Controller.canClaimDevice(device)) {
|
||||
controller = new Xbox360Controller(device, connection, nextDeviceId++, this);
|
||||
}
|
||||
else if (Xbox360WirelessDongle.canClaimDevice(device)) {
|
||||
controller = new Xbox360WirelessDongle(device, connection, nextDeviceId++, this);
|
||||
}
|
||||
else {
|
||||
// Unreachable
|
||||
return;
|
||||
@@ -200,28 +211,22 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
}
|
||||
|
||||
public static boolean isRecognizedInputDevice(UsbDevice device) {
|
||||
// On KitKat and later, we can determine if this VID and PID combo
|
||||
// matches an existing input device and defer to the built-in controller
|
||||
// support in that case. Prior to KitKat, we'll always return true to be safe.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
for (int id : InputDevice.getDeviceIds()) {
|
||||
InputDevice inputDev = InputDevice.getDevice(id);
|
||||
if (inputDev == null) {
|
||||
// Device was removed while looping
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||
inputDev.getProductId() == device.getProductId()) {
|
||||
return true;
|
||||
}
|
||||
// Determine if this VID and PID combo matches an existing input device
|
||||
// and defer to the built-in controller support in that case.
|
||||
for (int id : InputDevice.getDeviceIds()) {
|
||||
InputDevice inputDev = InputDevice.getDevice(id);
|
||||
if (inputDev == null) {
|
||||
// Device was removed while looping
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||
inputDev.getProductId() == device.getProductId()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean kernelSupportsXboxOne() {
|
||||
@@ -248,13 +253,37 @@ public class UsbDriverService extends Service implements UsbDriverListener {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldClaimDevice(UsbDevice device, boolean claimAllAvailable) {
|
||||
return ((!kernelSupportsXboxOne() || !isRecognizedInputDevice(device) || claimAllAvailable) && XboxOneController.canClaimDevice(device)) ||
|
||||
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device));
|
||||
public static boolean kernelSupportsXbox360W() {
|
||||
// Check if this kernel is 4.2+ to see if the xpad driver sets Xbox 360 wireless LEDs
|
||||
// https://github.com/torvalds/linux/commit/75b7f05d2798ee3a1cc5bbdd54acd0e318a80396
|
||||
String kernelVersion = System.getProperty("os.version");
|
||||
if (kernelVersion != null) {
|
||||
if (kernelVersion.startsWith("2.") || kernelVersion.startsWith("3.") ||
|
||||
kernelVersion.startsWith("4.0.") || kernelVersion.startsWith("4.1.")) {
|
||||
// Even if LED devices are present, the driver won't set the initial LED state.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// We know we have a kernel that should set Xbox 360 wireless LEDs, but we still don't
|
||||
// know if CONFIG_JOYSTICK_XPAD_LEDS was enabled during the kernel build. Unfortunately
|
||||
// it's not possible to detect this reliably due to Android's app sandboxing. Reading
|
||||
// /proc/config.gz and enumerating /sys/class/leds are both blocked by SELinux on any
|
||||
// relatively modern device. We will assume that CONFIG_JOYSTICK_XPAD_LEDS=y on these
|
||||
// kernels and users can override by using the settings option to claim all devices.
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean shouldClaimDevice(UsbDevice device, boolean claimAllAvailable) {
|
||||
return ((!kernelSupportsXboxOne() || !isRecognizedInputDevice(device) || claimAllAvailable) && XboxOneController.canClaimDevice(device)) ||
|
||||
((!isRecognizedInputDevice(device) || claimAllAvailable) && Xbox360Controller.canClaimDevice(device)) ||
|
||||
// We must not call isRecognizedInputDevice() because wireless controllers don't share the same product ID as the dongle
|
||||
((!kernelSupportsXbox360W() || claimAllAvailable) && Xbox360WirelessDongle.canClaimDevice(device));
|
||||
}
|
||||
|
||||
@SuppressLint("UnspecifiedRegisterReceiverFlag")
|
||||
private void start() {
|
||||
if (started) {
|
||||
if (started || usbManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class Xbox360Controller extends AbstractXboxController {
|
||||
0x20d6, // PowerA
|
||||
0x24c6, // PowerA
|
||||
0x2f24, // GameSir
|
||||
0x2dc8, // 8BitDo
|
||||
};
|
||||
|
||||
public static boolean canClaimDevice(UsbDevice device) {
|
||||
@@ -156,4 +157,9 @@ public class Xbox360Controller extends AbstractXboxController {
|
||||
LimeLog.warning("Rumble transfer failed: "+res);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
|
||||
// Trigger motors not present on Xbox 360 controllers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.limelight.binding.input.driver;
|
||||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.os.Build;
|
||||
import android.view.InputDevice;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class Xbox360WirelessDongle extends AbstractController {
|
||||
private UsbDevice device;
|
||||
private UsbDeviceConnection connection;
|
||||
|
||||
private static final int XB360W_IFACE_SUBCLASS = 93;
|
||||
private static final int XB360W_IFACE_PROTOCOL = 129; // Wireless only
|
||||
|
||||
private static final int[] SUPPORTED_VENDORS = {
|
||||
0x045e, // Microsoft
|
||||
};
|
||||
|
||||
public static boolean canClaimDevice(UsbDevice device) {
|
||||
for (int supportedVid : SUPPORTED_VENDORS) {
|
||||
if (device.getVendorId() == supportedVid &&
|
||||
device.getInterfaceCount() >= 1 &&
|
||||
device.getInterface(0).getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
|
||||
device.getInterface(0).getInterfaceSubclass() == XB360W_IFACE_SUBCLASS &&
|
||||
device.getInterface(0).getInterfaceProtocol() == XB360W_IFACE_PROTOCOL) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public Xbox360WirelessDongle(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
||||
super(deviceId, listener, device.getVendorId(), device.getProductId());
|
||||
this.device = device;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
private void sendLedCommandToEndpoint(UsbEndpoint endpoint, int controllerIndex) {
|
||||
byte[] commandBuffer = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x08,
|
||||
(byte) (0x40 + (2 + (controllerIndex % 4))),
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00};
|
||||
|
||||
int res = connection.bulkTransfer(endpoint, commandBuffer, commandBuffer.length, 3000);
|
||||
if (res != commandBuffer.length) {
|
||||
LimeLog.warning("LED set transfer failed: "+res);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendLedCommandToInterface(UsbInterface iface, int controllerIndex) {
|
||||
// Claim this interface to kick xpad off it (temporarily)
|
||||
if (!connection.claimInterface(iface, true)) {
|
||||
LimeLog.warning("Failed to claim interface: "+iface.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the out endpoint for this interface
|
||||
for (int i = 0; i < iface.getEndpointCount(); i++) {
|
||||
UsbEndpoint endpt = iface.getEndpoint(i);
|
||||
if (endpt.getDirection() == UsbConstants.USB_DIR_OUT) {
|
||||
// Send the LED command
|
||||
sendLedCommandToEndpoint(endpt, controllerIndex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Release the interface to allow xpad to take over again
|
||||
connection.releaseInterface(iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
int controllerIndex = 0;
|
||||
|
||||
// On Android, there is a controller number associated with input devices.
|
||||
// We can use this to approximate the likely controller number. This won't
|
||||
// be completely accurate because there's no guarantee the order of interfaces
|
||||
// matches the order that devices were enumerated by xpad, but it's probably
|
||||
// better than nothing.
|
||||
for (int id : InputDevice.getDeviceIds()) {
|
||||
InputDevice inputDev = InputDevice.getDevice(id);
|
||||
if (inputDev == null) {
|
||||
// Device was removed while looping
|
||||
continue;
|
||||
}
|
||||
|
||||
// Newer xpad versions use a special product ID (0x02a1) for controllers
|
||||
// rather than copying the product ID of the dongle itself.
|
||||
if (inputDev.getVendorId() == device.getVendorId() &&
|
||||
(inputDev.getProductId() == device.getProductId() ||
|
||||
inputDev.getProductId() == 0x02a1) &&
|
||||
inputDev.getControllerNumber() > 0) {
|
||||
controllerIndex = inputDev.getControllerNumber() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Send LED commands on the out endpoint of each interface. There is one interface
|
||||
// corresponding to each possible attached controller.
|
||||
for (int i = 0; i < device.getInterfaceCount(); i++) {
|
||||
UsbInterface iface = device.getInterface(i);
|
||||
|
||||
// Skip the non-input interfaces
|
||||
if (iface.getInterfaceClass() != UsbConstants.USB_CLASS_VENDOR_SPEC ||
|
||||
iface.getInterfaceSubclass() != XB360W_IFACE_SUBCLASS ||
|
||||
iface.getInterfaceProtocol() != XB360W_IFACE_PROTOCOL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sendLedCommandToInterface(iface, controllerIndex++);
|
||||
}
|
||||
|
||||
// "Fail" to give control back to the kernel driver
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumble(short lowFreqMotor, short highFreqMotor) {
|
||||
// Unreachable.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
|
||||
// Unreachable.
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import android.hardware.usb.UsbDeviceConnection;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.input.ControllerPacket;
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
@@ -24,10 +25,12 @@ public class XboxOneController extends AbstractXboxController {
|
||||
0x20d6, // PowerA
|
||||
0x24c6, // PowerA
|
||||
0x2e24, // Hyperkin
|
||||
0x2dc8, // 8BitDo
|
||||
};
|
||||
|
||||
private static final byte[] FW2015_INIT = {0x05, 0x20, 0x00, 0x01, 0x00};
|
||||
private static final byte[] ONE_S_INIT = {0x05, 0x20, 0x00, 0x0f, 0x06};
|
||||
private static final byte[] SERIES_S_INIT = {0x05, 0x20, 0x00, 0x0f, 0x06};
|
||||
private static final byte[] HORI_INIT = {0x01, 0x20, 0x00, 0x09, 0x00, 0x04, 0x20, 0x3a,
|
||||
0x00, 0x00, 0x00, (byte)0x80, 0x00};
|
||||
private static final byte[] PDP_INIT1 = {0x0a, 0x20, 0x00, 0x03, 0x00, 0x01, 0x14};
|
||||
@@ -42,7 +45,11 @@ public class XboxOneController extends AbstractXboxController {
|
||||
new InitPacket(0x0f0d, 0x0067, HORI_INIT),
|
||||
new InitPacket(0x0000, 0x0000, FW2015_INIT),
|
||||
new InitPacket(0x045e, 0x02ea, ONE_S_INIT),
|
||||
new InitPacket(0x045e, 0x02fe, ONE_S_INIT),
|
||||
new InitPacket(0x045e, 0x0b00, ONE_S_INIT),
|
||||
new InitPacket(0x045e, 0x0b05, SERIES_S_INIT),
|
||||
new InitPacket(0x045e, 0x0b12, SERIES_S_INIT),
|
||||
new InitPacket(0x045e, 0x0b13, SERIES_S_INIT),
|
||||
new InitPacket(0x0e6f, 0x0000, PDP_INIT1),
|
||||
new InitPacket(0x0e6f, 0x0000, PDP_INIT2),
|
||||
new InitPacket(0x24c6, 0x541a, RUMBLE_INIT1),
|
||||
@@ -54,9 +61,14 @@ public class XboxOneController extends AbstractXboxController {
|
||||
};
|
||||
|
||||
private byte seqNum = 0;
|
||||
private short lowFreqMotor = 0;
|
||||
private short highFreqMotor = 0;
|
||||
private short leftTriggerMotor = 0;
|
||||
private short rightTriggerMotor = 0;
|
||||
|
||||
public XboxOneController(UsbDevice device, UsbDeviceConnection connection, int deviceId, UsbDriverListener listener) {
|
||||
super(device, connection, deviceId, listener);
|
||||
capabilities |= MoonBridge.LI_CCAP_TRIGGER_RUMBLE;
|
||||
}
|
||||
|
||||
private void processButtons(ByteBuffer buffer) {
|
||||
@@ -176,12 +188,14 @@ public class XboxOneController extends AbstractXboxController {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumble(short lowFreqMotor, short highFreqMotor) {
|
||||
private void sendRumblePacket() {
|
||||
byte[] data = {
|
||||
0x09, 0x00, seqNum++, 0x09, 0x00,
|
||||
0x0F, 0x00, 0x00,
|
||||
(byte)(lowFreqMotor >> 9), (byte)(highFreqMotor >> 9),
|
||||
0x0F,
|
||||
(byte)(leftTriggerMotor >> 9),
|
||||
(byte)(rightTriggerMotor >> 9),
|
||||
(byte)(lowFreqMotor >> 9),
|
||||
(byte)(highFreqMotor >> 9),
|
||||
(byte)0xFF, 0x00, (byte)0xFF
|
||||
};
|
||||
int res = connection.bulkTransfer(outEndpt, data, data.length, 100);
|
||||
@@ -190,6 +204,20 @@ public class XboxOneController extends AbstractXboxController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumble(short lowFreqMotor, short highFreqMotor) {
|
||||
this.lowFreqMotor = lowFreqMotor;
|
||||
this.highFreqMotor = highFreqMotor;
|
||||
sendRumblePacket();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rumbleTriggers(short leftTrigger, short rightTrigger) {
|
||||
this.leftTriggerMotor = leftTrigger;
|
||||
this.rightTriggerMotor = rightTrigger;
|
||||
sendRumblePacket();
|
||||
}
|
||||
|
||||
private static class InitPacket {
|
||||
final int vendorId;
|
||||
final int productId;
|
||||
|
||||
@@ -9,6 +9,7 @@ public interface EvdevListener {
|
||||
|
||||
void mouseMove(int deltaX, int deltaY);
|
||||
void mouseButtonEvent(int buttonId, boolean down);
|
||||
void mouseScroll(byte amount);
|
||||
void mouseVScroll(byte amount);
|
||||
void mouseHScroll(byte amount);
|
||||
void keyboardEvent(boolean buttonDown, short keyCode);
|
||||
}
|
||||
|
||||
+14
@@ -185,6 +185,10 @@ public class VirtualControllerConfigurationLoader {
|
||||
private static final int START_BACK_WIDTH = 12;
|
||||
private static final int START_BACK_HEIGHT = 7;
|
||||
|
||||
// Make the Guide Menu be in the center of START and BACK menu
|
||||
private static final int GUIDE_X = START_X-BACK_X;
|
||||
private static final int GUIDE_Y = START_BACK_Y;
|
||||
|
||||
public static void createDefaultLayout(final VirtualController controller, final Context context) {
|
||||
|
||||
DisplayMetrics screen = context.getResources().getDisplayMetrics();
|
||||
@@ -333,6 +337,16 @@ public class VirtualControllerConfigurationLoader {
|
||||
);
|
||||
}
|
||||
|
||||
if(config.showGuideButton){
|
||||
controller.addElement(createDigitalButton(VirtualControllerElement.EID_GDB,
|
||||
ControllerPacket.SPECIAL_BUTTON_FLAG, 0, 1, "GUIDE", -1, controller, context),
|
||||
screenScale(GUIDE_X, height)+ rightDisplacement,
|
||||
screenScale(GUIDE_Y, height),
|
||||
screenScale(START_BACK_WIDTH, height),
|
||||
screenScale(START_BACK_HEIGHT, height)
|
||||
);
|
||||
}
|
||||
|
||||
controller.setOpacity(config.oscOpacity);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -35,6 +35,7 @@ public abstract class VirtualControllerElement extends View {
|
||||
public static final int EID_RS = 13;
|
||||
public static final int EID_LSB = 14;
|
||||
public static final int EID_RSB = 15;
|
||||
public static final int EID_GDB = 16;
|
||||
|
||||
protected VirtualController virtualController;
|
||||
protected final int elementId;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,6 @@ package com.limelight.binding.video;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -78,12 +77,6 @@ public class MediaCodecHelper {
|
||||
refFrameInvalidationHevcPrefixes.add("omx.exynos");
|
||||
refFrameInvalidationHevcPrefixes.add("c2.exynos");
|
||||
|
||||
// The Chromecast with Google TV 4K works well with HEVC RFI since we also use the
|
||||
// vendor.low-latency.enable option.
|
||||
if (Build.DEVICE.equalsIgnoreCase("sabrina")) {
|
||||
refFrameInvalidationHevcPrefixes.add("omx.amlogic");
|
||||
}
|
||||
|
||||
// Qualcomm and NVIDIA may be added at runtime
|
||||
}
|
||||
|
||||
@@ -184,6 +177,9 @@ public class MediaCodecHelper {
|
||||
// vendor.low-latency.enable. We will still use HEVC if decoderCanMeetPerformancePointWithHevcAndNotAvc()
|
||||
// determines it's the only way to meet the performance requirements.
|
||||
//
|
||||
// With the Android 12 update, Sabrina now uses HEVC (with RFI) based upon FEATURE_LowLatency
|
||||
// support, which provides equivalent latency to H.264 now.
|
||||
//
|
||||
// FIXME: Should we do this for all Amlogic S905X SoCs?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !Build.DEVICE.equalsIgnoreCase("sabrina")) {
|
||||
whitelistedHevcDecoders.add("omx.amlogic");
|
||||
@@ -360,7 +356,14 @@ public class MediaCodecHelper {
|
||||
if (configInfo.reqGlEsVersion >= 0x30000) {
|
||||
LimeLog.info("Added omx.nvidia/c2.nvidia to reference frame invalidation support list");
|
||||
refFrameInvalidationAvcPrefixes.add("omx.nvidia");
|
||||
refFrameInvalidationHevcPrefixes.add("omx.nvidia");
|
||||
|
||||
// Exclude HEVC RFI on Pixel C and Tegra devices prior to Android 11. Misbehaving RFI
|
||||
// on these devices can cause hundreds of milliseconds of latency, so it's not worth
|
||||
// using it unless we're absolutely sure that it will not cause increased latency.
|
||||
if (!Build.DEVICE.equalsIgnoreCase("dragon") && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
refFrameInvalidationHevcPrefixes.add("omx.nvidia");
|
||||
}
|
||||
|
||||
refFrameInvalidationAvcPrefixes.add("c2.nvidia"); // Unconfirmed
|
||||
refFrameInvalidationHevcPrefixes.add("c2.nvidia"); // Unconfirmed
|
||||
|
||||
@@ -526,6 +529,17 @@ public class MediaCodecHelper {
|
||||
setNewOption = true;
|
||||
}
|
||||
|
||||
if (tryNumber < 3) {
|
||||
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(decoderInfo.getName())) {
|
||||
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
|
||||
setNewOption = true;
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
videoFormat.setInteger(MediaFormat.KEY_PRIORITY, 0);
|
||||
setNewOption = true;
|
||||
}
|
||||
}
|
||||
|
||||
// MediaCodec supports vendor-defined format keys using the "vendor.<extension name>.<parameter name>" syntax.
|
||||
// These allow access to functionality that is not exposed through documented MediaFormat.KEY_* values.
|
||||
// https://cs.android.com/android/platform/superproject/+/master:hardware/qcom/sdm845/media/mm-video-v4l2/vidc/common/inc/vidc_vendor_extensions.h;l=67
|
||||
@@ -542,17 +556,17 @@ public class MediaCodecHelper {
|
||||
// https://cs.android.com/android/_/android/platform/hardware/qcom/sm8150/media/+/0621ceb1c1b19564999db8293574a0e12952ff6c
|
||||
//
|
||||
// We will first try both, then try vendor.qti-ext-dec-low-latency.enable alone if that fails
|
||||
if (tryNumber < 3) {
|
||||
if (tryNumber < 4) {
|
||||
videoFormat.setInteger("vendor.qti-ext-dec-picture-order.enable", 1);
|
||||
setNewOption = true;
|
||||
}
|
||||
if (tryNumber < 4) {
|
||||
if (tryNumber < 5) {
|
||||
videoFormat.setInteger("vendor.qti-ext-dec-low-latency.enable", 1);
|
||||
setNewOption = true;
|
||||
}
|
||||
}
|
||||
else if (isDecoderInList(kirinDecoderPrefixes, decoderInfo.getName())) {
|
||||
if (tryNumber < 3) {
|
||||
if (tryNumber < 4) {
|
||||
// Kirin low latency options
|
||||
// https://developer.huawei.com/consumer/cn/forum/topic/0202325564295980115
|
||||
videoFormat.setInteger("vendor.hisi-ext-low-latency-video-dec.video-scene-for-low-latency-req", 1);
|
||||
@@ -561,14 +575,14 @@ public class MediaCodecHelper {
|
||||
}
|
||||
}
|
||||
else if (isDecoderInList(exynosDecoderPrefixes, decoderInfo.getName())) {
|
||||
if (tryNumber < 3) {
|
||||
if (tryNumber < 4) {
|
||||
// Exynos low latency option for H.264 decoder
|
||||
videoFormat.setInteger("vendor.rtc-ext-dec-low-latency.enable", 1);
|
||||
setNewOption = true;
|
||||
}
|
||||
}
|
||||
else if (isDecoderInList(amlogicDecoderPrefixes, decoderInfo.getName())) {
|
||||
if (tryNumber < 3) {
|
||||
if (tryNumber < 4) {
|
||||
// Amlogic low latency vendor extension
|
||||
// https://github.com/codewalkerster/android_vendor_amlogic_common_prebuilt_libstagefrighthw/commit/41fefc4e035c476d58491324a5fe7666bfc2989e
|
||||
videoFormat.setInteger("vendor.low-latency.enable", 1);
|
||||
@@ -577,55 +591,44 @@ public class MediaCodecHelper {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: We should probably integrate this into the try system
|
||||
if (MediaCodecHelper.decoderSupportsMaxOperatingRate(decoderInfo.getName())) {
|
||||
videoFormat.setInteger(MediaFormat.KEY_OPERATING_RATE, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
return setNewOption;
|
||||
}
|
||||
|
||||
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();
|
||||
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) {
|
||||
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
||||
LimeLog.info("Decoder blacklisted for adaptive playback");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
||||
{
|
||||
// This will make getCapabilities() return that adaptive playback is supported
|
||||
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Tolerate buggy codecs
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (isDecoderInList(blacklistedAdaptivePlaybackPrefixes, decoderInfo.getName())) {
|
||||
LimeLog.info("Decoder blacklisted for adaptive playback");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
if (decoderInfo.getCapabilitiesForType(mimeType).
|
||||
isFeatureSupported(CodecCapabilities.FEATURE_AdaptivePlayback))
|
||||
{
|
||||
// This will make getCapabilities() return that adaptive playback is supported
|
||||
LimeLog.info("Adaptive playback supported (FEATURE_AdaptivePlayback)");
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Tolerate buggy codecs
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -688,14 +691,18 @@ public class MediaCodecHelper {
|
||||
return isDecoderInList(refFrameInvalidationHevcPrefixes, decoderInfo.getName());
|
||||
}
|
||||
|
||||
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
||||
// Google didn't have official support for HEVC (or more importantly, a CTS test) until
|
||||
// Lollipop. I've seen some MediaTek devices on 4.4 crash when attempting to use HEVC,
|
||||
// so I'm restricting HEVC usage to Lollipop and higher.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return false;
|
||||
public static boolean decoderSupportsRefFrameInvalidationAv1(MediaCodecInfo decoderInfo) {
|
||||
// We'll use the same heuristics as HEVC for now
|
||||
if (decoderSupportsAndroidRLowLatency(decoderInfo, "video/av01") ||
|
||||
decoderSupportsKnownVendorLowLatencyOption(decoderInfo.getName())) {
|
||||
LimeLog.info("Enabling AV1 RFI based on low latency option support");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean decoderIsWhitelistedForHevc(MediaCodecInfo decoderInfo) {
|
||||
//
|
||||
// Software decoders are terrible and we never want to use them.
|
||||
// We want to catch decoders like:
|
||||
@@ -715,19 +722,12 @@ public class MediaCodecHelper {
|
||||
// HEVC decoder present is fast and modern enough for streaming.
|
||||
//
|
||||
// [5.3/H-1-1] MUST NOT drop more than 2 frames in 10 seconds (i.e less than 0.333 percent frame drop) for a 1080p 60 fps video session under load.
|
||||
//
|
||||
// NB: We use reflection here because this field seems to be absent on Amazon Fire OS devices
|
||||
try {
|
||||
Field mediaClassField = Build.VERSION.class.getDeclaredField("MEDIA_PERFORMANCE_CLASS");
|
||||
int mediaClass = mediaClassField.getInt(null);
|
||||
if (mediaClass >= Build.VERSION_CODES.S) {
|
||||
LimeLog.info("Allowing HEVC based on media performance class: " + mediaClass);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
LimeLog.info("Media performance class: " + Build.VERSION.MEDIA_PERFORMANCE_CLASS);
|
||||
if (Build.VERSION.MEDIA_PERFORMANCE_CLASS >= Build.VERSION_CODES.S) {
|
||||
LimeLog.info("Allowing HEVC based on media performance class");
|
||||
return true;
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
LimeLog.info("Build.VERSION.MEDIA_PERFORMANCE_CLASS not present");
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// If the decoder supports FEATURE_LowLatency, we will assume it is fast and modern enough
|
||||
@@ -740,22 +740,41 @@ public class MediaCodecHelper {
|
||||
// Otherwise, we use our list of known working HEVC decoders
|
||||
return isDecoderInList(whitelistedHevcDecoders, decoderInfo.getName());
|
||||
}
|
||||
|
||||
|
||||
public static boolean isDecoderWhitelistedForAv1(MediaCodecInfo decoderInfo) {
|
||||
// Google didn't have official support for AV1 (or more importantly, a CTS test) until
|
||||
// Android 10, so don't use any decoder before then.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Software decoders are terrible and we never want to use them.
|
||||
// We want to catch decoders like:
|
||||
// OMX.qcom.video.decoder.hevcswvdec
|
||||
// OMX.SEC.hevc.sw.dec
|
||||
//
|
||||
if (decoderInfo.getName().contains("sw")) {
|
||||
LimeLog.info("Disallowing AV1 on software decoder: " + decoderInfo.getName());
|
||||
return false;
|
||||
}
|
||||
else if (!decoderInfo.isHardwareAccelerated() || decoderInfo.isSoftwareOnly()) {
|
||||
LimeLog.info("Disallowing AV1 on software decoder: " + decoderInfo.getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Test some AV1 decoders
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressLint("NewApi")
|
||||
private static LinkedList<MediaCodecInfo> getMediaCodecList() {
|
||||
LinkedList<MediaCodecInfo> infoList = new LinkedList<>();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||
Collections.addAll(infoList, mcl.getCodecInfos());
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
|
||||
infoList.add(MediaCodecList.getCodecInfoAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||
Collections.addAll(infoList, mcl.getCodecInfos());
|
||||
|
||||
return infoList;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ class VideoStats {
|
||||
int totalFramesRendered;
|
||||
int frameLossEvents;
|
||||
int framesLost;
|
||||
char minHostProcessingLatency;
|
||||
char maxHostProcessingLatency;
|
||||
int totalHostProcessingLatency;
|
||||
int framesWithHostProcessingLatency;
|
||||
long measurementStartTimestamp;
|
||||
|
||||
void add(VideoStats other) {
|
||||
@@ -22,6 +26,15 @@ class VideoStats {
|
||||
this.frameLossEvents += other.frameLossEvents;
|
||||
this.framesLost += other.framesLost;
|
||||
|
||||
if (this.minHostProcessingLatency == 0) {
|
||||
this.minHostProcessingLatency = other.minHostProcessingLatency;
|
||||
} else {
|
||||
this.minHostProcessingLatency = (char) Math.min(this.minHostProcessingLatency, other.minHostProcessingLatency);
|
||||
}
|
||||
this.maxHostProcessingLatency = (char) Math.max(this.maxHostProcessingLatency, other.maxHostProcessingLatency);
|
||||
this.totalHostProcessingLatency += other.totalHostProcessingLatency;
|
||||
this.framesWithHostProcessingLatency += other.framesWithHostProcessingLatency;
|
||||
|
||||
if (this.measurementStartTimestamp == 0) {
|
||||
this.measurementStartTimestamp = other.measurementStartTimestamp;
|
||||
}
|
||||
@@ -37,6 +50,10 @@ class VideoStats {
|
||||
this.totalFramesRendered = other.totalFramesRendered;
|
||||
this.frameLossEvents = other.frameLossEvents;
|
||||
this.framesLost = other.framesLost;
|
||||
this.minHostProcessingLatency = other.minHostProcessingLatency;
|
||||
this.maxHostProcessingLatency = other.maxHostProcessingLatency;
|
||||
this.totalHostProcessingLatency = other.totalHostProcessingLatency;
|
||||
this.framesWithHostProcessingLatency = other.framesWithHostProcessingLatency;
|
||||
this.measurementStartTimestamp = other.measurementStartTimestamp;
|
||||
}
|
||||
|
||||
@@ -48,6 +65,10 @@ class VideoStats {
|
||||
this.totalFramesRendered = 0;
|
||||
this.frameLossEvents = 0;
|
||||
this.framesLost = 0;
|
||||
this.minHostProcessingLatency = 0;
|
||||
this.maxHostProcessingLatency = 0;
|
||||
this.totalHostProcessingLatency = 0;
|
||||
this.framesWithHostProcessingLatency = 0;
|
||||
this.measurementStartTimestamp = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
|
||||
@@ -18,18 +19,28 @@ import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class ComputerDatabaseManager {
|
||||
private static final String COMPUTER_DB_NAME = "computers3.db";
|
||||
private static final String COMPUTER_DB_NAME = "computers4.db";
|
||||
private static final String COMPUTER_TABLE_NAME = "Computers";
|
||||
private static final String COMPUTER_UUID_COLUMN_NAME = "UUID";
|
||||
private static final String COMPUTER_NAME_COLUMN_NAME = "ComputerName";
|
||||
private static final String ADDRESSES_COLUMN_NAME = "Addresses";
|
||||
private interface AddressFields {
|
||||
String LOCAL = "local";
|
||||
String REMOTE = "remote";
|
||||
String MANUAL = "manual";
|
||||
String IPv6 = "ipv6";
|
||||
|
||||
String ADDRESS = "address";
|
||||
String PORT = "port";
|
||||
}
|
||||
|
||||
private static final String MAC_ADDRESS_COLUMN_NAME = "MacAddress";
|
||||
private static final String SERVER_CERT_COLUMN_NAME = "ServerCert";
|
||||
|
||||
private static final char ADDRESS_DELIMITER = ';';
|
||||
private static final char PORT_DELIMITER = '_';
|
||||
|
||||
private SQLiteDatabase computerDb;
|
||||
|
||||
public ComputerDatabaseManager(Context c) {
|
||||
@@ -64,24 +75,54 @@ public class ComputerDatabaseManager {
|
||||
for (ComputerDetails computer : oldComputers) {
|
||||
updateComputer(computer);
|
||||
}
|
||||
oldComputers = LegacyDatabaseReader3.migrateAllComputers(c);
|
||||
for (ComputerDetails computer : oldComputers) {
|
||||
updateComputer(computer);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteComputer(ComputerDetails details) {
|
||||
computerDb.delete(COMPUTER_TABLE_NAME, COMPUTER_UUID_COLUMN_NAME+"=?", new String[]{details.uuid});
|
||||
}
|
||||
|
||||
public static JSONObject tupleToJson(ComputerDetails.AddressTuple tuple) throws JSONException {
|
||||
if (tuple == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject json = new JSONObject();
|
||||
json.put(AddressFields.ADDRESS, tuple.address);
|
||||
json.put(AddressFields.PORT, tuple.port);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
public static ComputerDetails.AddressTuple tupleFromJson(JSONObject json, String name) throws JSONException {
|
||||
if (!json.has(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JSONObject address = json.getJSONObject(name);
|
||||
return new ComputerDetails.AddressTuple(
|
||||
address.getString(AddressFields.ADDRESS), address.getInt(AddressFields.PORT));
|
||||
}
|
||||
|
||||
public boolean updateComputer(ComputerDetails details) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COMPUTER_UUID_COLUMN_NAME, details.uuid);
|
||||
values.put(COMPUTER_NAME_COLUMN_NAME, details.name);
|
||||
|
||||
StringBuilder addresses = new StringBuilder();
|
||||
addresses.append(details.localAddress != null ? splitTupleToAddress(details.localAddress) : "");
|
||||
addresses.append(ADDRESS_DELIMITER).append(details.remoteAddress != null ? splitTupleToAddress(details.remoteAddress) : "");
|
||||
addresses.append(ADDRESS_DELIMITER).append(details.manualAddress != null ? splitTupleToAddress(details.manualAddress) : "");
|
||||
addresses.append(ADDRESS_DELIMITER).append(details.ipv6Address != null ? splitTupleToAddress(details.ipv6Address) : "");
|
||||
try {
|
||||
JSONObject addresses = new JSONObject();
|
||||
addresses.put(AddressFields.LOCAL, tupleToJson(details.localAddress));
|
||||
addresses.put(AddressFields.REMOTE, tupleToJson(details.remoteAddress));
|
||||
addresses.put(AddressFields.MANUAL, tupleToJson(details.manualAddress));
|
||||
addresses.put(AddressFields.IPv6, tupleToJson(details.ipv6Address));
|
||||
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
values.put(ADDRESSES_COLUMN_NAME, addresses.toString());
|
||||
values.put(MAC_ADDRESS_COLUMN_NAME, details.macAddress);
|
||||
try {
|
||||
if (details.serverCert != null) {
|
||||
@@ -97,44 +138,20 @@ public class ComputerDatabaseManager {
|
||||
return -1 != computerDb.insertWithOnConflict(COMPUTER_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
private static String readNonEmptyString(String input) {
|
||||
if (input.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private static ComputerDetails.AddressTuple splitAddressToTuple(String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] parts = input.split(""+PORT_DELIMITER, -1);
|
||||
if (parts.length == 1) {
|
||||
return new ComputerDetails.AddressTuple(parts[0], NvHTTP.DEFAULT_HTTP_PORT);
|
||||
}
|
||||
else {
|
||||
return new ComputerDetails.AddressTuple(parts[0], Integer.parseInt(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
private static String splitTupleToAddress(ComputerDetails.AddressTuple tuple) {
|
||||
return tuple.address+PORT_DELIMITER+tuple.port;
|
||||
}
|
||||
|
||||
private ComputerDetails getComputerFromCursor(Cursor c) {
|
||||
ComputerDetails details = new ComputerDetails();
|
||||
|
||||
details.uuid = c.getString(0);
|
||||
details.name = c.getString(1);
|
||||
|
||||
String[] addresses = c.getString(2).split(""+ADDRESS_DELIMITER, -1);
|
||||
|
||||
details.localAddress = splitAddressToTuple(readNonEmptyString(addresses[0]));
|
||||
details.remoteAddress = splitAddressToTuple(readNonEmptyString(addresses[1]));
|
||||
details.manualAddress = splitAddressToTuple(readNonEmptyString(addresses[2]));
|
||||
details.ipv6Address = splitAddressToTuple(readNonEmptyString(addresses[3]));
|
||||
try {
|
||||
JSONObject addresses = new JSONObject(c.getString(2));
|
||||
details.localAddress = tupleFromJson(addresses, AddressFields.LOCAL);
|
||||
details.remoteAddress = tupleFromJson(addresses, AddressFields.REMOTE);
|
||||
details.manualAddress = tupleFromJson(addresses, AddressFields.MANUAL);
|
||||
details.ipv6Address = tupleFromJson(addresses, AddressFields.IPv6);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// External port is persisted in the remote address field
|
||||
if (details.remoteAddress != null) {
|
||||
@@ -173,6 +190,35 @@ public class ComputerDatabaseManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a computer by name
|
||||
* NOTE: It is perfectly valid for multiple computers to have the same name,
|
||||
* this function will only return the first one it finds.
|
||||
* Consider using getComputerByUUID instead.
|
||||
* @param name The name of the computer
|
||||
* @see ComputerDatabaseManager#getComputerByUUID(String) for alternative.
|
||||
* @return The computer details, or null if no computer with that name exists
|
||||
*/
|
||||
public ComputerDetails getComputerByName(String name) {
|
||||
try (final Cursor c = computerDb.query(
|
||||
COMPUTER_TABLE_NAME, null, COMPUTER_NAME_COLUMN_NAME+"=?",
|
||||
new String[]{ name }, null, null, null)
|
||||
) {
|
||||
if (!c.moveToFirst()) {
|
||||
// No matching computer
|
||||
return null;
|
||||
}
|
||||
|
||||
return getComputerFromCursor(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a computer by UUID
|
||||
* @param uuid The UUID of the computer
|
||||
* @see ComputerDatabaseManager#getComputerByName(String) for alternative.
|
||||
* @return The computer details, or null if no computer with that UUID exists
|
||||
*/
|
||||
public ComputerDetails getComputerByUUID(String uuid) {
|
||||
try (final Cursor c = computerDb.query(
|
||||
COMPUTER_TABLE_NAME, null, COMPUTER_UUID_COLUMN_NAME+"=?",
|
||||
|
||||
@@ -64,6 +64,8 @@ public class ComputerManagerService extends Service {
|
||||
private boolean pollingActive = false;
|
||||
private final Lock defaultNetworkLock = new ReentrantLock();
|
||||
|
||||
private ConnectivityManager.NetworkCallback networkCallback;
|
||||
|
||||
private DiscoveryService.DiscoveryBinder discoveryBinder;
|
||||
private final ServiceConnection discoveryServiceConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||
@@ -339,57 +341,53 @@ public class ComputerManagerService extends Service {
|
||||
// Acquire the default network lock since we could be changing global process state
|
||||
defaultNetworkLock.lock();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
// On Lollipop or later, we can bind our process to the underlying interface
|
||||
// to ensure our STUN request goes out on that interface or not at all (which is
|
||||
// preferable to getting a VPN endpoint address back).
|
||||
Network[] networks = connMgr.getAllNetworks();
|
||||
for (Network net : networks) {
|
||||
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
||||
if (netCaps != null) {
|
||||
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
||||
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||
// This network looks like an underlying multicast-capable transport,
|
||||
// so let's guess that it's probably where our mDNS response came from.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (connMgr.bindProcessToNetwork(net)) {
|
||||
boundToNetwork = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
||||
// On Lollipop or later, we can bind our process to the underlying interface
|
||||
// to ensure our STUN request goes out on that interface or not at all (which is
|
||||
// preferable to getting a VPN endpoint address back).
|
||||
Network[] networks = connMgr.getAllNetworks();
|
||||
for (Network net : networks) {
|
||||
NetworkCapabilities netCaps = connMgr.getNetworkCapabilities(net);
|
||||
if (netCaps != null) {
|
||||
if (!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) &&
|
||||
!netCaps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||
// This network looks like an underlying multicast-capable transport,
|
||||
// so let's guess that it's probably where our mDNS response came from.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (connMgr.bindProcessToNetwork(net)) {
|
||||
boundToNetwork = true;
|
||||
break;
|
||||
}
|
||||
} else if (ConnectivityManager.setProcessDefaultNetwork(net)) {
|
||||
boundToNetwork = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
||||
if (!activeNetworkIsVpn || boundToNetwork) {
|
||||
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
||||
if (stunResolvedAddress != null) {
|
||||
// We don't know for sure what the external port is, so we will have to guess.
|
||||
// When we contact the PC (if we haven't already), it will update the port.
|
||||
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
||||
// Perform the STUN request if we're not on a VPN or if we bound to a network
|
||||
if (!activeNetworkIsVpn || boundToNetwork) {
|
||||
String stunResolvedAddress = NvConnection.findExternalAddressForMdns("stun.moonlight-stream.org", 3478);
|
||||
if (stunResolvedAddress != null) {
|
||||
// We don't know for sure what the external port is, so we will have to guess.
|
||||
// When we contact the PC (if we haven't already), it will update the port.
|
||||
details.remoteAddress = new ComputerDetails.AddressTuple(stunResolvedAddress, details.guessExternalPort());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unbind from the network
|
||||
if (boundToNetwork) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
connMgr.bindProcessToNetwork(null);
|
||||
// Unbind from the network
|
||||
if (boundToNetwork) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
connMgr.bindProcessToNetwork(null);
|
||||
} else {
|
||||
ConnectivityManager.setProcessDefaultNetwork(null);
|
||||
}
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
ConnectivityManager.setProcessDefaultNetwork(null);
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock the network state
|
||||
if (activeNetworkIsVpn) {
|
||||
defaultNetworkLock.unlock();
|
||||
// Unlock the network state
|
||||
if (activeNetworkIsVpn) {
|
||||
defaultNetworkLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,11 +427,6 @@ public class ComputerManagerService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyComputerRemoved(MdnsComputer computer) {
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDiscoveryFailure(Exception e) {
|
||||
LimeLog.severe("mDNS discovery failed");
|
||||
@@ -553,7 +546,8 @@ public class ComputerManagerService extends Service {
|
||||
// If the current address's port number matches the active address's port number, we can also assume
|
||||
// the HTTPS port will also match. This assumption is currently safe because Sunshine sets all ports
|
||||
// as offsets from the base HTTP port and doesn't allow custom HttpsPort responses for WAN vs LAN.
|
||||
boolean portMatchesActiveAddress = details.activeAddress != null && address.port == details.activeAddress.port;
|
||||
boolean portMatchesActiveAddress = details.state == ComputerDetails.State.ONLINE &&
|
||||
details.activeAddress != null && address.port == details.activeAddress.port;
|
||||
|
||||
NvHTTP http = new NvHTTP(address, portMatchesActiveAddress ? details.httpsPort : 0, idManager.getUniqueId(), details.serverCert,
|
||||
PlatformBinding.getCryptoProvider(ComputerManagerService.this));
|
||||
@@ -743,10 +737,49 @@ public class ComputerManagerService extends Service {
|
||||
}
|
||||
|
||||
releaseLocalDatabaseReference();
|
||||
|
||||
// Monitor for network changes to invalidate our PC state
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
networkCallback = new ConnectivityManager.NetworkCallback() {
|
||||
@Override
|
||||
public void onAvailable(Network network) {
|
||||
LimeLog.info("Resetting PC state for new available network");
|
||||
synchronized (pollingTuples) {
|
||||
for (PollingTuple tuple : pollingTuples) {
|
||||
tuple.computer.state = ComputerDetails.State.UNKNOWN;
|
||||
if (listener != null) {
|
||||
listener.notifyComputerUpdated(tuple.computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLost(Network network) {
|
||||
LimeLog.info("Offlining PCs due to network loss");
|
||||
synchronized (pollingTuples) {
|
||||
for (PollingTuple tuple : pollingTuples) {
|
||||
tuple.computer.state = ComputerDetails.State.OFFLINE;
|
||||
if (listener != null) {
|
||||
listener.notifyComputerUpdated(tuple.computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
connMgr.registerDefaultNetworkCallback(networkCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
connMgr.unregisterNetworkCallback(networkCallback);
|
||||
}
|
||||
|
||||
if (discoveryBinder != null) {
|
||||
// Unbind from the discovery service
|
||||
unbindService(discoveryServiceConnection);
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.limelight.computers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteException;
|
||||
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class LegacyDatabaseReader3 {
|
||||
private static final String COMPUTER_DB_NAME = "computers3.db";
|
||||
private static final String COMPUTER_TABLE_NAME = "Computers";
|
||||
|
||||
private static final char ADDRESS_DELIMITER = ';';
|
||||
private static final char PORT_DELIMITER = '_';
|
||||
|
||||
private static String readNonEmptyString(String input) {
|
||||
if (input.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private static ComputerDetails.AddressTuple splitAddressToTuple(String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] parts = input.split(""+PORT_DELIMITER, -1);
|
||||
if (parts.length == 1) {
|
||||
return new ComputerDetails.AddressTuple(parts[0], NvHTTP.DEFAULT_HTTP_PORT);
|
||||
}
|
||||
else {
|
||||
return new ComputerDetails.AddressTuple(parts[0], Integer.parseInt(parts[1]));
|
||||
}
|
||||
}
|
||||
|
||||
private static String splitTupleToAddress(ComputerDetails.AddressTuple tuple) {
|
||||
return tuple.address+PORT_DELIMITER+tuple.port;
|
||||
}
|
||||
|
||||
private static ComputerDetails getComputerFromCursor(Cursor c) {
|
||||
ComputerDetails details = new ComputerDetails();
|
||||
|
||||
details.uuid = c.getString(0);
|
||||
details.name = c.getString(1);
|
||||
|
||||
String[] addresses = c.getString(2).split(""+ADDRESS_DELIMITER, -1);
|
||||
|
||||
details.localAddress = splitAddressToTuple(readNonEmptyString(addresses[0]));
|
||||
details.remoteAddress = splitAddressToTuple(readNonEmptyString(addresses[1]));
|
||||
details.manualAddress = splitAddressToTuple(readNonEmptyString(addresses[2]));
|
||||
details.ipv6Address = splitAddressToTuple(readNonEmptyString(addresses[3]));
|
||||
|
||||
// External port is persisted in the remote address field
|
||||
if (details.remoteAddress != null) {
|
||||
details.externalPort = details.remoteAddress.port;
|
||||
}
|
||||
else {
|
||||
details.externalPort = NvHTTP.DEFAULT_HTTP_PORT;
|
||||
}
|
||||
|
||||
details.macAddress = c.getString(3);
|
||||
|
||||
try {
|
||||
byte[] derCertData = c.getBlob(4);
|
||||
|
||||
if (derCertData != null) {
|
||||
details.serverCert = (X509Certificate) CertificateFactory.getInstance("X.509")
|
||||
.generateCertificate(new ByteArrayInputStream(derCertData));
|
||||
}
|
||||
} catch (CertificateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// This signifies we don't have dynamic state (like pair state)
|
||||
details.state = ComputerDetails.State.UNKNOWN;
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
public static List<ComputerDetails> getAllComputers(SQLiteDatabase computerDb) {
|
||||
try (final Cursor c = computerDb.rawQuery("SELECT * FROM "+COMPUTER_TABLE_NAME, null)) {
|
||||
LinkedList<ComputerDetails> computerList = new LinkedList<>();
|
||||
while (c.moveToNext()) {
|
||||
ComputerDetails details = getComputerFromCursor(c);
|
||||
|
||||
// If a critical field is corrupt or missing, skip the database entry
|
||||
if (details.uuid == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
computerList.add(details);
|
||||
}
|
||||
|
||||
return computerList;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ComputerDetails> migrateAllComputers(Context c) {
|
||||
try (final SQLiteDatabase computerDb = SQLiteDatabase.openDatabase(
|
||||
c.getDatabasePath(COMPUTER_DB_NAME).getPath(),
|
||||
null, SQLiteDatabase.OPEN_READONLY)
|
||||
) {
|
||||
// Open the existing database
|
||||
return getAllComputers(computerDb);
|
||||
} catch (SQLiteException e) {
|
||||
return new LinkedList<ComputerDetails>();
|
||||
} finally {
|
||||
// Close and delete the old DB
|
||||
c.deleteDatabase(COMPUTER_DB_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,22 +3,21 @@ package com.limelight.discovery;
|
||||
import java.util.List;
|
||||
|
||||
import com.limelight.nvstream.mdns.MdnsComputer;
|
||||
import com.limelight.nvstream.mdns.JmDNSDiscoveryAgent;
|
||||
import com.limelight.nvstream.mdns.MdnsDiscoveryAgent;
|
||||
import com.limelight.nvstream.mdns.MdnsDiscoveryListener;
|
||||
import com.limelight.nvstream.mdns.NsdManagerDiscoveryAgent;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiManager.MulticastLock;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class DiscoveryService extends Service {
|
||||
|
||||
private MdnsDiscoveryAgent discoveryAgent;
|
||||
private MdnsDiscoveryListener boundListener;
|
||||
private MulticastLock multicastLock;
|
||||
|
||||
public class DiscoveryBinder extends Binder {
|
||||
public void setListener(MdnsDiscoveryListener listener) {
|
||||
@@ -26,13 +25,11 @@ public class DiscoveryService extends Service {
|
||||
}
|
||||
|
||||
public void startDiscovery(int queryIntervalMs) {
|
||||
multicastLock.acquire();
|
||||
discoveryAgent.startDiscovery(queryIntervalMs);
|
||||
}
|
||||
|
||||
public void stopDiscovery() {
|
||||
discoveryAgent.stopDiscovery();
|
||||
multicastLock.release();
|
||||
}
|
||||
|
||||
public List<MdnsComputer> getComputerSet() {
|
||||
@@ -42,11 +39,7 @@ public class DiscoveryService extends Service {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
WifiManager wifiMgr = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
|
||||
multicastLock = wifiMgr.createMulticastLock("Limelight mDNS");
|
||||
multicastLock.setReferenceCounted(false);
|
||||
|
||||
discoveryAgent = new MdnsDiscoveryAgent(new MdnsDiscoveryListener() {
|
||||
MdnsDiscoveryListener listener = new MdnsDiscoveryListener() {
|
||||
@Override
|
||||
public void notifyComputerAdded(MdnsComputer computer) {
|
||||
if (boundListener != null) {
|
||||
@@ -54,20 +47,28 @@ public class DiscoveryService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyComputerRemoved(MdnsComputer computer) {
|
||||
if (boundListener != null) {
|
||||
boundListener.notifyComputerRemoved(computer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDiscoveryFailure(Exception e) {
|
||||
if (boundListener != null) {
|
||||
boundListener.notifyDiscoveryFailure(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Prior to Android 14, NsdManager doesn't provide all the capabilities needed for parity
|
||||
// with jmDNS (specifically handling multiple addresses for a single service). There are
|
||||
// also documented reliability bugs early in the Android 4.x series shortly after it was
|
||||
// introduced. The benefit of using NsdManager over jmDNS is that it works correctly in
|
||||
// environments where mDNS proxying is required, like ChromeOS, WSA, and the emulator.
|
||||
//
|
||||
// As such, we use the jmDNS-based MdnsDiscoveryAgent prior to Android 14 and NsdManager
|
||||
// on Android 14 and above.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
discoveryAgent = new JmDNSDiscoveryAgent(getApplicationContext(), listener);
|
||||
}
|
||||
else {
|
||||
discoveryAgent = new NsdManagerDiscoveryAgent(getApplicationContext(), listener);
|
||||
}
|
||||
}
|
||||
|
||||
private final DiscoveryBinder binder = new DiscoveryBinder();
|
||||
@@ -81,7 +82,6 @@ public class DiscoveryService extends Service {
|
||||
public boolean onUnbind(Intent intent) {
|
||||
// Stop any discovery session
|
||||
discoveryAgent.stopDiscovery();
|
||||
multicastLock.release();
|
||||
|
||||
// Unbind the listener
|
||||
boundListener = null;
|
||||
|
||||
@@ -28,14 +28,8 @@ public class DiskAssetLoader {
|
||||
|
||||
public DiskAssetLoader(Context context) {
|
||||
this.cacheDir = context.getCacheDir();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
this.isLowRamDevice =
|
||||
((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
||||
}
|
||||
else {
|
||||
// Use conservative low RAM behavior on very old devices
|
||||
this.isLowRamDevice = true;
|
||||
}
|
||||
this.isLowRamDevice =
|
||||
((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).isLowRamDevice();
|
||||
}
|
||||
|
||||
public boolean checkCacheExists(CachedAppAssetLoader.LoaderTuple tuple) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import javax.crypto.SecretKey;
|
||||
public class ConnectionContext {
|
||||
public ComputerDetails.AddressTuple serverAddress;
|
||||
public int httpsPort;
|
||||
public boolean isNvidiaServerSoftware;
|
||||
public X509Certificate serverCert;
|
||||
public StreamConfiguration streamConfig;
|
||||
public NvConnectionListener connListener;
|
||||
@@ -18,6 +19,7 @@ public class ConnectionContext {
|
||||
// This is the version quad from the appversion tag of /serverinfo
|
||||
public String serverAppVersion;
|
||||
public String serverGfeVersion;
|
||||
public int serverCodecModeSupport;
|
||||
|
||||
// This is the sessionUrl0 tag from /resume and /launch
|
||||
public String rtspSessionUrl;
|
||||
|
||||
@@ -15,7 +15,6 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
@@ -33,7 +32,7 @@ import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.av.audio.AudioRenderer;
|
||||
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||
import com.limelight.nvstream.http.HostHttpResponseException;
|
||||
import com.limelight.nvstream.http.LimelightCryptoProvider;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
@@ -48,21 +47,13 @@ public class NvConnection {
|
||||
private ConnectionContext context;
|
||||
private static Semaphore connectionAllowed = new Semaphore(1);
|
||||
private final boolean isMonkey;
|
||||
private final boolean batchMouseInput;
|
||||
private final Context appContext;
|
||||
|
||||
private static final int MOUSE_BATCH_PERIOD_MS = 5;
|
||||
private Timer mouseInputTimer;
|
||||
private final Object mouseInputLock = new Object();
|
||||
private short relMouseX, relMouseY, relMouseWidth, relMouseHeight;
|
||||
private short absMouseX, absMouseY, absMouseWidth, absMouseHeight;
|
||||
|
||||
public NvConnection(Context appContext, ComputerDetails.AddressTuple host, int httpsPort, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert, boolean batchMouseInput)
|
||||
public NvConnection(Context appContext, ComputerDetails.AddressTuple host, int httpsPort, String uniqueId, StreamConfiguration config, LimelightCryptoProvider cryptoProvider, X509Certificate serverCert)
|
||||
{
|
||||
this.appContext = appContext;
|
||||
this.cryptoProvider = cryptoProvider;
|
||||
this.uniqueId = uniqueId;
|
||||
this.batchMouseInput = batchMouseInput;
|
||||
|
||||
this.context = new ConnectionContext();
|
||||
this.context.serverAddress = host;
|
||||
@@ -96,11 +87,6 @@ public class NvConnection {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
// Stop sending additional input
|
||||
if (mouseInputTimer != null) {
|
||||
mouseInputTimer.cancel();
|
||||
}
|
||||
|
||||
// Interrupt any pending connection. This is thread-safe.
|
||||
MoonBridge.interruptConnection();
|
||||
|
||||
@@ -115,24 +101,6 @@ public class NvConnection {
|
||||
connectionAllowed.release();
|
||||
}
|
||||
|
||||
private void flushMousePosition() {
|
||||
synchronized (mouseInputLock) {
|
||||
if (relMouseX != 0 || relMouseY != 0) {
|
||||
if (relMouseWidth != 0 || relMouseHeight != 0) {
|
||||
MoonBridge.sendMouseMoveAsMousePosition(relMouseX, relMouseY, relMouseWidth, relMouseHeight);
|
||||
}
|
||||
else {
|
||||
MoonBridge.sendMouseMove(relMouseX, relMouseY);
|
||||
}
|
||||
relMouseX = relMouseY = relMouseWidth = relMouseHeight = 0;
|
||||
}
|
||||
if (absMouseX != 0 || absMouseY != 0 || absMouseWidth != 0 || absMouseHeight != 0) {
|
||||
MoonBridge.sendMousePosition(absMouseX, absMouseY, absMouseWidth, absMouseHeight);
|
||||
absMouseX = absMouseY = absMouseWidth = absMouseHeight = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InetAddress resolveServerAddress() throws IOException {
|
||||
// Try to find an address that works for this host
|
||||
InetAddress[] addrs = InetAddress.getAllByName(context.serverAddress.address);
|
||||
@@ -230,7 +198,7 @@ public class NvConnection {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
else {
|
||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||
if (activeNetworkInfo != null) {
|
||||
switch (activeNetworkInfo.getType()) {
|
||||
@@ -263,6 +231,9 @@ public class NvConnection {
|
||||
return false;
|
||||
}
|
||||
|
||||
ComputerDetails details = h.getComputerDetails(serverInfo);
|
||||
context.isNvidiaServerSoftware = details.nvidiaServer;
|
||||
|
||||
// May be missing for older servers
|
||||
context.serverGfeVersion = h.getGfeVersion(serverInfo);
|
||||
|
||||
@@ -271,9 +242,11 @@ public class NvConnection {
|
||||
return false;
|
||||
}
|
||||
|
||||
context.negotiatedHdr = context.streamConfig.getEnableHdr();
|
||||
if ((h.getServerCodecModeSupport(serverInfo) & 0x200) == 0 && context.negotiatedHdr) {
|
||||
context.connListener.displayTransientMessage("Your GPU does not support streaming HDR. The stream will be SDR.");
|
||||
context.serverCodecModeSupport = (int)h.getServerCodecModeSupport(serverInfo);
|
||||
|
||||
context.negotiatedHdr = (context.streamConfig.getSupportedVideoFormats() & MoonBridge.VIDEO_FORMAT_MASK_10BIT) != 0;
|
||||
if ((context.serverCodecModeSupport & 0x20200) == 0 && context.negotiatedHdr) {
|
||||
context.connListener.displayTransientMessage("Your PC GPU does not support streaming HDR. The stream will be SDR.");
|
||||
context.negotiatedHdr = false;
|
||||
}
|
||||
|
||||
@@ -283,13 +256,13 @@ public class NvConnection {
|
||||
|
||||
// Check for a supported stream resolution
|
||||
if ((context.streamConfig.getWidth() > 4096 || context.streamConfig.getHeight() > 4096) &&
|
||||
(h.getServerCodecModeSupport(serverInfo) & 0x200) == 0) {
|
||||
(h.getServerCodecModeSupport(serverInfo) & 0x200) == 0 && context.isNvidiaServerSoftware) {
|
||||
context.connListener.displayMessage("Your host PC does not support streaming at resolutions above 4K.");
|
||||
return false;
|
||||
}
|
||||
else if ((context.streamConfig.getWidth() > 4096 || context.streamConfig.getHeight() > 4096) &&
|
||||
!context.streamConfig.getHevcSupported()) {
|
||||
context.connListener.displayMessage("Your streaming device must support HEVC to stream at resolutions above 4K.");
|
||||
(context.streamConfig.getSupportedVideoFormats() & ~MoonBridge.VIDEO_FORMAT_MASK_H264) == 0) {
|
||||
context.connListener.displayMessage("Your streaming device must support HEVC or AV1 to stream at resolutions above 4K.");
|
||||
return false;
|
||||
}
|
||||
else if (context.streamConfig.getHeight() >= 2160 && !h.supports4K(serverInfo)) {
|
||||
@@ -338,14 +311,14 @@ public class NvConnection {
|
||||
if (h.getCurrentGame(serverInfo) != 0) {
|
||||
try {
|
||||
if (h.getCurrentGame(serverInfo) == app.getAppId()) {
|
||||
if (!h.resumeApp(context)) {
|
||||
if (!h.launchApp(context, "resume", app.getAppId(), context.negotiatedHdr)) {
|
||||
context.connListener.displayMessage("Failed to resume existing session");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return quitAndLaunch(h, context);
|
||||
}
|
||||
} catch (GfeHttpResponseException e) {
|
||||
} catch (HostHttpResponseException e) {
|
||||
if (e.getErrorCode() == 470) {
|
||||
// This is the error you get when you try to resume a session that's not yours.
|
||||
// Because this is fairly common, we'll display a more detailed message.
|
||||
@@ -378,7 +351,7 @@ public class NvConnection {
|
||||
context.connListener.displayMessage("Failed to quit previous session! You must quit it manually");
|
||||
return false;
|
||||
}
|
||||
} catch (GfeHttpResponseException e) {
|
||||
} catch (HostHttpResponseException e) {
|
||||
if (e.getErrorCode() == 599) {
|
||||
context.connListener.displayMessage("This session wasn't started by this device," +
|
||||
" so it cannot be quit. End streaming on the original " +
|
||||
@@ -396,7 +369,7 @@ public class NvConnection {
|
||||
private boolean launchNotRunningApp(NvHTTP h, ConnectionContext context)
|
||||
throws IOException, XmlPullParserException {
|
||||
// Launch the app since it's not running
|
||||
if (!h.launchApp(context, context.streamConfig.getApp().getAppId(), context.negotiatedHdr)) {
|
||||
if (!h.launchApp(context, "launch", context.streamConfig.getApp().getAppId(), context.negotiatedHdr)) {
|
||||
context.connListener.displayMessage("Failed to launch application");
|
||||
return false;
|
||||
}
|
||||
@@ -423,7 +396,7 @@ public class NvConnection {
|
||||
return;
|
||||
}
|
||||
context.connListener.stageComplete(appName);
|
||||
} catch (GfeHttpResponseException e) {
|
||||
} catch (HostHttpResponseException e) {
|
||||
e.printStackTrace();
|
||||
context.connListener.displayMessage(e.getMessage());
|
||||
context.connListener.stageFailed(appName, 0, e.getErrorCode());
|
||||
@@ -454,15 +427,13 @@ public class NvConnection {
|
||||
MoonBridge.setupBridge(videoDecoderRenderer, audioRenderer, connectionListener);
|
||||
int ret = MoonBridge.startConnection(context.serverAddress.address,
|
||||
context.serverAppVersion, context.serverGfeVersion, context.rtspSessionUrl,
|
||||
context.serverCodecModeSupport,
|
||||
context.negotiatedWidth, context.negotiatedHeight,
|
||||
context.streamConfig.getRefreshRate(), context.streamConfig.getBitrate(),
|
||||
context.negotiatedPacketSize, context.negotiatedRemoteStreaming,
|
||||
context.streamConfig.getAudioConfiguration().toInt(),
|
||||
context.streamConfig.getHevcSupported(),
|
||||
context.negotiatedHdr,
|
||||
context.streamConfig.getHevcBitratePercentageMultiplier(),
|
||||
context.streamConfig.getSupportedVideoFormats(),
|
||||
context.streamConfig.getClientRefreshRateX100(),
|
||||
context.streamConfig.getEncryptionFlags(),
|
||||
context.riKey.getEncoded(), ib.array(),
|
||||
context.videoCapabilities,
|
||||
context.streamConfig.getColorSpace(),
|
||||
@@ -474,20 +445,6 @@ public class NvConnection {
|
||||
connectionAllowed.release();
|
||||
return;
|
||||
}
|
||||
|
||||
if (batchMouseInput) {
|
||||
// High polling rate mice can cause GeForce Experience's input queue to get backed up,
|
||||
// causing massive input latency. We counter this by limiting our mouse events to 200 Hz
|
||||
// which appears to avoid triggering the issue on all known configurations.
|
||||
mouseInputTimer = new Timer("MouseInput", true);
|
||||
mouseInputTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Flush the mouse position every 5 ms
|
||||
flushMousePosition();
|
||||
}
|
||||
}, MOUSE_BATCH_PERIOD_MS, MOUSE_BATCH_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
@@ -496,65 +453,27 @@ public class NvConnection {
|
||||
public void sendMouseMove(final short deltaX, final short deltaY)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
synchronized (mouseInputLock) {
|
||||
relMouseX += deltaX;
|
||||
relMouseY += deltaY;
|
||||
|
||||
// Reset these to ensure we don't send this as a position update
|
||||
relMouseWidth = 0;
|
||||
relMouseHeight = 0;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
MoonBridge.sendMouseMove(deltaX, deltaY);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMousePosition(short x, short y, short referenceWidth, short referenceHeight)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
synchronized (mouseInputLock) {
|
||||
absMouseX = x;
|
||||
absMouseY = y;
|
||||
absMouseWidth = referenceWidth;
|
||||
absMouseHeight = referenceHeight;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
MoonBridge.sendMousePosition(x, y, referenceWidth, referenceHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseMoveAsMousePosition(short deltaX, short deltaY, short referenceWidth, short referenceHeight)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
synchronized (mouseInputLock) {
|
||||
// Only accumulate the delta if the reference size is the same
|
||||
if (relMouseWidth == referenceWidth && relMouseHeight == referenceHeight) {
|
||||
relMouseX += deltaX;
|
||||
relMouseY += deltaY;
|
||||
}
|
||||
else {
|
||||
relMouseX = deltaX;
|
||||
relMouseY = deltaY;
|
||||
}
|
||||
|
||||
relMouseWidth = referenceWidth;
|
||||
relMouseHeight = referenceHeight;
|
||||
}
|
||||
|
||||
if (!batchMouseInput) {
|
||||
flushMousePosition();
|
||||
}
|
||||
MoonBridge.sendMouseMoveAsMousePosition(deltaX, deltaY, referenceWidth, referenceHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseButtonDown(final byte mouseButton)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseButton(MouseButtonPacket.PRESS_EVENT, mouseButton);
|
||||
}
|
||||
}
|
||||
@@ -562,13 +481,12 @@ public class NvConnection {
|
||||
public void sendMouseButtonUp(final byte mouseButton)
|
||||
{
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseButton(MouseButtonPacket.RELEASE_EVENT, mouseButton);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendControllerInput(final short controllerNumber,
|
||||
final short activeGamepadMask, final short buttonFlags,
|
||||
final short activeGamepadMask, final int buttonFlags,
|
||||
final byte leftTrigger, final byte rightTrigger,
|
||||
final short leftStickX, final short leftStickY,
|
||||
final short rightStickX, final short rightStickY)
|
||||
@@ -578,38 +496,89 @@ public class NvConnection {
|
||||
leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendControllerInput(final short buttonFlags,
|
||||
final byte leftTrigger, final byte rightTrigger,
|
||||
final short leftStickX, final short leftStickY,
|
||||
final short rightStickX, final short rightStickY)
|
||||
{
|
||||
|
||||
public void sendKeyboardInput(final short keyMap, final byte keyDirection, final byte modifier, final byte flags) {
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX,
|
||||
leftStickY, rightStickX, rightStickY);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendKeyboardInput(final short keyMap, final byte keyDirection, final byte modifier) {
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendKeyboardInput(keyMap, keyDirection, modifier);
|
||||
MoonBridge.sendKeyboardInput(keyMap, keyDirection, modifier, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseScroll(final byte scrollClicks) {
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseScroll(scrollClicks);
|
||||
MoonBridge.sendMouseHighResScroll((short)(scrollClicks * 120)); // WHEEL_DELTA
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseHScroll(final byte scrollClicks) {
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendMouseHighResHScroll((short)(scrollClicks * 120)); // WHEEL_DELTA
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseHighResScroll(final short scrollAmount) {
|
||||
if (!isMonkey) {
|
||||
flushMousePosition();
|
||||
MoonBridge.sendMouseHighResScroll(scrollAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMouseHighResHScroll(final short scrollAmount) {
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendMouseHighResHScroll(scrollAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressureOrDistance,
|
||||
float contactAreaMajor, float contactAreaMinor, short rotation) {
|
||||
if (!isMonkey) {
|
||||
return MoonBridge.sendTouchEvent(eventType, pointerId, x, y, pressureOrDistance,
|
||||
contactAreaMajor, contactAreaMinor, rotation);
|
||||
}
|
||||
else {
|
||||
return MoonBridge.LI_ERR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
public int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
|
||||
float pressureOrDistance, float contactAreaMajor, float contactAreaMinor,
|
||||
short rotation, byte tilt) {
|
||||
if (!isMonkey) {
|
||||
return MoonBridge.sendPenEvent(eventType, toolType, penButtons, x, y, pressureOrDistance,
|
||||
contactAreaMajor, contactAreaMinor, rotation, tilt);
|
||||
}
|
||||
else {
|
||||
return MoonBridge.LI_ERR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
public int sendControllerArrivalEvent(byte controllerNumber, short activeGamepadMask, byte type,
|
||||
int supportedButtonFlags, short capabilities) {
|
||||
return MoonBridge.sendControllerArrivalEvent(controllerNumber, activeGamepadMask, type, supportedButtonFlags, capabilities);
|
||||
}
|
||||
|
||||
public int sendControllerTouchEvent(byte controllerNumber, byte eventType, int pointerId,
|
||||
float x, float y, float pressure) {
|
||||
if (!isMonkey) {
|
||||
return MoonBridge.sendControllerTouchEvent(controllerNumber, eventType, pointerId, x, y, pressure);
|
||||
}
|
||||
else {
|
||||
return MoonBridge.LI_ERR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
public int sendControllerMotionEvent(byte controllerNumber, byte motionType,
|
||||
float x, float y, float z) {
|
||||
if (!isMonkey) {
|
||||
return MoonBridge.sendControllerMotionEvent(controllerNumber, motionType, x, y, z);
|
||||
}
|
||||
else {
|
||||
return MoonBridge.LI_ERR_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
public void sendControllerBatteryEvent(byte controllerNumber, byte batteryState, byte batteryPercentage) {
|
||||
MoonBridge.sendControllerBatteryEvent(controllerNumber, batteryState, batteryPercentage);
|
||||
}
|
||||
|
||||
public void sendUtf8Text(final String text) {
|
||||
if (!isMonkey) {
|
||||
MoonBridge.sendUtf8Text(text);
|
||||
|
||||
@@ -13,6 +13,11 @@ public interface NvConnectionListener {
|
||||
void displayTransientMessage(String message);
|
||||
|
||||
void rumble(short controllerNumber, short lowFreqMotor, short highFreqMotor);
|
||||
void rumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger);
|
||||
|
||||
void setHdrMode(boolean enabled);
|
||||
void setHdrMode(boolean enabled, byte[] hdrMetadata);
|
||||
|
||||
void setMotionEventState(short controllerNumber, byte motionType, short reportRateHz);
|
||||
|
||||
void setControllerLED(short controllerNumber, byte r, byte g, byte b);
|
||||
}
|
||||
|
||||
@@ -22,13 +22,12 @@ public class StreamConfiguration {
|
||||
private int maxPacketSize;
|
||||
private int remote;
|
||||
private MoonBridge.AudioConfiguration audioConfiguration;
|
||||
private boolean supportsHevc;
|
||||
private int hevcBitratePercentageMultiplier;
|
||||
private boolean enableHdr;
|
||||
private int supportedVideoFormats;
|
||||
private int attachedGamepadMask;
|
||||
private int encryptionFlags;
|
||||
private int colorRange;
|
||||
private int colorSpace;
|
||||
private boolean persistGamepadsAfterDisconnect;
|
||||
|
||||
public static class Builder {
|
||||
private StreamConfiguration config = new StreamConfiguration();
|
||||
@@ -84,16 +83,6 @@ public class StreamConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setHevcBitratePercentageMultiplier(int multiplier) {
|
||||
config.hevcBitratePercentageMultiplier = multiplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setEnableHdr(boolean enableHdr) {
|
||||
config.enableHdr = enableHdr;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setAttachedGamepadMask(int attachedGamepadMask) {
|
||||
config.attachedGamepadMask = attachedGamepadMask;
|
||||
return this;
|
||||
@@ -109,18 +98,13 @@ public class StreamConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setClientRefreshRateX100(int refreshRateX100) {
|
||||
config.clientRefreshRateX100 = refreshRateX100;
|
||||
public StreamConfiguration.Builder setPersistGamepadsAfterDisconnect(boolean value) {
|
||||
config.persistGamepadsAfterDisconnect = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setAudioEncryption(boolean enable) {
|
||||
if (enable) {
|
||||
config.encryptionFlags |= MoonBridge.ENCFLG_AUDIO;
|
||||
}
|
||||
else {
|
||||
config.encryptionFlags &= ~MoonBridge.ENCFLG_AUDIO;
|
||||
}
|
||||
public StreamConfiguration.Builder setClientRefreshRateX100(int refreshRateX100) {
|
||||
config.clientRefreshRateX100 = refreshRateX100;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -129,8 +113,8 @@ public class StreamConfiguration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public StreamConfiguration.Builder setHevcSupported(boolean supportsHevc) {
|
||||
config.supportsHevc = supportsHevc;
|
||||
public StreamConfiguration.Builder setSupportedVideoFormats(int supportedVideoFormats) {
|
||||
config.supportedVideoFormats = supportedVideoFormats;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -162,8 +146,7 @@ public class StreamConfiguration {
|
||||
this.sops = true;
|
||||
this.enableAdaptiveResolution = false;
|
||||
this.audioConfiguration = MoonBridge.AUDIO_CONFIGURATION_STEREO;
|
||||
this.supportsHevc = false;
|
||||
this.enableHdr = false;
|
||||
this.supportedVideoFormats = MoonBridge.VIDEO_FORMAT_H264;
|
||||
this.attachedGamepadMask = 0;
|
||||
}
|
||||
|
||||
@@ -215,28 +198,20 @@ public class StreamConfiguration {
|
||||
return audioConfiguration;
|
||||
}
|
||||
|
||||
public boolean getHevcSupported() {
|
||||
return supportsHevc;
|
||||
}
|
||||
|
||||
public int getHevcBitratePercentageMultiplier() {
|
||||
return hevcBitratePercentageMultiplier;
|
||||
}
|
||||
|
||||
public boolean getEnableHdr() {
|
||||
return enableHdr;
|
||||
public int getSupportedVideoFormats() {
|
||||
return supportedVideoFormats;
|
||||
}
|
||||
|
||||
public int getAttachedGamepadMask() {
|
||||
return attachedGamepadMask;
|
||||
}
|
||||
|
||||
public int getClientRefreshRateX100() {
|
||||
return clientRefreshRateX100;
|
||||
public boolean getPersistGamepadsAfterDisconnect() {
|
||||
return persistGamepadsAfterDisconnect;
|
||||
}
|
||||
|
||||
public int getEncryptionFlags() {
|
||||
return encryptionFlags;
|
||||
public int getClientRefreshRateX100() {
|
||||
return clientRefreshRateX100;
|
||||
}
|
||||
|
||||
public int getColorRange() {
|
||||
|
||||
@@ -10,11 +10,12 @@ public abstract class VideoDecoderRenderer {
|
||||
// This is called once for each frame-start NALU. This means it will be called several times
|
||||
// for an IDR frame which contains several parameter sets and the I-frame data.
|
||||
public abstract int submitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
|
||||
int frameNumber, int frameType, long receiveTimeMs, long enqueueTimeMs);
|
||||
int frameNumber, int frameType, char frameHostProcessingLatency,
|
||||
long receiveTimeUs, long enqueueTimeUs);
|
||||
|
||||
public abstract void cleanup();
|
||||
|
||||
public abstract int getCapabilities();
|
||||
|
||||
public abstract void setHdrMode(boolean enabled);
|
||||
public abstract void setHdrMode(boolean enabled, byte[] hdrMetadata);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.limelight.nvstream.http;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public class ComputerDetails {
|
||||
@@ -20,13 +21,18 @@ public class ComputerDetails {
|
||||
throw new IllegalArgumentException("Invalid port");
|
||||
}
|
||||
|
||||
// If this was an escaped IPv6 address, remove the brackets
|
||||
if (address.startsWith("[") && address.endsWith("]")) {
|
||||
address = address.substring(1, address.length() - 1);
|
||||
}
|
||||
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return address.hashCode();
|
||||
return Objects.hash(address, port);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,7 +46,14 @@ public class ComputerDetails {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return address + ":" + port;
|
||||
if (address.contains(":")) {
|
||||
// IPv6
|
||||
return "[" + address + "]:" + port;
|
||||
}
|
||||
else {
|
||||
// IPv4 and hostnames
|
||||
return address + ":" + port;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +75,7 @@ public class ComputerDetails {
|
||||
public PairingManager.PairState pairState;
|
||||
public int runningGameId;
|
||||
public String rawAppList;
|
||||
public boolean nvidiaServer;
|
||||
|
||||
public ComputerDetails() {
|
||||
// Use defaults
|
||||
@@ -130,6 +144,7 @@ public class ComputerDetails {
|
||||
this.httpsPort = details.httpsPort;
|
||||
this.pairState = details.pairState;
|
||||
this.runningGameId = details.runningGameId;
|
||||
this.nvidiaServer = details.nvidiaServer;
|
||||
this.rawAppList = details.rawAppList;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -2,13 +2,13 @@ package com.limelight.nvstream.http;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class GfeHttpResponseException extends IOException {
|
||||
public class HostHttpResponseException extends IOException {
|
||||
private static final long serialVersionUID = 1543508830807804222L;
|
||||
|
||||
private int errorCode;
|
||||
private String errorMsg;
|
||||
|
||||
public GfeHttpResponseException(int errorCode, String errorMsg) {
|
||||
public HostHttpResponseException(int errorCode, String errorMsg) {
|
||||
this.errorCode = errorCode;
|
||||
this.errorMsg = errorMsg;
|
||||
}
|
||||
@@ -23,6 +23,6 @@ public class GfeHttpResponseException extends IOException {
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "GeForce Experience returned error: "+errorMsg+" (Error code: "+errorCode+")";
|
||||
return "Host PC returned error: "+errorMsg+" (Error code: "+errorCode+")";
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package com.limelight.nvstream.http;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
|
||||
public interface LimelightCryptoProvider {
|
||||
X509Certificate getClientCertificate();
|
||||
RSAPrivateKey getClientPrivateKey();
|
||||
PrivateKey getClientPrivateKey();
|
||||
byte[] getPemEncodedClientCertificate();
|
||||
String encodeBase64String(byte[] data);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Proxy;
|
||||
import java.net.Socket;
|
||||
@@ -49,6 +50,7 @@ import com.limelight.BuildConfig;
|
||||
import com.limelight.LimeLog;
|
||||
import com.limelight.nvstream.ConnectionContext;
|
||||
import com.limelight.nvstream.http.PairingManager.PairState;
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
|
||||
import okhttp3.ConnectionPool;
|
||||
import okhttp3.HttpUrl;
|
||||
@@ -209,9 +211,21 @@ public class NvHTTP {
|
||||
this.httpsPort = httpsPort;
|
||||
|
||||
try {
|
||||
// If this is an IPv4-mapped IPv6 address, OkHTTP will choke on it if it's
|
||||
// in IPv6 form, because InetAddress.getByName() will return an Inet4Address
|
||||
// for what OkHTTP thinks is an IPv6 address. Normalize it into IPv4 form
|
||||
// to avoid triggering this bug.
|
||||
String addressString = address.address;
|
||||
if (addressString.contains(":") && addressString.contains(".")) {
|
||||
InetAddress addr = InetAddress.getByName(addressString);
|
||||
if (addr instanceof Inet4Address) {
|
||||
addressString = ((Inet4Address)addr).getHostAddress();
|
||||
}
|
||||
}
|
||||
|
||||
this.baseUrlHttp = new HttpUrl.Builder()
|
||||
.scheme("http")
|
||||
.host(address.address)
|
||||
.host(addressString)
|
||||
.port(address.port)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
@@ -266,7 +280,7 @@ public class NvHTTP {
|
||||
return getXmlString(new StringReader(str), tagname, throwIfMissing);
|
||||
}
|
||||
|
||||
private static void verifyResponseStatus(XmlPullParser xpp) throws GfeHttpResponseException {
|
||||
private static void verifyResponseStatus(XmlPullParser xpp) throws HostHttpResponseException {
|
||||
// We use Long.parseLong() because in rare cases GFE can send back a status code of
|
||||
// 0xFFFFFFFF, which will cause Integer.parseInt() to throw a NumberFormatException due
|
||||
// to exceeding Integer.MAX_VALUE. We'll get the desired error code of -1 by just casting
|
||||
@@ -280,7 +294,7 @@ public class NvHTTP {
|
||||
statusCode = 418;
|
||||
statusMsg = "Missing audio capture device. Reinstall GeForce Experience.";
|
||||
}
|
||||
throw new GfeHttpResponseException(statusCode, statusMsg);
|
||||
throw new HostHttpResponseException(statusCode, statusMsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +320,7 @@ public class NvHTTP {
|
||||
if (e.getCause() instanceof CertificateException) {
|
||||
// Jump to the GfeHttpResponseException exception handler to retry
|
||||
// over HTTP which will allow us to pair again to update the cert
|
||||
throw new GfeHttpResponseException(401, "Server certificate mismatch");
|
||||
throw new HostHttpResponseException(401, "Server certificate mismatch");
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
@@ -317,7 +331,7 @@ public class NvHTTP {
|
||||
// We want this because it will throw us into the HTTP case if the client is unpaired.
|
||||
getServerVersion(resp);
|
||||
}
|
||||
catch (GfeHttpResponseException e) {
|
||||
catch (HostHttpResponseException e) {
|
||||
if (e.getErrorCode() == 401) {
|
||||
// Cert validation error - fall back to HTTP
|
||||
return openHttpConnectionToString(client, baseUrlHttp, "serverinfo");
|
||||
@@ -342,11 +356,10 @@ public class NvHTTP {
|
||||
|
||||
return new ComputerDetails.AddressTuple(address, port);
|
||||
}
|
||||
|
||||
public ComputerDetails getComputerDetails(boolean likelyOnline) throws IOException, XmlPullParserException {
|
||||
|
||||
public ComputerDetails getComputerDetails(String serverInfo) throws IOException, XmlPullParserException {
|
||||
ComputerDetails details = new ComputerDetails();
|
||||
String serverInfo = getServerInfo(likelyOnline);
|
||||
|
||||
|
||||
details.name = getXmlString(serverInfo, "hostname", false);
|
||||
if (details.name == null || details.name.isEmpty()) {
|
||||
details.name = "UNKNOWN";
|
||||
@@ -368,12 +381,19 @@ public class NvHTTP {
|
||||
|
||||
details.pairState = getPairState(serverInfo);
|
||||
details.runningGameId = getCurrentGame(serverInfo);
|
||||
|
||||
|
||||
// The MJOLNIR codename was used by GFE but never by any third-party server
|
||||
details.nvidiaServer = getXmlString(serverInfo, "state", true).contains("MJOLNIR");
|
||||
|
||||
// We could reach it so it's online
|
||||
details.state = ComputerDetails.State.ONLINE;
|
||||
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
public ComputerDetails getComputerDetails(boolean likelyOnline) throws IOException, XmlPullParserException {
|
||||
return getComputerDetails(getServerInfo(likelyOnline));
|
||||
}
|
||||
|
||||
// This hack is Android-specific but we do it on all platforms
|
||||
// because it doesn't really matter
|
||||
@@ -383,16 +403,7 @@ public class NvHTTP {
|
||||
try {
|
||||
SSLContext sc = SSLContext.getInstance("TLS");
|
||||
sc.init(new KeyManager[] { keyManager }, new TrustManager[] { trustManager }, new SecureRandom());
|
||||
|
||||
// TLS 1.2 is not enabled by default prior to Android 5.0, so we'll need a custom
|
||||
// SSLSocketFactory in order to connect to GFE 3.20.4 which requires TLSv1.2 or later.
|
||||
// We don't just always use TLSv12SocketFactory because explicitly specifying TLS versions
|
||||
// prevents later TLS versions from being negotiated even if client and server otherwise
|
||||
// support them.
|
||||
return client.newBuilder().sslSocketFactory(
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
|
||||
sc.getSocketFactory() : new TLSv12SocketFactory(sc),
|
||||
trustManager).build();
|
||||
return client.newBuilder().sslSocketFactory(sc.getSocketFactory(), trustManager).build();
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
@@ -435,7 +446,7 @@ public class NvHTTP {
|
||||
throw new FileNotFoundException(completeUrl.toString());
|
||||
}
|
||||
else {
|
||||
throw new GfeHttpResponseException(response.code(), response.message());
|
||||
throw new HostHttpResponseException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,6 +586,12 @@ public class NvHTTP {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an app by ID
|
||||
* @param appId The ID of the app
|
||||
* @see #getAppByName(String) for alternative.
|
||||
* @return app details, or null if no app with that ID exists
|
||||
*/
|
||||
public NvApp getAppById(int appId) throws IOException, XmlPullParserException {
|
||||
LinkedList<NvApp> appList = getAppList();
|
||||
for (NvApp appFromList : appList) {
|
||||
@@ -584,11 +601,16 @@ public class NvHTTP {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* NOTE: Only use this function if you know what you're doing.
|
||||
* It's totally valid to have two apps named the same thing,
|
||||
* or even nothing at all! Look apps up by ID if at all possible
|
||||
* using the above function */
|
||||
|
||||
/**
|
||||
* Get an app by name
|
||||
* NOTE: It is perfectly valid for multiple apps to have the same name,
|
||||
* this function will only return the first one it finds.
|
||||
* Consider using getAppById instead.
|
||||
* @param appName The name of the app
|
||||
* @see #getAppById(int) for alternative.
|
||||
* @return app details, or null if no app with that name exists
|
||||
*/
|
||||
public NvApp getAppByName(String appName) throws IOException, XmlPullParserException {
|
||||
LinkedList<NvApp> appList = getAppList();
|
||||
for (NvApp appFromList : appList) {
|
||||
@@ -669,7 +691,7 @@ public class NvHTTP {
|
||||
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true), "applist");
|
||||
}
|
||||
|
||||
public LinkedList<NvApp> getAppList() throws GfeHttpResponseException, IOException, XmlPullParserException {
|
||||
public LinkedList<NvApp> getAppList() throws HostHttpResponseException, IOException, XmlPullParserException {
|
||||
if (verbose) {
|
||||
// Use the raw function so the app list is printed
|
||||
return getAppListByReader(new StringReader(getAppListRaw()));
|
||||
@@ -681,12 +703,12 @@ public class NvHTTP {
|
||||
}
|
||||
}
|
||||
|
||||
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws GfeHttpResponseException, IOException {
|
||||
String executePairingCommand(String additionalArguments, boolean enableReadTimeout) throws HostHttpResponseException, IOException {
|
||||
return openHttpConnectionToString(enableReadTimeout ? httpClientLongConnectTimeout : httpClientLongConnectNoReadTimeout,
|
||||
baseUrlHttp, "pair", "devicename=roth&updateState=1&" + additionalArguments);
|
||||
}
|
||||
|
||||
String executePairingChallenge() throws GfeHttpResponseException, IOException {
|
||||
String executePairingChallenge() throws HostHttpResponseException, IOException {
|
||||
return openHttpConnectionToString(httpClientLongConnectTimeout, getHttpsUrl(true),
|
||||
"pair", "devicename=roth&updateState=1&phrase=pairchallenge");
|
||||
}
|
||||
@@ -731,27 +753,30 @@ public class NvHTTP {
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public boolean launchApp(ConnectionContext context, int appId, boolean enableHdr) throws IOException, XmlPullParserException {
|
||||
public boolean launchApp(ConnectionContext context, String verb, int appId, boolean enableHdr) throws IOException, XmlPullParserException {
|
||||
// Using an FPS value over 60 causes SOPS to default to 720p60,
|
||||
// so force it to 0 to ensure the correct resolution is set. We
|
||||
// used to use 60 here but that locked the frame rate to 60 FPS
|
||||
// on GFE 3.20.3.
|
||||
int fps = context.streamConfig.getLaunchRefreshRate() > 60 ? 0 : context.streamConfig.getLaunchRefreshRate();
|
||||
int fps = context.isNvidiaServerSoftware && context.streamConfig.getLaunchRefreshRate() > 60 ?
|
||||
0 : context.streamConfig.getLaunchRefreshRate();
|
||||
|
||||
// Using an unsupported resolution (not 720p, 1080p, or 4K) causes
|
||||
// GFE to force SOPS to 720p60. This is fine for < 720p resolutions like
|
||||
// 360p or 480p, but it is not ideal for 1440p and other resolutions.
|
||||
// When we detect an unsupported resolution, disable SOPS unless it's under 720p.
|
||||
// FIXME: Detect support resolutions using the serverinfo response, not a hardcoded list
|
||||
boolean enableSops = context.streamConfig.getSops();
|
||||
if (context.negotiatedWidth * context.negotiatedHeight > 1280 * 720 &&
|
||||
context.negotiatedWidth * context.negotiatedHeight != 1920 * 1080 &&
|
||||
context.negotiatedWidth * context.negotiatedHeight != 3840 * 2160) {
|
||||
LimeLog.info("Disabling SOPS due to non-standard resolution: "+context.negotiatedWidth+"x"+context.negotiatedHeight);
|
||||
enableSops = false;
|
||||
if (context.isNvidiaServerSoftware) {
|
||||
// Using an unsupported resolution (not 720p, 1080p, or 4K) causes
|
||||
// GFE to force SOPS to 720p60. This is fine for < 720p resolutions like
|
||||
// 360p or 480p, but it is not ideal for 1440p and other resolutions.
|
||||
// When we detect an unsupported resolution, disable SOPS unless it's under 720p.
|
||||
// FIXME: Detect support resolutions using the serverinfo response, not a hardcoded list
|
||||
if (context.negotiatedWidth * context.negotiatedHeight > 1280 * 720 &&
|
||||
context.negotiatedWidth * context.negotiatedHeight != 1920 * 1080 &&
|
||||
context.negotiatedWidth * context.negotiatedHeight != 3840 * 2160) {
|
||||
LimeLog.info("Disabling SOPS due to non-standard resolution: "+context.negotiatedWidth+"x"+context.negotiatedHeight);
|
||||
enableSops = false;
|
||||
}
|
||||
}
|
||||
|
||||
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "launch",
|
||||
String xmlStr = openHttpConnectionToString(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), verb,
|
||||
"appid=" + appId +
|
||||
"&mode=" + context.negotiatedWidth + "x" + context.negotiatedHeight + "x" + fps +
|
||||
"&additionalStates=1&sops=" + (enableSops ? 1 : 0) +
|
||||
@@ -760,24 +785,12 @@ public class NvHTTP {
|
||||
(!enableHdr ? "" : "&hdrMode=1&clientHdrCapVersion=0&clientHdrCapSupportedFlagsInUint32=0&clientHdrCapMetaDataId=NV_STATIC_METADATA_TYPE_1&clientHdrCapDisplayData=0x0x0x0x0x0x0x0x0x0x0") +
|
||||
"&localAudioPlayMode=" + (context.streamConfig.getPlayLocalAudio() ? 1 : 0) +
|
||||
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo() +
|
||||
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() : "") +
|
||||
(context.streamConfig.getAttachedGamepadMask() != 0 ? "&gcmap=" + context.streamConfig.getAttachedGamepadMask() : ""));
|
||||
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(httpClientLongConnectNoReadTimeout, getHttpsUrl(true), "resume",
|
||||
"rikey="+bytesToHex(context.riKey.getEncoded()) +
|
||||
"&rikeyid="+context.riKeyId +
|
||||
"&surroundAudioInfo=" + context.streamConfig.getAudioConfiguration().getSurroundAudioInfo());
|
||||
if (!getXmlString(xmlStr, "resume", true).equals("0")) {
|
||||
"&remoteControllersBitmap=" + context.streamConfig.getAttachedGamepadMask() +
|
||||
"&gcmap=" + context.streamConfig.getAttachedGamepadMask() +
|
||||
"&gcpersist="+(context.streamConfig.getPersistGamepadsAfterDisconnect() ? 1 : 0) +
|
||||
MoonBridge.getLaunchUrlQueryParameters());
|
||||
if ((verb.equals("launch") && !getXmlString(xmlStr, "gamesession", true).equals("0") ||
|
||||
(verb.equals("resume") && !getXmlString(xmlStr, "resume", true).equals("0")))) {
|
||||
// sessionUrl0 will be missing for older GFE versions
|
||||
context.rtspSessionUrl = getXmlString(xmlStr, "sessionUrl0", false);
|
||||
return true;
|
||||
@@ -798,67 +811,9 @@ public class NvHTTP {
|
||||
if (getCurrentGame(getServerInfo(true)) != 0) {
|
||||
// Generate a synthetic GfeResponseException letting the caller know
|
||||
// that they can't kill someone else's stream.
|
||||
throw new GfeHttpResponseException(599, "");
|
||||
throw new HostHttpResponseException(599, "");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Based on example code from https://blog.dev-area.net/2015/08/13/android-4-1-enable-tls-1-1-and-tls-1-2/
|
||||
private static class TLSv12SocketFactory extends SSLSocketFactory {
|
||||
private SSLSocketFactory internalSSLSocketFactory;
|
||||
|
||||
public TLSv12SocketFactory(SSLContext context) {
|
||||
internalSSLSocketFactory = context.getSocketFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getDefaultCipherSuites() {
|
||||
return internalSSLSocketFactory.getDefaultCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedCipherSuites() {
|
||||
return internalSSLSocketFactory.getSupportedCipherSuites();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket() throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(s, host, port, autoClose));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port) throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port, localHost, localPort));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress host, int port) throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(host, port));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
|
||||
return enableTLSv12OnSocket(internalSSLSocketFactory.createSocket(address, port, localAddress, localPort));
|
||||
}
|
||||
|
||||
private Socket enableTLSv12OnSocket(Socket socket) {
|
||||
if (socket instanceof SSLSocket) {
|
||||
// TLS 1.2 is not enabled by default prior to Android 5.0. We must enable it
|
||||
// explicitly to ensure we can communicate with GFE 3.20.4 which blocks TLS 1.0.
|
||||
((SSLSocket)socket).setEnabledProtocols(new String[] {"TLSv1.2"});
|
||||
}
|
||||
return socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,10 +98,21 @@ public class PairingManager {
|
||||
System.arraycopy(pin.getBytes("UTF-8"), 0, saltedPin, salt.length, pin.length());
|
||||
return saltedPin;
|
||||
}
|
||||
|
||||
private static Signature getSha256SignatureInstanceForKey(Key key) throws NoSuchAlgorithmException {
|
||||
switch (key.getAlgorithm()) {
|
||||
case "RSA":
|
||||
return Signature.getInstance("SHA256withRSA");
|
||||
case "EC":
|
||||
return Signature.getInstance("SHA256withECDSA");
|
||||
default:
|
||||
throw new NoSuchAlgorithmException("Unhandled key algorithm: " + key.getAlgorithm());
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean verifySignature(byte[] data, byte[] signature, Certificate cert) {
|
||||
try {
|
||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
||||
Signature sig = PairingManager.getSha256SignatureInstanceForKey(cert.getPublicKey());
|
||||
sig.initVerify(cert.getPublicKey());
|
||||
sig.update(data);
|
||||
return sig.verify(signature);
|
||||
@@ -113,12 +124,10 @@ public class PairingManager {
|
||||
|
||||
private static byte[] signData(byte[] data, PrivateKey key) {
|
||||
try {
|
||||
Signature sig = Signature.getInstance("SHA256withRSA");
|
||||
Signature sig = PairingManager.getSha256SignatureInstanceForKey(key);
|
||||
sig.initSign(key);
|
||||
sig.update(data);
|
||||
byte[] signature = new byte[256];
|
||||
sig.sign(signature, 0, signature.length);
|
||||
return signature;
|
||||
return sig.sign();
|
||||
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
@@ -245,7 +254,7 @@ public class PairingManager {
|
||||
// Get the server's signed secret
|
||||
byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret", true));
|
||||
byte[] serverSecret = Arrays.copyOfRange(serverSecretResp, 0, 16);
|
||||
byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, 272);
|
||||
byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, serverSecretResp.length);
|
||||
|
||||
// Ensure the authenticity of the data
|
||||
if (!verifySignature(serverSecret, serverSignature, serverCert)) {
|
||||
|
||||
@@ -1,19 +1,27 @@
|
||||
package com.limelight.nvstream.input;
|
||||
|
||||
public class ControllerPacket {
|
||||
public static final short A_FLAG = 0x1000;
|
||||
public static final short B_FLAG = 0x2000;
|
||||
public static final short X_FLAG = 0x4000;
|
||||
public static final short Y_FLAG = (short)0x8000;
|
||||
public static final short UP_FLAG = 0x0001;
|
||||
public static final short DOWN_FLAG = 0x0002;
|
||||
public static final short LEFT_FLAG = 0x0004;
|
||||
public static final short RIGHT_FLAG = 0x0008;
|
||||
public static final short LB_FLAG = 0x0100;
|
||||
public static final short RB_FLAG = 0x0200;
|
||||
public static final short PLAY_FLAG = 0x0010;
|
||||
public static final short BACK_FLAG = 0x0020;
|
||||
public static final short LS_CLK_FLAG = 0x0040;
|
||||
public static final short RS_CLK_FLAG = 0x0080;
|
||||
public static final short SPECIAL_BUTTON_FLAG = 0x0400;
|
||||
public static final int A_FLAG = 0x1000;
|
||||
public static final int B_FLAG = 0x2000;
|
||||
public static final int X_FLAG = 0x4000;
|
||||
public static final int Y_FLAG = 0x8000;
|
||||
public static final int UP_FLAG = 0x0001;
|
||||
public static final int DOWN_FLAG = 0x0002;
|
||||
public static final int LEFT_FLAG = 0x0004;
|
||||
public static final int RIGHT_FLAG = 0x0008;
|
||||
public static final int LB_FLAG = 0x0100;
|
||||
public static final int RB_FLAG = 0x0200;
|
||||
public static final int PLAY_FLAG = 0x0010;
|
||||
public static final int BACK_FLAG = 0x0020;
|
||||
public static final int LS_CLK_FLAG = 0x0040;
|
||||
public static final int RS_CLK_FLAG = 0x0080;
|
||||
public static final int SPECIAL_BUTTON_FLAG = 0x0400;
|
||||
|
||||
// Extended buttons (Sunshine only)
|
||||
public static final int PADDLE1_FLAG = 0x010000;
|
||||
public static final int PADDLE2_FLAG = 0x020000;
|
||||
public static final int PADDLE3_FLAG = 0x040000;
|
||||
public static final int PADDLE4_FLAG = 0x080000;
|
||||
public static final int TOUCHPAD_FLAG = 0x100000; // Touchpad buttons on Sony controllers
|
||||
public static final int MISC_FLAG = 0x200000; // Share/Mic/Capture/Mute buttons on various controllers
|
||||
}
|
||||
@@ -7,4 +7,5 @@ public class KeyboardPacket {
|
||||
public static final byte MODIFIER_SHIFT = 0x01;
|
||||
public static final byte MODIFIER_CTRL = 0x02;
|
||||
public static final byte MODIFIER_ALT = 0x04;
|
||||
}
|
||||
public static final byte MODIFIER_META = 0x08;
|
||||
}
|
||||
@@ -14,13 +14,13 @@ public class MoonBridge {
|
||||
public static final int VIDEO_FORMAT_H264 = 0x0001;
|
||||
public static final int VIDEO_FORMAT_H265 = 0x0100;
|
||||
public static final int VIDEO_FORMAT_H265_MAIN10 = 0x0200;
|
||||
public static final int VIDEO_FORMAT_AV1_MAIN8 = 0x1000;
|
||||
public static final int VIDEO_FORMAT_AV1_MAIN10 = 0x2000;
|
||||
|
||||
public static final int VIDEO_FORMAT_MASK_H264 = 0x00FF;
|
||||
public static final int VIDEO_FORMAT_MASK_H265 = 0xFF00;
|
||||
|
||||
public static final int ENCFLG_NONE = 0;
|
||||
public static final int ENCFLG_AUDIO = 1;
|
||||
public static final int ENCFLG_ALL = 0xFFFFFFFF;
|
||||
public static final int VIDEO_FORMAT_MASK_H264 = 0x000F;
|
||||
public static final int VIDEO_FORMAT_MASK_H265 = 0x0F00;
|
||||
public static final int VIDEO_FORMAT_MASK_AV1 = 0xF000;
|
||||
public static final int VIDEO_FORMAT_MASK_10BIT = 0x2200;
|
||||
|
||||
public static final int BUFFER_TYPE_PICDATA = 0;
|
||||
public static final int BUFFER_TYPE_SPS = 1;
|
||||
@@ -40,6 +40,7 @@ public class MoonBridge {
|
||||
public static final int CAPABILITY_DIRECT_SUBMIT = 1;
|
||||
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC = 2;
|
||||
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_HEVC = 4;
|
||||
public static final int CAPABILITY_REFERENCE_FRAME_INVALIDATION_AV1 = 0x40;
|
||||
|
||||
public static final int DR_OK = 0;
|
||||
public static final int DR_NEED_IDR = -1;
|
||||
@@ -73,6 +74,58 @@ public class MoonBridge {
|
||||
|
||||
public static final int ML_TEST_RESULT_INCONCLUSIVE = 0xFFFFFFFF;
|
||||
|
||||
public static final byte SS_KBE_FLAG_NON_NORMALIZED = 0x01;
|
||||
|
||||
public static final int LI_ERR_UNSUPPORTED = -5501;
|
||||
|
||||
public static final byte LI_TOUCH_EVENT_HOVER = 0x00;
|
||||
public static final byte LI_TOUCH_EVENT_DOWN = 0x01;
|
||||
public static final byte LI_TOUCH_EVENT_UP = 0x02;
|
||||
public static final byte LI_TOUCH_EVENT_MOVE = 0x03;
|
||||
public static final byte LI_TOUCH_EVENT_CANCEL = 0x04;
|
||||
public static final byte LI_TOUCH_EVENT_BUTTON_ONLY = 0x05;
|
||||
public static final byte LI_TOUCH_EVENT_HOVER_LEAVE = 0x06;
|
||||
public static final byte LI_TOUCH_EVENT_CANCEL_ALL = 0x07;
|
||||
|
||||
public static final byte LI_TOOL_TYPE_UNKNOWN = 0x00;
|
||||
public static final byte LI_TOOL_TYPE_PEN = 0x01;
|
||||
public static final byte LI_TOOL_TYPE_ERASER = 0x02;
|
||||
|
||||
public static final byte LI_PEN_BUTTON_PRIMARY = 0x01;
|
||||
public static final byte LI_PEN_BUTTON_SECONDARY = 0x02;
|
||||
public static final byte LI_PEN_BUTTON_TERTIARY = 0x04;
|
||||
|
||||
public static final byte LI_TILT_UNKNOWN = (byte)0xFF;
|
||||
public static final short LI_ROT_UNKNOWN = (short)0xFFFF;
|
||||
|
||||
public static final byte LI_CTYPE_UNKNOWN = 0x00;
|
||||
public static final byte LI_CTYPE_XBOX = 0x01;
|
||||
public static final byte LI_CTYPE_PS = 0x02;
|
||||
public static final byte LI_CTYPE_NINTENDO = 0x03;
|
||||
public static final byte LI_CTYPE_STEAM = 0x04;
|
||||
|
||||
public static final short LI_CCAP_ANALOG_TRIGGERS = 0x01;
|
||||
public static final short LI_CCAP_RUMBLE = 0x02;
|
||||
public static final short LI_CCAP_TRIGGER_RUMBLE = 0x04;
|
||||
public static final short LI_CCAP_TOUCHPAD = 0x08;
|
||||
public static final short LI_CCAP_ACCEL = 0x10;
|
||||
public static final short LI_CCAP_GYRO = 0x20;
|
||||
public static final short LI_CCAP_BATTERY_STATE = 0x40;
|
||||
public static final short LI_CCAP_RGB_LED = 0x80;
|
||||
public static final short LI_CCAP_DUAL_TOUCHPAD = 0x100;
|
||||
|
||||
public static final byte LI_MOTION_TYPE_ACCEL = 0x01;
|
||||
public static final byte LI_MOTION_TYPE_GYRO = 0x02;
|
||||
|
||||
public static final byte LI_BATTERY_STATE_UNKNOWN = 0x00;
|
||||
public static final byte LI_BATTERY_STATE_NOT_PRESENT = 0x01;
|
||||
public static final byte LI_BATTERY_STATE_DISCHARGING = 0x02;
|
||||
public static final byte LI_BATTERY_STATE_CHARGING = 0x03;
|
||||
public static final byte LI_BATTERY_STATE_NOT_CHARGING = 0x04; // Connected to power but not charging
|
||||
public static final byte LI_BATTERY_STATE_FULL = 0x05;
|
||||
|
||||
public static final byte LI_BATTERY_PERCENTAGE_UNKNOWN = (byte)0xFF;
|
||||
|
||||
private static AudioRenderer audioRenderer;
|
||||
private static VideoDecoderRenderer videoRenderer;
|
||||
private static NvConnectionListener connectionListener;
|
||||
@@ -165,11 +218,11 @@ public class MoonBridge {
|
||||
}
|
||||
|
||||
public static int bridgeDrSubmitDecodeUnit(byte[] decodeUnitData, int decodeUnitLength, int decodeUnitType,
|
||||
int frameNumber, int frameType,
|
||||
long receiveTimeMs, long enqueueTimeMs) {
|
||||
int frameNumber, int frameType, char frameHostProcessingLatency,
|
||||
long receiveTimeUs, long enqueueTimeUs) {
|
||||
if (videoRenderer != null) {
|
||||
return videoRenderer.submitDecodeUnit(decodeUnitData, decodeUnitLength,
|
||||
decodeUnitType, frameNumber, frameType, receiveTimeMs, enqueueTimeMs);
|
||||
decodeUnitType, frameNumber, frameType, frameHostProcessingLatency, receiveTimeUs, enqueueTimeUs);
|
||||
}
|
||||
else {
|
||||
return DR_OK;
|
||||
@@ -251,9 +304,27 @@ public class MoonBridge {
|
||||
}
|
||||
}
|
||||
|
||||
public static void bridgeClSetHdrMode(boolean enabled) {
|
||||
public static void bridgeClSetHdrMode(boolean enabled, byte[] hdrMetadata) {
|
||||
if (connectionListener != null) {
|
||||
connectionListener.setHdrMode(enabled);
|
||||
connectionListener.setHdrMode(enabled, hdrMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bridgeClRumbleTriggers(short controllerNumber, short leftTrigger, short rightTrigger) {
|
||||
if (connectionListener != null) {
|
||||
connectionListener.rumbleTriggers(controllerNumber, leftTrigger, rightTrigger);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bridgeClSetMotionEventState(short controllerNumber, byte eventType, short sampleRateHz) {
|
||||
if (connectionListener != null) {
|
||||
connectionListener.setMotionEventState(controllerNumber, eventType, sampleRateHz);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bridgeClSetControllerLED(short controllerNumber, byte r, byte g, byte b) {
|
||||
if (connectionListener != null) {
|
||||
connectionListener.setControllerLED(controllerNumber, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,14 +341,11 @@ public class MoonBridge {
|
||||
}
|
||||
|
||||
public static native int startConnection(String address, String appVersion, String gfeVersion,
|
||||
String rtspSessionUrl,
|
||||
String rtspSessionUrl, int serverCodecModeSupport,
|
||||
int width, int height, int fps,
|
||||
int bitrate, int packetSize, int streamingRemotely,
|
||||
int audioConfiguration, boolean supportsHevc,
|
||||
boolean enableHdr,
|
||||
int hevcBitratePercentageMultiplier,
|
||||
int audioConfiguration, int supportedVideoFormats,
|
||||
int clientRefreshRateX100,
|
||||
int encryptionFlags,
|
||||
byte[] riAesKey, byte[] riAesIv,
|
||||
int videoCapabilities,
|
||||
int colorSpace, int colorRange);
|
||||
@@ -295,22 +363,32 @@ public class MoonBridge {
|
||||
public static native void sendMouseButton(byte buttonEvent, byte mouseButton);
|
||||
|
||||
public static native void sendMultiControllerInput(short controllerNumber,
|
||||
short activeGamepadMask, short buttonFlags,
|
||||
short activeGamepadMask, int buttonFlags,
|
||||
byte leftTrigger, byte rightTrigger,
|
||||
short leftStickX, short leftStickY,
|
||||
short rightStickX, short rightStickY);
|
||||
|
||||
public static native void sendControllerInput(short buttonFlags,
|
||||
byte leftTrigger, byte rightTrigger,
|
||||
short leftStickX, short leftStickY,
|
||||
short rightStickX, short rightStickY);
|
||||
public static native int sendTouchEvent(byte eventType, int pointerId, float x, float y, float pressure,
|
||||
float contactAreaMajor, float contactAreaMinor, short rotation);
|
||||
|
||||
public static native void sendKeyboardInput(short keyMap, byte keyDirection, byte modifier);
|
||||
public static native int sendPenEvent(byte eventType, byte toolType, byte penButtons, float x, float y,
|
||||
float pressure, float contactAreaMajor, float contactAreaMinor,
|
||||
short rotation, byte tilt);
|
||||
|
||||
public static native void sendMouseScroll(byte scrollClicks);
|
||||
public static native int sendControllerArrivalEvent(byte controllerNumber, short activeGamepadMask, byte type, int supportedButtonFlags, short capabilities);
|
||||
|
||||
public static native int sendControllerTouchEvent(byte controllerNumber, byte eventType, int pointerId, float x, float y, float pressure);
|
||||
|
||||
public static native int sendControllerMotionEvent(byte controllerNumber, byte motionType, float x, float y, float z);
|
||||
|
||||
public static native int sendControllerBatteryEvent(byte controllerNumber, byte batteryState, byte batteryPercentage);
|
||||
|
||||
public static native void sendKeyboardInput(short keyMap, byte keyDirection, byte modifier, byte flags);
|
||||
|
||||
public static native void sendMouseHighResScroll(short scrollAmount);
|
||||
|
||||
public static native void sendMouseHighResHScroll(short scrollAmount);
|
||||
|
||||
public static native void sendUtf8Text(String text);
|
||||
|
||||
public static native String getStageName(int stage);
|
||||
@@ -332,5 +410,13 @@ public class MoonBridge {
|
||||
// The RTT is in the top 32 bits, and the RTT variance is in the bottom 32 bits
|
||||
public static native long getEstimatedRttInfo();
|
||||
|
||||
public static native String getLaunchUrlQueryParameters();
|
||||
|
||||
public static native byte guessControllerType(int vendorId, int productId);
|
||||
|
||||
public static native boolean guessControllerHasPaddles(int vendorId, int productId);
|
||||
|
||||
public static native boolean guessControllerHasShareButton(int vendorId, int productId);
|
||||
|
||||
public static native void init();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
package com.limelight.nvstream.mdns;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.jmdns.JmmDNS;
|
||||
import javax.jmdns.NetworkTopologyDiscovery;
|
||||
import javax.jmdns.ServiceEvent;
|
||||
import javax.jmdns.ServiceInfo;
|
||||
import javax.jmdns.ServiceListener;
|
||||
import javax.jmdns.impl.NetworkTopologyDiscoveryImpl;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
|
||||
public class JmDNSDiscoveryAgent extends MdnsDiscoveryAgent implements ServiceListener {
|
||||
private static final String SERVICE_TYPE = "_nvstream._tcp.local.";
|
||||
private WifiManager.MulticastLock multicastLock;
|
||||
private Thread discoveryThread;
|
||||
private HashSet<String> pendingResolution = new HashSet<>();
|
||||
|
||||
// The resolver factory's instance member has a static lifetime which
|
||||
// means our ref count and listener must be static also.
|
||||
private static int resolverRefCount = 0;
|
||||
private static HashSet<ServiceListener> listeners = new HashSet<>();
|
||||
private static ServiceListener nvstreamListener = new ServiceListener() {
|
||||
@Override
|
||||
public void serviceAdded(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceAdded(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceRemoved(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceRemoved(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceResolved(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceResolved(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static class MyNetworkTopologyDiscovery extends NetworkTopologyDiscoveryImpl {
|
||||
@Override
|
||||
public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress) {
|
||||
// This is an copy of jmDNS's implementation, except we omit the multicast check, since
|
||||
// it seems at least some devices lie about interfaces not supporting multicast when they really do.
|
||||
try {
|
||||
if (!networkInterface.isUp()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!networkInterface.supportsMulticast()) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (networkInterface.isLoopback()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
// Override jmDNS's default topology discovery class with ours
|
||||
NetworkTopologyDiscovery.Factory.setClassDelegate(new NetworkTopologyDiscovery.Factory.ClassDelegate() {
|
||||
@Override
|
||||
public NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
|
||||
return new MyNetworkTopologyDiscovery();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static JmmDNS referenceResolver() {
|
||||
synchronized (JmDNSDiscoveryAgent.class) {
|
||||
JmmDNS instance = JmmDNS.Factory.getInstance();
|
||||
if (++resolverRefCount == 1) {
|
||||
// This will cause the listener to be invoked for known hosts immediately.
|
||||
// JmDNS only supports one listener per service, so we have to do this here
|
||||
// with a static listener.
|
||||
instance.addServiceListener(SERVICE_TYPE, nvstreamListener);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static void dereferenceResolver() {
|
||||
synchronized (JmDNSDiscoveryAgent.class) {
|
||||
if (--resolverRefCount == 0) {
|
||||
try {
|
||||
JmmDNS.Factory.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JmDNSDiscoveryAgent(Context context, MdnsDiscoveryListener listener) {
|
||||
super(listener);
|
||||
|
||||
// Create the multicast lock required to receive mDNS traffic
|
||||
WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
|
||||
multicastLock = wifiMgr.createMulticastLock("Limelight mDNS");
|
||||
multicastLock.setReferenceCounted(false);
|
||||
}
|
||||
|
||||
private void handleResolvedServiceInfo(ServiceInfo info) {
|
||||
synchronized (pendingResolution) {
|
||||
pendingResolution.remove(info.getName());
|
||||
}
|
||||
|
||||
try {
|
||||
handleServiceInfo(info);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Invalid DNS response
|
||||
LimeLog.info("mDNS: Invalid response for machine: "+info.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleServiceInfo(ServiceInfo info) throws UnsupportedEncodingException {
|
||||
reportNewComputer(info.getName(), info.getPort(), info.getInet4Addresses(), info.getInet6Addresses());
|
||||
}
|
||||
|
||||
public void startDiscovery(final int discoveryIntervalMs) {
|
||||
// Kill any existing discovery before starting a new one
|
||||
stopDiscovery();
|
||||
|
||||
// Acquire the multicast lock to start receiving mDNS traffic
|
||||
multicastLock.acquire();
|
||||
|
||||
// Add our listener to the set
|
||||
synchronized (listeners) {
|
||||
listeners.add(JmDNSDiscoveryAgent.this);
|
||||
}
|
||||
|
||||
discoveryThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
// This may result in listener callbacks so we must register
|
||||
// our listener first.
|
||||
JmmDNS resolver = referenceResolver();
|
||||
|
||||
try {
|
||||
while (!Thread.interrupted()) {
|
||||
// Start an mDNS request
|
||||
resolver.requestServiceInfo(SERVICE_TYPE, null, discoveryIntervalMs);
|
||||
|
||||
// Run service resolution again for pending machines
|
||||
ArrayList<String> pendingNames;
|
||||
synchronized (pendingResolution) {
|
||||
pendingNames = new ArrayList<String>(pendingResolution);
|
||||
}
|
||||
for (String name : pendingNames) {
|
||||
LimeLog.info("mDNS: Retrying service resolution for machine: "+name);
|
||||
ServiceInfo[] infos = resolver.getServiceInfos(SERVICE_TYPE, name, 500);
|
||||
if (infos != null && infos.length != 0) {
|
||||
LimeLog.info("mDNS: Resolved (retry) with "+infos.length+" service entries");
|
||||
for (ServiceInfo svcinfo : infos) {
|
||||
handleResolvedServiceInfo(svcinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the next polling interval
|
||||
try {
|
||||
Thread.sleep(discoveryIntervalMs);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Dereference the resolver
|
||||
dereferenceResolver();
|
||||
}
|
||||
}
|
||||
};
|
||||
discoveryThread.setName("mDNS Discovery Thread");
|
||||
discoveryThread.start();
|
||||
}
|
||||
|
||||
public void stopDiscovery() {
|
||||
// Release the multicast lock to stop receiving mDNS traffic
|
||||
multicastLock.release();
|
||||
|
||||
// Remove our listener from the set
|
||||
synchronized (listeners) {
|
||||
listeners.remove(JmDNSDiscoveryAgent.this);
|
||||
}
|
||||
|
||||
// If there's already a running thread, interrupt it
|
||||
if (discoveryThread != null) {
|
||||
discoveryThread.interrupt();
|
||||
discoveryThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceAdded(ServiceEvent event) {
|
||||
LimeLog.info("mDNS: Machine appeared: "+event.getInfo().getName());
|
||||
|
||||
ServiceInfo info = event.getDNS().getServiceInfo(SERVICE_TYPE, event.getInfo().getName(), 500);
|
||||
if (info == null) {
|
||||
// This machine is pending resolution
|
||||
synchronized (pendingResolution) {
|
||||
pendingResolution.add(event.getInfo().getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LimeLog.info("mDNS: Resolved (blocking)");
|
||||
handleResolvedServiceInfo(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceRemoved(ServiceEvent event) {
|
||||
LimeLog.info("mDNS: Machine disappeared: "+event.getInfo().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceResolved(ServiceEvent event) {
|
||||
// We handle this synchronously
|
||||
}
|
||||
}
|
||||
@@ -1,166 +1,64 @@
|
||||
package com.limelight.nvstream.mdns;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.jmdns.JmmDNS;
|
||||
import javax.jmdns.NetworkTopologyDiscovery;
|
||||
import javax.jmdns.ServiceEvent;
|
||||
import javax.jmdns.ServiceInfo;
|
||||
import javax.jmdns.ServiceListener;
|
||||
import javax.jmdns.impl.NetworkTopologyDiscoveryImpl;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
|
||||
public class MdnsDiscoveryAgent implements ServiceListener {
|
||||
public static final String SERVICE_TYPE = "_nvstream._tcp.local.";
|
||||
|
||||
private MdnsDiscoveryListener listener;
|
||||
private Thread discoveryThread;
|
||||
private HashMap<InetAddress, MdnsComputer> computers = new HashMap<InetAddress, MdnsComputer>();
|
||||
private HashSet<String> pendingResolution = new HashSet<String>();
|
||||
|
||||
// The resolver factory's instance member has a static lifetime which
|
||||
// means our ref count and listener must be static also.
|
||||
private static int resolverRefCount = 0;
|
||||
private static HashSet<ServiceListener> listeners = new HashSet<ServiceListener>();
|
||||
private static ServiceListener nvstreamListener = new ServiceListener() {
|
||||
@Override
|
||||
public void serviceAdded(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceAdded(event);
|
||||
}
|
||||
}
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
@Override
|
||||
public void serviceRemoved(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceRemoved(event);
|
||||
}
|
||||
}
|
||||
public abstract class MdnsDiscoveryAgent {
|
||||
protected MdnsDiscoveryListener listener;
|
||||
|
||||
@Override
|
||||
public void serviceResolved(ServiceEvent event) {
|
||||
HashSet<ServiceListener> localListeners;
|
||||
|
||||
// Copy the listener set into a new set so we can invoke
|
||||
// the callbacks without holding the listeners monitor the
|
||||
// whole time.
|
||||
synchronized (listeners) {
|
||||
localListeners = new HashSet<ServiceListener>(listeners);
|
||||
}
|
||||
|
||||
for (ServiceListener listener : localListeners) {
|
||||
listener.serviceResolved(event);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public static class MyNetworkTopologyDiscovery extends NetworkTopologyDiscoveryImpl {
|
||||
@Override
|
||||
public boolean useInetAddress(NetworkInterface networkInterface, InetAddress interfaceAddress) {
|
||||
// This is an copy of jmDNS's implementation, except we omit the multicast check, since
|
||||
// it seems at least some devices lie about interfaces not supporting multicast when they really do.
|
||||
try {
|
||||
if (!networkInterface.isUp()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (!networkInterface.supportsMulticast()) {
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (networkInterface.isLoopback()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static {
|
||||
// Override jmDNS's default topology discovery class with ours
|
||||
NetworkTopologyDiscovery.Factory.setClassDelegate(new NetworkTopologyDiscovery.Factory.ClassDelegate() {
|
||||
@Override
|
||||
public NetworkTopologyDiscovery newNetworkTopologyDiscovery() {
|
||||
return new MyNetworkTopologyDiscovery();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static JmmDNS referenceResolver() {
|
||||
synchronized (MdnsDiscoveryAgent.class) {
|
||||
JmmDNS instance = JmmDNS.Factory.getInstance();
|
||||
if (++resolverRefCount == 1) {
|
||||
// This will cause the listener to be invoked for known hosts immediately.
|
||||
// JmDNS only supports one listener per service, so we have to do this here
|
||||
// with a static listener.
|
||||
instance.addServiceListener(SERVICE_TYPE, nvstreamListener);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static void dereferenceResolver() {
|
||||
synchronized (MdnsDiscoveryAgent.class) {
|
||||
if (--resolverRefCount == 0) {
|
||||
try {
|
||||
JmmDNS.Factory.close();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected HashSet<MdnsComputer> computers = new HashSet<>();
|
||||
|
||||
public MdnsDiscoveryAgent(MdnsDiscoveryListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void handleResolvedServiceInfo(ServiceInfo info) {
|
||||
synchronized (pendingResolution) {
|
||||
pendingResolution.remove(info.getName());
|
||||
public abstract void startDiscovery(final int discoveryIntervalMs);
|
||||
|
||||
public abstract void stopDiscovery();
|
||||
|
||||
protected void reportNewComputer(String name, int port, Inet4Address[] v4Addrs, Inet6Address[] v6Addrs) {
|
||||
LimeLog.info("mDNS: "+name+" has "+v4Addrs.length+" IPv4 addresses");
|
||||
LimeLog.info("mDNS: "+name+" has "+v6Addrs.length+" IPv6 addresses");
|
||||
|
||||
Inet6Address v6GlobalAddr = getBestIpv6Address(v6Addrs);
|
||||
|
||||
// Add a computer object for each IPv4 address reported by the PC
|
||||
for (Inet4Address v4Addr : v4Addrs) {
|
||||
synchronized (computers) {
|
||||
MdnsComputer computer = new MdnsComputer(name, v4Addr, v6GlobalAddr, port);
|
||||
if (computers.add(computer)) {
|
||||
// This was a new entry
|
||||
listener.notifyComputerAdded(computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
handleServiceInfo(info);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Invalid DNS response
|
||||
LimeLog.info("mDNS: Invalid response for machine: "+info.getName());
|
||||
return;
|
||||
// If there were no IPv4 addresses, use IPv6 for registration
|
||||
if (v4Addrs.length == 0) {
|
||||
Inet6Address v6LocalAddr = getLocalAddress(v6Addrs);
|
||||
|
||||
if (v6LocalAddr != null || v6GlobalAddr != null) {
|
||||
MdnsComputer computer = new MdnsComputer(name, v6LocalAddr, v6GlobalAddr, port);
|
||||
if (computers.add(computer)) {
|
||||
// This was a new entry
|
||||
listener.notifyComputerAdded(computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Inet6Address getLocalAddress(Inet6Address[] addresses) {
|
||||
public List<MdnsComputer> getComputerSet() {
|
||||
synchronized (computers) {
|
||||
return new ArrayList<>(computers);
|
||||
}
|
||||
}
|
||||
|
||||
protected static Inet6Address getLocalAddress(Inet6Address[] addresses) {
|
||||
for (Inet6Address addr : addresses) {
|
||||
if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) {
|
||||
return addr;
|
||||
@@ -174,7 +72,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Inet6Address getLinkLocalAddress(Inet6Address[] addresses) {
|
||||
protected static Inet6Address getLinkLocalAddress(Inet6Address[] addresses) {
|
||||
for (Inet6Address addr : addresses) {
|
||||
if (addr.isLinkLocalAddress()) {
|
||||
LimeLog.info("Found link-local address: "+addr.getHostAddress());
|
||||
@@ -185,7 +83,7 @@ public class MdnsDiscoveryAgent implements ServiceListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Inet6Address getBestIpv6Address(Inet6Address[] addresses) {
|
||||
protected static Inet6Address getBestIpv6Address(Inet6Address[] addresses) {
|
||||
// First try to find a link local address, so we can match the interface identifier
|
||||
// with a global address (this will work for SLAAC but not DHCPv6).
|
||||
Inet6Address linkLocalAddr = getLinkLocalAddress(addresses);
|
||||
@@ -247,162 +145,4 @@ public class MdnsDiscoveryAgent implements ServiceListener {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void handleServiceInfo(ServiceInfo info) throws UnsupportedEncodingException {
|
||||
Inet4Address v4Addrs[] = info.getInet4Addresses();
|
||||
Inet6Address v6Addrs[] = info.getInet6Addresses();
|
||||
|
||||
LimeLog.info("mDNS: "+info.getName()+" has "+v4Addrs.length+" IPv4 addresses");
|
||||
LimeLog.info("mDNS: "+info.getName()+" has "+v6Addrs.length+" IPv6 addresses");
|
||||
|
||||
Inet6Address v6GlobalAddr = getBestIpv6Address(v6Addrs);
|
||||
|
||||
// Add a computer object for each IPv4 address reported by the PC
|
||||
for (Inet4Address v4Addr : v4Addrs) {
|
||||
synchronized (computers) {
|
||||
MdnsComputer computer = new MdnsComputer(info.getName(), v4Addr, v6GlobalAddr, info.getPort());
|
||||
if (computers.put(computer.getLocalAddress(), computer) == null) {
|
||||
// This was a new entry
|
||||
listener.notifyComputerAdded(computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there were no IPv4 addresses, use IPv6 for registration
|
||||
if (v4Addrs.length == 0) {
|
||||
Inet6Address v6LocalAddr = getLocalAddress(v6Addrs);
|
||||
|
||||
if (v6LocalAddr != null || v6GlobalAddr != null) {
|
||||
MdnsComputer computer = new MdnsComputer(info.getName(), v6LocalAddr, v6GlobalAddr, info.getPort());
|
||||
if (computers.put(v6LocalAddr != null ?
|
||||
computer.getLocalAddress() : computer.getIpv6Address(), computer) == null) {
|
||||
// This was a new entry
|
||||
listener.notifyComputerAdded(computer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startDiscovery(final int discoveryIntervalMs) {
|
||||
// Kill any existing discovery before starting a new one
|
||||
stopDiscovery();
|
||||
|
||||
// Add our listener to the set
|
||||
synchronized (listeners) {
|
||||
listeners.add(MdnsDiscoveryAgent.this);
|
||||
}
|
||||
|
||||
discoveryThread = new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
// This may result in listener callbacks so we must register
|
||||
// our listener first.
|
||||
JmmDNS resolver = referenceResolver();
|
||||
|
||||
try {
|
||||
while (!Thread.interrupted()) {
|
||||
// Start an mDNS request
|
||||
resolver.requestServiceInfo(SERVICE_TYPE, null, discoveryIntervalMs);
|
||||
|
||||
// Run service resolution again for pending machines
|
||||
ArrayList<String> pendingNames;
|
||||
synchronized (pendingResolution) {
|
||||
pendingNames = new ArrayList<String>(pendingResolution);
|
||||
}
|
||||
for (String name : pendingNames) {
|
||||
LimeLog.info("mDNS: Retrying service resolution for machine: "+name);
|
||||
ServiceInfo[] infos = resolver.getServiceInfos(SERVICE_TYPE, name, 500);
|
||||
if (infos != null && infos.length != 0) {
|
||||
LimeLog.info("mDNS: Resolved (retry) with "+infos.length+" service entries");
|
||||
for (ServiceInfo svcinfo : infos) {
|
||||
handleResolvedServiceInfo(svcinfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the next polling interval
|
||||
try {
|
||||
Thread.sleep(discoveryIntervalMs);
|
||||
} catch (InterruptedException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Dereference the resolver
|
||||
dereferenceResolver();
|
||||
}
|
||||
}
|
||||
};
|
||||
discoveryThread.setName("mDNS Discovery Thread");
|
||||
discoveryThread.start();
|
||||
}
|
||||
|
||||
public void stopDiscovery() {
|
||||
// Remove our listener from the set
|
||||
synchronized (listeners) {
|
||||
listeners.remove(MdnsDiscoveryAgent.this);
|
||||
}
|
||||
|
||||
// If there's already a running thread, interrupt it
|
||||
if (discoveryThread != null) {
|
||||
discoveryThread.interrupt();
|
||||
discoveryThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MdnsComputer> getComputerSet() {
|
||||
synchronized (computers) {
|
||||
return new ArrayList<MdnsComputer>(computers.values());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceAdded(ServiceEvent event) {
|
||||
LimeLog.info("mDNS: Machine appeared: "+event.getInfo().getName());
|
||||
|
||||
ServiceInfo info = event.getDNS().getServiceInfo(SERVICE_TYPE, event.getInfo().getName(), 500);
|
||||
if (info == null) {
|
||||
// This machine is pending resolution
|
||||
synchronized (pendingResolution) {
|
||||
pendingResolution.add(event.getInfo().getName());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LimeLog.info("mDNS: Resolved (blocking)");
|
||||
handleResolvedServiceInfo(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceRemoved(ServiceEvent event) {
|
||||
LimeLog.info("mDNS: Machine disappeared: "+event.getInfo().getName());
|
||||
|
||||
Inet4Address v4Addrs[] = event.getInfo().getInet4Addresses();
|
||||
for (Inet4Address addr : v4Addrs) {
|
||||
synchronized (computers) {
|
||||
MdnsComputer computer = computers.remove(addr);
|
||||
if (computer != null) {
|
||||
listener.notifyComputerRemoved(computer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Inet6Address v6Addrs[] = event.getInfo().getInet6Addresses();
|
||||
for (Inet6Address addr : v6Addrs) {
|
||||
synchronized (computers) {
|
||||
MdnsComputer computer = computers.remove(addr);
|
||||
if (computer != null) {
|
||||
listener.notifyComputerRemoved(computer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceResolved(ServiceEvent event) {
|
||||
// We handle this synchronously
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,5 @@ package com.limelight.nvstream.mdns;
|
||||
|
||||
public interface MdnsDiscoveryListener {
|
||||
void notifyComputerAdded(MdnsComputer computer);
|
||||
void notifyComputerRemoved(MdnsComputer computer);
|
||||
void notifyDiscoveryFailure(Exception e);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
package com.limelight.nvstream.mdns;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.net.nsd.NsdManager;
|
||||
import android.net.nsd.NsdServiceInfo;
|
||||
import android.os.Build;
|
||||
|
||||
import com.limelight.LimeLog;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
|
||||
public class NsdManagerDiscoveryAgent extends MdnsDiscoveryAgent {
|
||||
private static final String SERVICE_TYPE = "_nvstream._tcp";
|
||||
private final NsdManager nsdManager;
|
||||
private final Object listenerLock = new Object();
|
||||
private NsdManager.DiscoveryListener pendingListener;
|
||||
private NsdManager.DiscoveryListener activeListener;
|
||||
private final HashMap<String, NsdManager.ServiceInfoCallback> serviceCallbacks = new HashMap<>();
|
||||
private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
|
||||
|
||||
private NsdManager.DiscoveryListener createDiscoveryListener() {
|
||||
return new NsdManager.DiscoveryListener() {
|
||||
@Override
|
||||
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
|
||||
LimeLog.severe("NSD: Service discovery start failed: " + errorCode);
|
||||
|
||||
// This listener is no longer pending after this failure
|
||||
synchronized (listenerLock) {
|
||||
if (pendingListener != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
pendingListener = null;
|
||||
}
|
||||
|
||||
listener.notifyDiscoveryFailure(new RuntimeException("onStartDiscoveryFailed(): " + errorCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
|
||||
LimeLog.severe("NSD: Service discovery stop failed: " + errorCode);
|
||||
|
||||
// This listener is no longer active after this failure
|
||||
synchronized (listenerLock) {
|
||||
if (activeListener != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiscoveryStarted(String serviceType) {
|
||||
LimeLog.info("NSD: Service discovery started");
|
||||
|
||||
synchronized (listenerLock) {
|
||||
if (pendingListener != this) {
|
||||
// If we registered another discovery listener in the meantime, stop this one
|
||||
nsdManager.stopServiceDiscovery(this);
|
||||
return;
|
||||
}
|
||||
|
||||
pendingListener = null;
|
||||
activeListener = this;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiscoveryStopped(String serviceType) {
|
||||
LimeLog.info("NSD: Service discovery stopped");
|
||||
|
||||
synchronized (listenerLock) {
|
||||
if (activeListener != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
activeListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
|
||||
// Protect against racing stopDiscovery() call
|
||||
synchronized (listenerLock) {
|
||||
// Ignore callbacks if we're not the active listener
|
||||
if (activeListener != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
LimeLog.info("NSD: Machine appeared: " + nsdServiceInfo.getServiceName());
|
||||
|
||||
NsdManager.ServiceInfoCallback serviceInfoCallback = new NsdManager.ServiceInfoCallback() {
|
||||
@Override
|
||||
public void onServiceInfoCallbackRegistrationFailed(int errorCode) {
|
||||
LimeLog.severe("NSD: Service info callback registration failed: " + errorCode);
|
||||
listener.notifyDiscoveryFailure(new RuntimeException("onServiceInfoCallbackRegistrationFailed(): " + errorCode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceUpdated(NsdServiceInfo nsdServiceInfo) {
|
||||
LimeLog.info("NSD: Machine resolved: " + nsdServiceInfo.getServiceName());
|
||||
reportNewComputer(nsdServiceInfo.getServiceName(), nsdServiceInfo.getPort(),
|
||||
getV4Addrs(nsdServiceInfo.getHostAddresses()),
|
||||
getV6Addrs(nsdServiceInfo.getHostAddresses()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceLost() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceInfoCallbackUnregistered() {
|
||||
}
|
||||
};
|
||||
|
||||
nsdManager.registerServiceInfoCallback(nsdServiceInfo, executor, serviceInfoCallback);
|
||||
serviceCallbacks.put(nsdServiceInfo.getServiceName(), serviceInfoCallback);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
|
||||
// Protect against racing stopDiscovery() call
|
||||
synchronized (listenerLock) {
|
||||
// Ignore callbacks if we're not the active listener
|
||||
if (activeListener != this) {
|
||||
return;
|
||||
}
|
||||
|
||||
LimeLog.info("NSD: Machine lost: " + nsdServiceInfo.getServiceName());
|
||||
|
||||
NsdManager.ServiceInfoCallback serviceInfoCallback = serviceCallbacks.remove(nsdServiceInfo.getServiceName());
|
||||
if (serviceInfoCallback != null) {
|
||||
nsdManager.unregisterServiceInfoCallback(serviceInfoCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public NsdManagerDiscoveryAgent(Context context, MdnsDiscoveryListener listener) {
|
||||
super(listener);
|
||||
this.nsdManager = context.getSystemService(NsdManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDiscovery(int discoveryIntervalMs) {
|
||||
synchronized (listenerLock) {
|
||||
// Register a new service discovery listener if there's not already one starting or running
|
||||
if (pendingListener == null && activeListener == null) {
|
||||
pendingListener = createDiscoveryListener();
|
||||
nsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, pendingListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopDiscovery() {
|
||||
// Protect against racing ServiceInfoCallback and DiscoveryListener callbacks
|
||||
synchronized (listenerLock) {
|
||||
// Clear any pending listener to ensure the discoverStarted() callback
|
||||
// will realize it's gone and stop itself.
|
||||
pendingListener = null;
|
||||
|
||||
// Unregister the service discovery listener
|
||||
if (activeListener != null) {
|
||||
nsdManager.stopServiceDiscovery(activeListener);
|
||||
|
||||
// Even though listener stoppage is asynchronous, the listener is gone as far as
|
||||
// we're concerned. We null this right now to ensure pending callbacks know it's
|
||||
// stopped and startDiscovery() can immediately create a new listener. If we left
|
||||
// it until onDiscoveryStopped() was called, startDiscovery() would get confused
|
||||
// and assume a listener was already running, even though it's stopping.
|
||||
activeListener = null;
|
||||
}
|
||||
|
||||
// Unregister all service info callbacks
|
||||
for (NsdManager.ServiceInfoCallback callback : serviceCallbacks.values()) {
|
||||
nsdManager.unregisterServiceInfoCallback(callback);
|
||||
}
|
||||
serviceCallbacks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static Inet4Address[] getV4Addrs(List<InetAddress> addrs) {
|
||||
int matchCount = 0;
|
||||
for (InetAddress addr : addrs) {
|
||||
if (addr instanceof Inet4Address) {
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Inet4Address[] matching = new Inet4Address[matchCount];
|
||||
|
||||
int i = 0;
|
||||
for (InetAddress addr : addrs) {
|
||||
if (addr instanceof Inet4Address) {
|
||||
matching[i++] = (Inet4Address) addr;
|
||||
}
|
||||
}
|
||||
|
||||
return matching;
|
||||
}
|
||||
|
||||
private static Inet6Address[] getV6Addrs(List<InetAddress> addrs) {
|
||||
int matchCount = 0;
|
||||
for (InetAddress addr : addrs) {
|
||||
if (addr instanceof Inet6Address) {
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Inet6Address[] matching = new Inet6Address[matchCount];
|
||||
|
||||
int i = 0;
|
||||
for (InetAddress addr : addrs) {
|
||||
if (addr instanceof Inet6Address) {
|
||||
matching[i++] = (Inet6Address) addr;
|
||||
}
|
||||
}
|
||||
|
||||
return matching;
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,21 @@ public class WakeOnLanSender {
|
||||
|
||||
try {
|
||||
sendPacketsForAddress(InetAddress.getByName("255.255.255.255"), address.port, sock, payload);
|
||||
sentWolPacket = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
lastException = e;
|
||||
}
|
||||
|
||||
try {
|
||||
for (InetAddress resolvedAddress : InetAddress.getAllByName(address.address)) {
|
||||
sendPacketsForAddress(resolvedAddress, address.port, sock, payload);
|
||||
try {
|
||||
sendPacketsForAddress(resolvedAddress, address.port, sock, payload);
|
||||
sentWolPacket = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
lastException = e;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// We may have addresses that don't resolve on this subnet,
|
||||
|
||||
@@ -98,8 +98,31 @@ public class AddComputerManually extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private URI parseRawUserInputToUri(String rawUserInput) {
|
||||
try {
|
||||
// Try adding a scheme and parsing the remaining input.
|
||||
// This handles input like 127.0.0.1:47989, [::1], [::1]:47989, and 127.0.0.1.
|
||||
URI uri = new URI("moonlight://" + rawUserInput);
|
||||
if (uri.getHost() != null && !uri.getHost().isEmpty()) {
|
||||
return uri;
|
||||
}
|
||||
} catch (URISyntaxException ignored) {}
|
||||
|
||||
try {
|
||||
// Attempt to escape the input as an IPv6 literal.
|
||||
// This handles input like ::1.
|
||||
URI uri = new URI("moonlight://[" + rawUserInput + "]");
|
||||
if (uri.getHost() != null && !uri.getHost().isEmpty()) {
|
||||
return uri;
|
||||
}
|
||||
} catch (URISyntaxException ignored) {}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void doAddPc(String rawUserInput) throws InterruptedException {
|
||||
boolean wrongSiteLocal = false;
|
||||
boolean invalidInput = false;
|
||||
boolean success;
|
||||
int portTestResult;
|
||||
|
||||
@@ -109,26 +132,26 @@ public class AddComputerManually extends Activity {
|
||||
try {
|
||||
ComputerDetails details = new ComputerDetails();
|
||||
|
||||
// Use URI-style parsing for the host address input
|
||||
URI uri = new URI("moonlight://" + rawUserInput);
|
||||
// Check if we parsed a host address successfully
|
||||
URI uri = parseRawUserInputToUri(rawUserInput);
|
||||
if (uri != null && uri.getHost() != null && !uri.getHost().isEmpty()) {
|
||||
String host = uri.getHost();
|
||||
int port = uri.getPort();
|
||||
|
||||
String host = uri.getHost();
|
||||
int port = uri.getPort();
|
||||
// If a port was not specified, use the default
|
||||
if (port == -1) {
|
||||
port = NvHTTP.DEFAULT_HTTP_PORT;
|
||||
}
|
||||
|
||||
// URI allows empty hosts, but we don't want that
|
||||
if (host == null || host.isEmpty()) {
|
||||
throw new URISyntaxException(rawUserInput, "Host failed to parse");
|
||||
}
|
||||
|
||||
// If a port was not specified, use the default
|
||||
if (port == -1) {
|
||||
port = NvHTTP.DEFAULT_HTTP_PORT;
|
||||
}
|
||||
|
||||
details.manualAddress = new ComputerDetails.AddressTuple(host, port);
|
||||
success = managerBinder.addComputerBlocking(details);
|
||||
if (!success){
|
||||
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
|
||||
details.manualAddress = new ComputerDetails.AddressTuple(host, port);
|
||||
success = managerBinder.addComputerBlocking(details);
|
||||
if (!success){
|
||||
wrongSiteLocal = isWrongSubnetSiteLocalAddress(host);
|
||||
}
|
||||
} else {
|
||||
// Invalid user input
|
||||
success = false;
|
||||
invalidInput = true;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Propagate the InterruptedException to the caller for proper handling
|
||||
@@ -139,13 +162,11 @@ public class AddComputerManually extends Activity {
|
||||
// https://github.com/square/okhttp/blob/okhttp_27/okhttp/src/main/java/com/squareup/okhttp/HttpUrl.java#L705
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
success = false;
|
||||
invalidInput = true;
|
||||
}
|
||||
|
||||
// Keep the SpinnerDialog open while testing connectivity
|
||||
if (!success && !wrongSiteLocal) {
|
||||
if (!success && !wrongSiteLocal && !invalidInput) {
|
||||
// Run the test before dismissing the spinner because it can take a few seconds.
|
||||
portTestResult = MoonBridge.testClientConnectivity(ServerHelper.CONNECTION_TEST_SERVER, 443,
|
||||
MoonBridge.ML_PORT_FLAG_TCP_47984 | MoonBridge.ML_PORT_FLAG_TCP_47989);
|
||||
@@ -156,7 +177,10 @@ public class AddComputerManually extends Activity {
|
||||
|
||||
dialog.dismiss();
|
||||
|
||||
if (wrongSiteLocal) {
|
||||
if (invalidInput) {
|
||||
Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title), getResources().getString(R.string.addpc_unknown_host), false);
|
||||
}
|
||||
else if (wrongSiteLocal) {
|
||||
Dialog.displayDialog(this, getResources().getString(R.string.conn_error_title), getResources().getString(R.string.addpc_wrong_sitelocal), false);
|
||||
}
|
||||
else if (!success) {
|
||||
|
||||
@@ -13,7 +13,6 @@ import com.limelight.R;
|
||||
import static com.limelight.binding.input.virtual_controller.VirtualControllerConfigurationLoader.OSC_PREFERENCE;
|
||||
|
||||
public class ConfirmDeleteOscPreference extends DialogPreference {
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public ConfirmDeleteOscPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
@@ -26,7 +25,6 @@ public class ConfirmDeleteOscPreference extends DialogPreference {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public ConfirmDeleteOscPreference(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@@ -11,12 +11,10 @@ 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);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,19 @@ import android.view.Display;
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
|
||||
public class PreferenceConfiguration {
|
||||
public enum FormatOption {
|
||||
AUTO,
|
||||
FORCE_AV1,
|
||||
FORCE_HEVC,
|
||||
FORCE_H264,
|
||||
};
|
||||
|
||||
public enum AnalogStickForScrolling {
|
||||
NONE,
|
||||
RIGHT,
|
||||
LEFT
|
||||
}
|
||||
|
||||
private static final String LEGACY_RES_FPS_PREF_STRING = "list_resolution_fps";
|
||||
private static final String LEGACY_ENABLE_51_SURROUND_PREF_STRING = "checkbox_51_surround";
|
||||
|
||||
@@ -31,16 +44,19 @@ 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 SHOW_GUIDE_BUTTON_PREF_STRING = "checkbox_show_guide_button";
|
||||
private static final String LEGACY_DISABLE_FRAME_DROP_PREF_STRING = "checkbox_disable_frame_drop";
|
||||
private static final String 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";
|
||||
private static final String BIND_ALL_USB_STRING = "checkbox_usb_bind_all";
|
||||
private static final String MOUSE_EMULATION_STRING = "checkbox_mouse_emulation";
|
||||
private static final String ANALOG_SCROLLING_PREF_STRING = "analog_scrolling";
|
||||
private static final String MOUSE_NAV_BUTTONS_STRING = "checkbox_mouse_nav_buttons";
|
||||
static final String UNLOCK_FPS_STRING = "checkbox_unlock_fps";
|
||||
private static final String VIBRATE_OSC_PREF_STRING = "checkbox_vibrate_osc";
|
||||
private static final String VIBRATE_FALLBACK_PREF_STRING = "checkbox_vibrate_fallback";
|
||||
private static final String VIBRATE_FALLBACK_STRENGTH_PREF_STRING = "seekbar_vibrate_fallback_strength";
|
||||
private static final String FLIP_FACE_BUTTONS_PREF_STRING = "checkbox_flip_face_buttons";
|
||||
private static final String TOUCHSCREEN_TRACKPAD_PREF_STRING = "checkbox_touchscreen_trackpad";
|
||||
private static final String LATENCY_TOAST_PREF_STRING = "checkbox_enable_post_stream_toast";
|
||||
@@ -48,6 +64,10 @@ public class PreferenceConfiguration {
|
||||
private static final String ABSOLUTE_MOUSE_MODE_PREF_STRING = "checkbox_absolute_mouse_mode";
|
||||
private static final String ENABLE_AUDIO_FX_PREF_STRING = "checkbox_enable_audiofx";
|
||||
private static final String REDUCE_REFRESH_RATE_PREF_STRING = "checkbox_reduce_refresh_rate";
|
||||
private static final String FULL_RANGE_PREF_STRING = "checkbox_full_range";
|
||||
private static final String GAMEPAD_TOUCHPAD_AS_MOUSE_PREF_STRING = "checkbox_gamepad_touchpad_as_mouse";
|
||||
private static final String GAMEPAD_MOTION_SENSORS_PREF_STRING = "checkbox_gamepad_motion_sensors";
|
||||
private static final String GAMEPAD_MOTION_FALLBACK_PREF_STRING = "checkbox_gamepad_motion_fallback";
|
||||
|
||||
static final String DEFAULT_RESOLUTION = "1280x720";
|
||||
static final String DEFAULT_FPS = "60";
|
||||
@@ -61,17 +81,21 @@ public class PreferenceConfiguration {
|
||||
private static final boolean DEFAULT_MULTI_CONTROLLER = true;
|
||||
private static final boolean DEFAULT_USB_DRIVER = true;
|
||||
private static final String DEFAULT_VIDEO_FORMAT = "auto";
|
||||
|
||||
private static final boolean ONSCREEN_CONTROLLER_DEFAULT = false;
|
||||
private static final boolean ONLY_L3_R3_DEFAULT = false;
|
||||
private static final boolean SHOW_GUIDE_BUTTON_DEFAULT = true;
|
||||
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;
|
||||
private static final boolean DEFAULT_BIND_ALL_USB = false;
|
||||
private static final boolean DEFAULT_MOUSE_EMULATION = true;
|
||||
private static final String DEFAULT_ANALOG_STICK_FOR_SCROLLING = "right";
|
||||
private static final boolean DEFAULT_MOUSE_NAV_BUTTONS = false;
|
||||
private static final boolean DEFAULT_UNLOCK_FPS = false;
|
||||
private static final boolean DEFAULT_VIBRATE_OSC = true;
|
||||
private static final boolean DEFAULT_VIBRATE_FALLBACK = false;
|
||||
private static final int DEFAULT_VIBRATE_FALLBACK_STRENGTH = 100;
|
||||
private static final boolean DEFAULT_FLIP_FACE_BUTTONS = false;
|
||||
private static final boolean DEFAULT_TOUCHSCREEN_TRACKPAD = true;
|
||||
private static final String DEFAULT_AUDIO_CONFIG = "2"; // Stereo
|
||||
@@ -80,27 +104,27 @@ public class PreferenceConfiguration {
|
||||
private static final boolean DEFAULT_ABSOLUTE_MOUSE_MODE = false;
|
||||
private static final boolean DEFAULT_ENABLE_AUDIO_FX = false;
|
||||
private static final boolean DEFAULT_REDUCE_REFRESH_RATE = false;
|
||||
|
||||
public static final int FORCE_H265_ON = -1;
|
||||
public static final int AUTOSELECT_H265 = 0;
|
||||
public static final int FORCE_H265_OFF = 1;
|
||||
private static final boolean DEFAULT_FULL_RANGE = false;
|
||||
private static final boolean DEFAULT_GAMEPAD_TOUCHPAD_AS_MOUSE = false;
|
||||
private static final boolean DEFAULT_GAMEPAD_MOTION_SENSORS = true;
|
||||
private static final boolean DEFAULT_GAMEPAD_MOTION_FALLBACK = false;
|
||||
|
||||
public static final int FRAME_PACING_MIN_LATENCY = 0;
|
||||
public static final int FRAME_PACING_BALANCED = 1;
|
||||
public static final int FRAME_PACING_CAP_FPS = 2;
|
||||
public static final int FRAME_PACING_MAX_SMOOTHNESS = 3;
|
||||
|
||||
public static final String RES_360P = "s_640x360";
|
||||
public static final String RES_480P = "s_854x480";
|
||||
public static final String RES_720P = "s_1280x720";
|
||||
public static final String RES_1080P = "s_1920x1080";
|
||||
public static final String RES_1440P = "s_2560x1440";
|
||||
public static final String RES_4K = "s_3840x2160";
|
||||
public static final String RES_360P = "640x360";
|
||||
public static final String RES_480P = "854x480";
|
||||
public static final String RES_720P = "1280x720";
|
||||
public static final String RES_1080P = "1920x1080";
|
||||
public static final String RES_1440P = "2560x1440";
|
||||
public static final String RES_4K = "3840x2160";
|
||||
public static final String RES_NATIVE = "Native";
|
||||
|
||||
public StreamResolution resolution;
|
||||
public int fps;
|
||||
public int width, height, fps;
|
||||
public int bitrate;
|
||||
public int videoFormat;
|
||||
public FormatOption videoFormat;
|
||||
public int deadzonePercentage;
|
||||
public int oscOpacity;
|
||||
public boolean stretchVideo, enableSops, playHostAudio, disableWarnings;
|
||||
@@ -108,26 +132,31 @@ public class PreferenceConfiguration {
|
||||
public boolean smallIconMode, multiController, usbDriver, flipFaceButtons;
|
||||
public boolean onscreenController;
|
||||
public boolean onlyL3R3;
|
||||
public boolean showGuideButton;
|
||||
public boolean enableHdr;
|
||||
public boolean enablePip;
|
||||
public boolean enablePerfOverlay;
|
||||
public boolean enableLatencyToast;
|
||||
public boolean bindAllUsb;
|
||||
public boolean mouseEmulation;
|
||||
public AnalogStickForScrolling analogStickForScrolling;
|
||||
public boolean mouseNavButtons;
|
||||
public boolean unlockFps;
|
||||
public boolean vibrateOsc;
|
||||
public boolean vibrateFallbackToDevice;
|
||||
public int vibrateFallbackToDeviceStrength;
|
||||
public boolean touchscreenTrackpad;
|
||||
public MoonBridge.AudioConfiguration audioConfiguration;
|
||||
public int framePacing;
|
||||
public boolean absoluteMouseMode;
|
||||
public boolean enableAudioFx;
|
||||
public boolean reduceRefreshRate;
|
||||
public boolean fullRange;
|
||||
public boolean gamepadMotionSensors;
|
||||
public boolean gamepadTouchpadAsMouse;
|
||||
public boolean gamepadMotionSensorsFallbackToDevice;
|
||||
|
||||
// This is used only for migration to the new type code format of resolution strings
|
||||
// It doesn't properly handle custom resolutions!
|
||||
private static boolean legacyIsNativeResolution(int width, int height) {
|
||||
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;
|
||||
@@ -177,76 +206,117 @@ public class PreferenceConfiguration {
|
||||
}
|
||||
|
||||
private static String convertFromLegacyResolutionString(String resString) {
|
||||
if (!resString.contains("x")) {
|
||||
// Convert from hardcoded strings to strings with dimensions embedded
|
||||
if (resString.equalsIgnoreCase("360p")) {
|
||||
return RES_360P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("480p")) {
|
||||
return RES_480P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("720p")) {
|
||||
return RES_720P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("1080p")) {
|
||||
return RES_1080P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("1440p")) {
|
||||
return RES_1440P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("4K")) {
|
||||
return RES_4K;
|
||||
}
|
||||
else {
|
||||
// Should be unreachable
|
||||
return RES_720P;
|
||||
}
|
||||
if (resString.equalsIgnoreCase("360p")) {
|
||||
return RES_360P;
|
||||
}
|
||||
else if (Character.isDigit(resString.charAt(0))) {
|
||||
// Convert to type code prefix format
|
||||
String[] dims = resString.split("x");
|
||||
int width = Integer.parseInt(dims[0]);
|
||||
int height = Integer.parseInt(dims[1]);
|
||||
return new StreamResolution(width, height,
|
||||
legacyIsNativeResolution(width, height) ? StreamResolution.ResolutionType.NATIVE : StreamResolution.ResolutionType.STANDARD)
|
||||
.toPrefString();
|
||||
else if (resString.equalsIgnoreCase("480p")) {
|
||||
return RES_480P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("720p")) {
|
||||
return RES_720P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("1080p")) {
|
||||
return RES_1080P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("1440p")) {
|
||||
return RES_1440P;
|
||||
}
|
||||
else if (resString.equalsIgnoreCase("4K")) {
|
||||
return RES_4K;
|
||||
}
|
||||
else {
|
||||
return resString;
|
||||
// Should be unreachable
|
||||
return RES_720P;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getWidthFromResolutionString(String resString) {
|
||||
return Integer.parseInt(resString.split("x")[0]);
|
||||
}
|
||||
|
||||
private static int getHeightFromResolutionString(String resString) {
|
||||
return Integer.parseInt(resString.split("x")[1]);
|
||||
}
|
||||
|
||||
private static String getResolutionString(int width, int height) {
|
||||
switch (height) {
|
||||
case 360:
|
||||
return RES_360P;
|
||||
case 480:
|
||||
return RES_480P;
|
||||
default:
|
||||
case 720:
|
||||
return RES_720P;
|
||||
case 1080:
|
||||
return RES_1080P;
|
||||
case 1440:
|
||||
return RES_1440P;
|
||||
case 2160:
|
||||
return RES_4K;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getDefaultBitrate(String resString, String fpsString) {
|
||||
StreamResolution res = new StreamResolution(resString);
|
||||
int width = getWidthFromResolutionString(resString);
|
||||
int height = getHeightFromResolutionString(resString);
|
||||
int fps = Integer.parseInt(fpsString);
|
||||
|
||||
// This table prefers 16:10 resolutions because they are
|
||||
// only slightly more pixels than the 16:9 equivalents, so
|
||||
// we don't want to bump those 16:10 resolutions up to the
|
||||
// next 16:9 slot.
|
||||
//
|
||||
// This logic is shamelessly stolen from Moonlight Qt:
|
||||
// https://github.com/moonlight-stream/moonlight-qt/blob/master/app/settings/streamingpreferences.cpp
|
||||
|
||||
if (res.width * res.height <= 640 * 360) {
|
||||
return (int)(1000 * (fps / 30.0));
|
||||
}
|
||||
else if (res.width * res.height <= 854 * 480) {
|
||||
return (int)(1500 * (fps / 30.0));
|
||||
}
|
||||
// This covers 1280x720 and 1280x800 too
|
||||
else if (res.width * res.height <= 1366 * 768) {
|
||||
return (int)(5000 * (fps / 30.0));
|
||||
}
|
||||
else if (res.width * res.height <= 1920 * 1200) {
|
||||
return (int)(10000 * (fps / 30.0));
|
||||
}
|
||||
else if (res.width * res.height <= 2560 * 1600) {
|
||||
return (int)(20000 * (fps / 30.0));
|
||||
}
|
||||
else /* if (res.width * res.height <= 3840 * 2160) */ {
|
||||
return (int)(40000 * (fps / 30.0));
|
||||
// Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear
|
||||
// bitrate increase for frame rate once we get to values that high.
|
||||
double frameRateFactor = (fps <= 60 ? fps : (Math.sqrt(fps / 60.f) * 60.f)) / 30.f;
|
||||
|
||||
// TODO: Collect some empirical data to see if these defaults make sense.
|
||||
// We're just using the values that the Shield used, as we have for years.
|
||||
int[] pixelVals = {
|
||||
640 * 360,
|
||||
854 * 480,
|
||||
1280 * 720,
|
||||
1920 * 1080,
|
||||
2560 * 1440,
|
||||
3840 * 2160,
|
||||
-1,
|
||||
};
|
||||
int[] factorVals = {
|
||||
1,
|
||||
2,
|
||||
5,
|
||||
10,
|
||||
20,
|
||||
40,
|
||||
-1
|
||||
};
|
||||
|
||||
// Calculate the resolution factor by linear interpolation of the resolution table
|
||||
float resolutionFactor;
|
||||
int pixels = width * height;
|
||||
for (int i = 0; ; i++) {
|
||||
if (pixels == pixelVals[i]) {
|
||||
// We can bail immediately for exact matches
|
||||
resolutionFactor = factorVals[i];
|
||||
break;
|
||||
}
|
||||
else if (pixels < pixelVals[i]) {
|
||||
if (i == 0) {
|
||||
// Never go below the lowest resolution entry
|
||||
resolutionFactor = factorVals[i];
|
||||
}
|
||||
else {
|
||||
// Interpolate between the entry greater than the chosen resolution (i) and the entry less than the chosen resolution (i-1)
|
||||
resolutionFactor = ((float)(pixels - pixelVals[i-1]) / (pixelVals[i] - pixelVals[i-1])) * (factorVals[i] - factorVals[i-1]) + factorVals[i-1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (pixelVals[i] == -1) {
|
||||
// Never go above the highest resolution entry
|
||||
resolutionFactor = factorVals[i-1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)Math.round(resolutionFactor * frameRateFactor) * 1000;
|
||||
}
|
||||
|
||||
public static boolean getDefaultSmallMode(Context context) {
|
||||
@@ -276,22 +346,25 @@ public class PreferenceConfiguration {
|
||||
prefs.getString(FPS_PREF_STRING, DEFAULT_FPS));
|
||||
}
|
||||
|
||||
private static int getVideoFormatValue(Context context) {
|
||||
private static FormatOption getVideoFormatValue(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
String str = prefs.getString(VIDEO_FORMAT_PREF_STRING, DEFAULT_VIDEO_FORMAT);
|
||||
if (str.equals("auto")) {
|
||||
return AUTOSELECT_H265;
|
||||
return FormatOption.AUTO;
|
||||
}
|
||||
else if (str.equals("forceav1")) {
|
||||
return FormatOption.FORCE_AV1;
|
||||
}
|
||||
else if (str.equals("forceh265")) {
|
||||
return FORCE_H265_ON;
|
||||
return FormatOption.FORCE_HEVC;
|
||||
}
|
||||
else if (str.equals("neverh265")) {
|
||||
return FORCE_H265_OFF;
|
||||
return FormatOption.FORCE_H264;
|
||||
}
|
||||
else {
|
||||
// Should never get here
|
||||
return AUTOSELECT_H265;
|
||||
return FormatOption.AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,6 +399,21 @@ public class PreferenceConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
private static AnalogStickForScrolling getAnalogStickForScrollingValue(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
String str = prefs.getString(ANALOG_SCROLLING_PREF_STRING, DEFAULT_ANALOG_STICK_FOR_SCROLLING);
|
||||
if (str.equals("right")) {
|
||||
return AnalogStickForScrolling.RIGHT;
|
||||
}
|
||||
else if (str.equals("left")) {
|
||||
return AnalogStickForScrolling.LEFT;
|
||||
}
|
||||
else {
|
||||
return AnalogStickForScrolling.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public static void resetStreamingSettings(Context context) {
|
||||
// We consider resolution, FPS, bitrate, HDR, and video format as "streaming settings" here
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
@@ -338,6 +426,7 @@ public class PreferenceConfiguration {
|
||||
.remove(VIDEO_FORMAT_PREF_STRING)
|
||||
.remove(ENABLE_HDR_PREF_STRING)
|
||||
.remove(UNLOCK_FPS_STRING)
|
||||
.remove(FULL_RANGE_PREF_STRING)
|
||||
.apply();
|
||||
}
|
||||
|
||||
@@ -371,46 +460,55 @@ public class PreferenceConfiguration {
|
||||
String str = prefs.getString(LEGACY_RES_FPS_PREF_STRING, null);
|
||||
if (str != null) {
|
||||
if (str.equals("360p30")) {
|
||||
config.resolution = new StreamResolution(640, 360, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 640;
|
||||
config.height = 360;
|
||||
config.fps = 30;
|
||||
}
|
||||
else if (str.equals("360p60")) {
|
||||
config.resolution = new StreamResolution(640, 360, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 640;
|
||||
config.height = 360;
|
||||
config.fps = 60;
|
||||
}
|
||||
else if (str.equals("720p30")) {
|
||||
config.resolution = new StreamResolution(1280, 720, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 1280;
|
||||
config.height = 720;
|
||||
config.fps = 30;
|
||||
}
|
||||
else if (str.equals("720p60")) {
|
||||
config.resolution = new StreamResolution(1280, 720, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 1280;
|
||||
config.height = 720;
|
||||
config.fps = 60;
|
||||
}
|
||||
else if (str.equals("1080p30")) {
|
||||
config.resolution = new StreamResolution(1920, 1080, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 1920;
|
||||
config.height = 1080;
|
||||
config.fps = 30;
|
||||
}
|
||||
else if (str.equals("1080p60")) {
|
||||
config.resolution = new StreamResolution(1920, 1080, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 1920;
|
||||
config.height = 1080;
|
||||
config.fps = 60;
|
||||
}
|
||||
else if (str.equals("4K30")) {
|
||||
config.resolution = new StreamResolution(3840, 2160, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 3840;
|
||||
config.height = 2160;
|
||||
config.fps = 30;
|
||||
}
|
||||
else if (str.equals("4K60")) {
|
||||
config.resolution = new StreamResolution(3840, 2160, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 3840;
|
||||
config.height = 2160;
|
||||
config.fps = 60;
|
||||
}
|
||||
else {
|
||||
// Should never get here
|
||||
config.resolution = new StreamResolution(1280, 720, StreamResolution.ResolutionType.STANDARD);
|
||||
config.width = 1280;
|
||||
config.height = 720;
|
||||
config.fps = 60;
|
||||
}
|
||||
|
||||
prefs.edit()
|
||||
.remove(LEGACY_RES_FPS_PREF_STRING)
|
||||
.putString(RESOLUTION_PREF_STRING, config.resolution.toPrefString())
|
||||
.putString(RESOLUTION_PREF_STRING, getResolutionString(config.width, config.height))
|
||||
.putString(FPS_PREF_STRING, ""+config.fps)
|
||||
.apply();
|
||||
}
|
||||
@@ -419,12 +517,13 @@ public class PreferenceConfiguration {
|
||||
String resStr = prefs.getString(RESOLUTION_PREF_STRING, PreferenceConfiguration.DEFAULT_RESOLUTION);
|
||||
|
||||
// Convert legacy resolution strings to the new style
|
||||
if (Character.isDigit(resStr.charAt(0)) || !resStr.contains("x")) {
|
||||
if (!resStr.contains("x")) {
|
||||
resStr = PreferenceConfiguration.convertFromLegacyResolutionString(resStr);
|
||||
prefs.edit().putString(RESOLUTION_PREF_STRING, resStr).apply();
|
||||
}
|
||||
|
||||
config.resolution = new StreamResolution(resStr);
|
||||
config.width = PreferenceConfiguration.getWidthFromResolutionString(resStr);
|
||||
config.height = PreferenceConfiguration.getHeightFromResolutionString(resStr);
|
||||
config.fps = Integer.parseInt(prefs.getString(FPS_PREF_STRING, PreferenceConfiguration.DEFAULT_FPS));
|
||||
}
|
||||
|
||||
@@ -434,6 +533,15 @@ public class PreferenceConfiguration {
|
||||
prefs.edit().putBoolean(SMALL_ICONS_PREF_STRING, getDefaultSmallMode(context)).apply();
|
||||
}
|
||||
|
||||
if (!prefs.contains(GAMEPAD_MOTION_SENSORS_PREF_STRING) && Build.VERSION.SDK_INT == Build.VERSION_CODES.S) {
|
||||
// Android 12 has a nasty bug that causes crashes when the app touches the InputDevice's
|
||||
// associated InputDeviceSensorManager (just calling getSensorManager() is enough).
|
||||
// As a workaround, we will override the default value for the gamepad motion sensor
|
||||
// option to disabled on Android 12 to reduce the impact of this bug.
|
||||
// https://cs.android.com/android/_/android/platform/frameworks/base/+/8970010a5e9f3dc5c069f56b4147552accfcbbeb
|
||||
prefs.edit().putBoolean(GAMEPAD_MOTION_SENSORS_PREF_STRING, false).apply();
|
||||
}
|
||||
|
||||
// This must happen after the preferences migration to ensure the preferences are populated
|
||||
config.bitrate = prefs.getInt(BITRATE_PREF_STRING, prefs.getInt(BITRATE_PREF_OLD_STRING, 0) * 1000);
|
||||
if (config.bitrate == 0) {
|
||||
@@ -454,6 +562,8 @@ public class PreferenceConfiguration {
|
||||
config.videoFormat = getVideoFormatValue(context);
|
||||
config.framePacing = getFramePacingValue(context);
|
||||
|
||||
config.analogStickForScrolling = getAnalogStickForScrollingValue(context);
|
||||
|
||||
config.deadzonePercentage = prefs.getInt(DEADZONE_PREF_STRING, DEFAULT_DEADZONE);
|
||||
|
||||
config.oscOpacity = prefs.getInt(OSC_OPACITY_PREF_STRING, DEFAULT_OPACITY);
|
||||
@@ -470,6 +580,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.showGuideButton = prefs.getBoolean(SHOW_GUIDE_BUTTON_PREF_STRING, SHOW_GUIDE_BUTTON_DEFAULT);
|
||||
config.enableHdr = prefs.getBoolean(ENABLE_HDR_PREF_STRING, DEFAULT_ENABLE_HDR) && !isShieldAtvFirmwareWithBrokenHdr();
|
||||
config.enablePip = prefs.getBoolean(ENABLE_PIP_PREF_STRING, DEFAULT_ENABLE_PIP);
|
||||
config.enablePerfOverlay = prefs.getBoolean(ENABLE_PERF_OVERLAY_STRING, DEFAULT_ENABLE_PERF_OVERLAY);
|
||||
@@ -479,121 +590,18 @@ public class PreferenceConfiguration {
|
||||
config.unlockFps = prefs.getBoolean(UNLOCK_FPS_STRING, DEFAULT_UNLOCK_FPS);
|
||||
config.vibrateOsc = prefs.getBoolean(VIBRATE_OSC_PREF_STRING, DEFAULT_VIBRATE_OSC);
|
||||
config.vibrateFallbackToDevice = prefs.getBoolean(VIBRATE_FALLBACK_PREF_STRING, DEFAULT_VIBRATE_FALLBACK);
|
||||
config.vibrateFallbackToDeviceStrength = prefs.getInt(VIBRATE_FALLBACK_STRENGTH_PREF_STRING, DEFAULT_VIBRATE_FALLBACK_STRENGTH);
|
||||
config.flipFaceButtons = prefs.getBoolean(FLIP_FACE_BUTTONS_PREF_STRING, DEFAULT_FLIP_FACE_BUTTONS);
|
||||
config.touchscreenTrackpad = prefs.getBoolean(TOUCHSCREEN_TRACKPAD_PREF_STRING, DEFAULT_TOUCHSCREEN_TRACKPAD);
|
||||
config.enableLatencyToast = prefs.getBoolean(LATENCY_TOAST_PREF_STRING, DEFAULT_LATENCY_TOAST);
|
||||
config.absoluteMouseMode = prefs.getBoolean(ABSOLUTE_MOUSE_MODE_PREF_STRING, DEFAULT_ABSOLUTE_MOUSE_MODE);
|
||||
config.enableAudioFx = prefs.getBoolean(ENABLE_AUDIO_FX_PREF_STRING, DEFAULT_ENABLE_AUDIO_FX);
|
||||
config.reduceRefreshRate = prefs.getBoolean(REDUCE_REFRESH_RATE_PREF_STRING, DEFAULT_REDUCE_REFRESH_RATE);
|
||||
config.fullRange = prefs.getBoolean(FULL_RANGE_PREF_STRING, DEFAULT_FULL_RANGE);
|
||||
config.gamepadTouchpadAsMouse = prefs.getBoolean(GAMEPAD_TOUCHPAD_AS_MOUSE_PREF_STRING, DEFAULT_GAMEPAD_TOUCHPAD_AS_MOUSE);
|
||||
config.gamepadMotionSensors = prefs.getBoolean(GAMEPAD_MOTION_SENSORS_PREF_STRING, DEFAULT_GAMEPAD_MOTION_SENSORS);
|
||||
config.gamepadMotionSensorsFallbackToDevice = prefs.getBoolean(GAMEPAD_MOTION_FALLBACK_PREF_STRING, DEFAULT_GAMEPAD_MOTION_FALLBACK);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static class StreamResolution {
|
||||
public int width;
|
||||
public int height;
|
||||
public ResolutionType type;
|
||||
public boolean portrait;
|
||||
public boolean fullScreen;
|
||||
|
||||
private static final char RES_START_DELIMITER = '_';
|
||||
private static final char RES_DIM_DELIMITER = 'x';
|
||||
|
||||
private static final char TYPE_CODE_STANDARD = 's';
|
||||
private static final char TYPE_CODE_NATIVE = 'n';
|
||||
|
||||
private static final char OPTION_CODE_PORTRAIT = 'p';
|
||||
private static final char OPTION_CODE_FULL_SCREEN = 'f';
|
||||
|
||||
public enum ResolutionType {
|
||||
STANDARD,
|
||||
NATIVE
|
||||
}
|
||||
|
||||
private StreamResolution(int width, int height, ResolutionType type) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.type = type;
|
||||
|
||||
// Just guess for the options, since we don't know for sure
|
||||
this.portrait = height > width;
|
||||
this.fullScreen = false;
|
||||
}
|
||||
|
||||
public StreamResolution(int width, int height, ResolutionType type, boolean portrait, boolean fullScreen) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.type = type;
|
||||
this.portrait = portrait;
|
||||
this.fullScreen = fullScreen;
|
||||
}
|
||||
|
||||
StreamResolution(String resString) {
|
||||
// Type code is the first character in the string
|
||||
switch (resString.charAt(0)) {
|
||||
case TYPE_CODE_NATIVE:
|
||||
this.type = StreamResolution.ResolutionType.NATIVE;
|
||||
break;
|
||||
case TYPE_CODE_STANDARD:
|
||||
this.type = StreamResolution.ResolutionType.STANDARD;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid type code: " + resString.charAt(0));
|
||||
}
|
||||
|
||||
// Parse options until we reach the resolution start delimiter
|
||||
int currentIndex = 1;
|
||||
while (resString.charAt(currentIndex) != RES_START_DELIMITER) {
|
||||
switch (resString.charAt(currentIndex)) {
|
||||
case OPTION_CODE_PORTRAIT:
|
||||
portrait = true;
|
||||
break;
|
||||
case OPTION_CODE_FULL_SCREEN:
|
||||
fullScreen = true;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid option code: " + resString.charAt(currentIndex));
|
||||
}
|
||||
|
||||
currentIndex++;
|
||||
}
|
||||
|
||||
// Skip the type code before splitting
|
||||
String[] dims = resString.substring(currentIndex).split(""+RES_DIM_DELIMITER);
|
||||
this.width = Integer.parseInt(dims[0]);
|
||||
this.height = Integer.parseInt(dims[1]);
|
||||
}
|
||||
|
||||
public String toPrefString() {
|
||||
String str = "";
|
||||
|
||||
// Start with the type code
|
||||
switch (type) {
|
||||
case NATIVE:
|
||||
str += TYPE_CODE_NATIVE;
|
||||
break;
|
||||
case STANDARD:
|
||||
str += TYPE_CODE_STANDARD;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid type: "+type);
|
||||
}
|
||||
|
||||
// Now any option codes that may apply
|
||||
if (portrait) {
|
||||
str += OPTION_CODE_PORTRAIT;
|
||||
}
|
||||
if (fullScreen) {
|
||||
str += OPTION_CODE_FULL_SCREEN;
|
||||
}
|
||||
|
||||
// And finally the dimensions
|
||||
str += RES_START_DELIMITER;
|
||||
str += width;
|
||||
str += RES_DIM_DELIMITER;
|
||||
str += height;
|
||||
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,74 +122,95 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment {
|
||||
private int nativeResolutionStartIndex = Integer.MAX_VALUE;
|
||||
private boolean nativeFramerateShown = false;
|
||||
|
||||
private void setValue(String preferenceKey, String value) {
|
||||
ListPreference pref = (ListPreference) findPreference(preferenceKey);
|
||||
|
||||
pref.setValue(value);
|
||||
}
|
||||
|
||||
private void addResolutionEntry(int width, int height, PreferenceConfiguration.StreamResolution.ResolutionType type,
|
||||
boolean insetsRemoved, boolean portrait) {
|
||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
|
||||
PreferenceConfiguration.StreamResolution newRes =
|
||||
new PreferenceConfiguration.StreamResolution(width, height, type, portrait, insetsRemoved);
|
||||
|
||||
String newName;
|
||||
|
||||
if (type == PreferenceConfiguration.StreamResolution.ResolutionType.NATIVE) {
|
||||
if (insetsRemoved) {
|
||||
newName = getResources().getString(R.string.resolution_prefix_native_fullscreen);
|
||||
}
|
||||
else {
|
||||
newName = getResources().getString(R.string.resolution_prefix_native);
|
||||
}
|
||||
|
||||
if (PreferenceConfiguration.isSquarishScreen(width, height)) {
|
||||
if (portrait) {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_portrait);
|
||||
}
|
||||
else {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_landscape);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
newName = null;
|
||||
}
|
||||
|
||||
newName += " ("+width+"x"+height+")";
|
||||
|
||||
CharSequence[] values = pref.getEntryValues();
|
||||
|
||||
// Check if the new resolution is already present
|
||||
for (CharSequence value : values) {
|
||||
PreferenceConfiguration.StreamResolution existingResolution = new PreferenceConfiguration.StreamResolution(value.toString());
|
||||
if (existingResolution.width == newRes.width && existingResolution.height == newRes.height) {
|
||||
// It is present in the default list, so don't add it again
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void appendPreferenceEntry(ListPreference pref, String newEntryName, String newEntryValue) {
|
||||
CharSequence[] newEntries = Arrays.copyOf(pref.getEntries(), pref.getEntries().length + 1);
|
||||
CharSequence[] newValues = Arrays.copyOf(values, values.length + 1);
|
||||
CharSequence[] newValues = Arrays.copyOf(pref.getEntryValues(), pref.getEntryValues().length + 1);
|
||||
|
||||
// Add the new resolution option
|
||||
newEntries[newEntries.length - 1] = newName;
|
||||
newValues[newValues.length - 1] = newRes.toPrefString();
|
||||
// Add the new option
|
||||
newEntries[newEntries.length - 1] = newEntryName;
|
||||
newValues[newValues.length - 1] = newEntryValue;
|
||||
|
||||
pref.setEntries(newEntries);
|
||||
pref.setEntryValues(newValues);
|
||||
}
|
||||
|
||||
private void addNativeResolutionEntry(int nativeWidth, int nativeHeight, boolean insetsRemoved, boolean portrait) {
|
||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.RESOLUTION_PREF_STRING);
|
||||
|
||||
String newName;
|
||||
|
||||
if (insetsRemoved) {
|
||||
newName = getResources().getString(R.string.resolution_prefix_native_fullscreen);
|
||||
}
|
||||
else {
|
||||
newName = getResources().getString(R.string.resolution_prefix_native);
|
||||
}
|
||||
|
||||
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
|
||||
if (portrait) {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_portrait);
|
||||
}
|
||||
else {
|
||||
newName += " " + getResources().getString(R.string.resolution_prefix_native_landscape);
|
||||
}
|
||||
}
|
||||
|
||||
newName += " ("+nativeWidth+"x"+nativeHeight+")";
|
||||
|
||||
String newValue = nativeWidth+"x"+nativeHeight;
|
||||
|
||||
// Check if the native resolution is already present
|
||||
for (CharSequence value : pref.getEntryValues()) {
|
||||
if (newValue.equals(value.toString())) {
|
||||
// It is present in the default list, so don't add it again
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pref.getEntryValues().length < nativeResolutionStartIndex) {
|
||||
nativeResolutionStartIndex = pref.getEntryValues().length;
|
||||
}
|
||||
appendPreferenceEntry(pref, newName, newValue);
|
||||
}
|
||||
|
||||
private void addNativeResolutionEntries(int nativeWidth, int nativeHeight, boolean insetsRemoved) {
|
||||
if (PreferenceConfiguration.isSquarishScreen(nativeWidth, nativeHeight)) {
|
||||
addResolutionEntry(nativeHeight, nativeWidth,
|
||||
PreferenceConfiguration.StreamResolution.ResolutionType.NATIVE,
|
||||
insetsRemoved, true);
|
||||
addNativeResolutionEntry(nativeHeight, nativeWidth, insetsRemoved, true);
|
||||
}
|
||||
addResolutionEntry(nativeWidth, nativeHeight,
|
||||
PreferenceConfiguration.StreamResolution.ResolutionType.NATIVE,
|
||||
insetsRemoved, false);
|
||||
addNativeResolutionEntry(nativeWidth, nativeHeight, insetsRemoved, false);
|
||||
}
|
||||
|
||||
private void addNativeFrameRateEntry(float framerate) {
|
||||
int frameRateRounded = Math.round(framerate);
|
||||
if (frameRateRounded == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ListPreference pref = (ListPreference) findPreference(PreferenceConfiguration.FPS_PREF_STRING);
|
||||
String fpsValue = Integer.toString(frameRateRounded);
|
||||
String fpsName = getResources().getString(R.string.resolution_prefix_native) +
|
||||
" (" + fpsValue + " " + getResources().getString(R.string.fps_suffix_fps) + ")";
|
||||
|
||||
// Check if the native frame rate is already present
|
||||
for (CharSequence value : pref.getEntryValues()) {
|
||||
if (fpsValue.equals(value.toString())) {
|
||||
// It is present in the default list, so don't add it again
|
||||
nativeFramerateShown = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
appendPreferenceEntry(pref, fpsName, fpsValue);
|
||||
nativeFramerateShown = true;
|
||||
}
|
||||
|
||||
private void removeValue(String preferenceKey, String value, Runnable onMatched) {
|
||||
@@ -257,19 +278,10 @@ public class StreamSettings extends Activity {
|
||||
PreferenceScreen screen = getPreferenceScreen();
|
||||
|
||||
// hide on-screen controls category on non touch screen devices
|
||||
if (!getActivity().getPackageManager().
|
||||
hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
|
||||
{
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_onscreen_controls");
|
||||
screen.removePreference(category);
|
||||
}
|
||||
|
||||
{
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_input_settings");
|
||||
category.removePreference(findPreference("checkbox_touchscreen_trackpad"));
|
||||
}
|
||||
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_onscreen_controls");
|
||||
screen.removePreference(category);
|
||||
}
|
||||
|
||||
// Hide remote desktop mouse mode on pre-Oreo (which doesn't have pointer capture)
|
||||
@@ -281,6 +293,30 @@ public class StreamSettings extends Activity {
|
||||
category.removePreference(findPreference("checkbox_absolute_mouse_mode"));
|
||||
}
|
||||
|
||||
// Hide gamepad motion sensor option when running on OSes before Android 12.
|
||||
// Support for motion, LED, battery, and other extensions were introduced in S.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_gamepad_settings");
|
||||
category.removePreference(findPreference("checkbox_gamepad_motion_sensors"));
|
||||
}
|
||||
|
||||
// Hide gamepad motion sensor fallback option if the device has no gyro or accelerometer
|
||||
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_ACCELEROMETER) &&
|
||||
!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_SENSOR_GYROSCOPE)) {
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_gamepad_settings");
|
||||
category.removePreference(findPreference("checkbox_gamepad_motion_fallback"));
|
||||
}
|
||||
|
||||
// Hide USB driver options on devices without USB host support
|
||||
if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_gamepad_settings");
|
||||
category.removePreference(findPreference("checkbox_usb_bind_all"));
|
||||
category.removePreference(findPreference("checkbox_usb_driver"));
|
||||
}
|
||||
|
||||
// Remove PiP mode on devices pre-Oreo, where the feature is not available (some low RAM devices),
|
||||
// and on Fire OS where it violates the Amazon App Store guidelines for some reason.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
|
||||
@@ -297,26 +333,29 @@ public class StreamSettings extends Activity {
|
||||
(PreferenceCategory) findPreference("category_help");
|
||||
screen.removePreference(category);
|
||||
}*/
|
||||
|
||||
PreferenceCategory category_gamepad_settings =
|
||||
(PreferenceCategory) findPreference("category_gamepad_settings");
|
||||
// Remove the vibration options if the device can't vibrate
|
||||
if (!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasVibrator()) {
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_input_settings");
|
||||
category.removePreference(findPreference("checkbox_vibrate_fallback"));
|
||||
|
||||
category_gamepad_settings.removePreference(findPreference("checkbox_vibrate_fallback"));
|
||||
category_gamepad_settings.removePreference(findPreference("seekbar_vibrate_fallback_strength"));
|
||||
// The entire OSC category may have already been removed by the touchscreen check above
|
||||
category = (PreferenceCategory) findPreference("category_onscreen_controls");
|
||||
PreferenceCategory category = (PreferenceCategory) findPreference("category_onscreen_controls");
|
||||
if (category != null) {
|
||||
category.removePreference(findPreference("checkbox_vibrate_osc"));
|
||||
}
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
|
||||
!((Vibrator)getActivity().getSystemService(Context.VIBRATOR_SERVICE)).hasAmplitudeControl() ) {
|
||||
// Remove the vibration strength selector of the device doesn't have amplitude control
|
||||
category_gamepad_settings.removePreference(findPreference("seekbar_vibrate_fallback_strength"));
|
||||
}
|
||||
|
||||
int maxSupportedFps = 0;
|
||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||
float maxSupportedFps = display.getRefreshRate();
|
||||
|
||||
// Hide non-supported resolution/FPS combinations
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||
|
||||
int maxSupportedResW = 0;
|
||||
|
||||
// Add a native resolution with any insets included for users that don't want content
|
||||
@@ -384,7 +423,7 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
|
||||
if (candidate.getRefreshRate() > maxSupportedFps) {
|
||||
maxSupportedFps = (int)candidate.getRefreshRate();
|
||||
maxSupportedFps = candidate.getRefreshRate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,30 +511,15 @@ 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).
|
||||
else {
|
||||
// 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);
|
||||
display.getRealMetrics(metrics);
|
||||
int width = Math.max(metrics.widthPixels, metrics.heightPixels);
|
||||
int height = Math.min(metrics.widthPixels, metrics.heightPixels);
|
||||
addNativeResolutionEntries(width, height, false);
|
||||
}
|
||||
else {
|
||||
// On Android 4.1, we have to resort to reflection to invoke hidden APIs
|
||||
// to get the real screen dimensions.
|
||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||
try {
|
||||
Method getRawHeightFunc = Display.class.getMethod("getRawHeight");
|
||||
Method getRawWidthFunc = Display.class.getMethod("getRawWidth");
|
||||
int width = (Integer) getRawWidthFunc.invoke(display);
|
||||
int height = (Integer) getRawHeightFunc.invoke(display);
|
||||
addNativeResolutionEntries(Math.max(width, height), Math.min(width, height), false);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!PreferenceConfiguration.readPreferences(this.getActivity()).unlockFps) {
|
||||
// We give some extra room in case the FPS is rounded down
|
||||
@@ -522,50 +546,31 @@ public class StreamSettings extends Activity {
|
||||
}
|
||||
// Never remove 30 FPS or 60 FPS
|
||||
}
|
||||
|
||||
// Android L introduces proper 7.1 surround sound support. Remove the 7.1 option
|
||||
// for earlier versions of Android to prevent AudioTrack initialization issues.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
LimeLog.info("Excluding 7.1 surround sound option based on OS");
|
||||
removeValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "71", new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setValue(PreferenceConfiguration.AUDIO_CONFIG_PREF_STRING, "51");
|
||||
}
|
||||
});
|
||||
}
|
||||
addNativeFrameRateEntry(maxSupportedFps);
|
||||
|
||||
// Android L introduces the drop duplicate behavior of releaseOutputBuffer()
|
||||
// that the unlock FPS option relies on to not massively increase latency.
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
LimeLog.info("Excluding unlock FPS toggle based on OS");
|
||||
PreferenceCategory category =
|
||||
(PreferenceCategory) findPreference("category_advanced_settings");
|
||||
category.removePreference(findPreference("checkbox_unlock_fps"));
|
||||
}
|
||||
else {
|
||||
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
||||
// it's reflected in the new layout.
|
||||
final Handler h = new Handler();
|
||||
h.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Ensure the activity is still open when this timeout expires
|
||||
StreamSettings settingsActivity = (StreamSettings)SettingsFragment.this.getActivity();
|
||||
if (settingsActivity != null) {
|
||||
settingsActivity.reloadSettings();
|
||||
}
|
||||
findPreference(PreferenceConfiguration.UNLOCK_FPS_STRING).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
// HACK: We need to let the preference change succeed before reinitializing to ensure
|
||||
// it's reflected in the new layout.
|
||||
final Handler h = new Handler();
|
||||
h.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Ensure the activity is still open when this timeout expires
|
||||
StreamSettings settingsActivity = (StreamSettings) SettingsFragment.this.getActivity();
|
||||
if (settingsActivity != null) {
|
||||
settingsActivity.reloadSettings();
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Allow the original preference change to take place
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Allow the original preference change to take place
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Remove HDR preference for devices below Nougat
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
|
||||
@@ -575,7 +580,6 @@ public class StreamSettings extends Activity {
|
||||
category.removePreference(findPreference("checkbox_enable_hdr"));
|
||||
}
|
||||
else {
|
||||
Display display = getActivity().getWindowManager().getDefaultDisplay();
|
||||
Display.HdrCapabilities hdrCaps = display.getHdrCapabilities();
|
||||
|
||||
// We must now ensure our display is compatible with HDR10
|
||||
@@ -585,6 +589,7 @@ public class StreamSettings extends Activity {
|
||||
for (int hdrType : hdrCaps.getSupportedHdrTypes()) {
|
||||
if (hdrType == Display.HdrCapabilities.HDR_TYPE_HDR10) {
|
||||
foundHdr10 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -613,10 +618,20 @@ public class StreamSettings extends Activity {
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
|
||||
String valueStr = (String) newValue;
|
||||
PreferenceConfiguration.StreamResolution resolution = new PreferenceConfiguration.StreamResolution(valueStr);
|
||||
|
||||
// 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 (resolution.type == PreferenceConfiguration.StreamResolution.ResolutionType.NATIVE) {
|
||||
if (isNativeRes) {
|
||||
Dialog.displayDialog(getActivity(),
|
||||
getResources().getString(R.string.title_native_res_dialog),
|
||||
getResources().getString(R.string.text_native_res_dialog),
|
||||
@@ -636,6 +651,15 @@ public class StreamSettings extends Activity {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SettingsFragment.this.getActivity());
|
||||
String valueStr = (String) newValue;
|
||||
|
||||
// If this is native frame rate, show the warning dialog
|
||||
CharSequence[] values = ((ListPreference)preference).getEntryValues();
|
||||
if (nativeFramerateShown && values[values.length - 1].toString().equals(newValue.toString())) {
|
||||
Dialog.displayDialog(getActivity(),
|
||||
getResources().getString(R.string.title_native_fps_dialog),
|
||||
getResources().getString(R.string.text_native_res_dialog),
|
||||
false);
|
||||
}
|
||||
|
||||
// Write the new bitrate value
|
||||
resetBitrateToDefault(prefs, null, valueStr);
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ public class WebLauncherPreference extends Preference {
|
||||
initialize(attrs);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public WebLauncherPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
initialize(attrs);
|
||||
|
||||
@@ -30,6 +30,6 @@ public class AdapterFragment extends Fragment {
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
callbacks.receiveAbsListView((AbsListView) getView().findViewById(R.id.fragmentView));
|
||||
callbacks.receiveAbsListView(getView().findViewById(R.id.fragmentView));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public class StreamView extends SurfaceView {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@TargetApi(21)
|
||||
public StreamView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@@ -44,4 +44,8 @@ public class HelpLauncher {
|
||||
public static void launchTroubleshooting(Context context) {
|
||||
launchUrl(context, "https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting");
|
||||
}
|
||||
|
||||
public static void launchGameStreamEolFaq(Context context) {
|
||||
launchUrl(context, "https://github.com/moonlight-stream/moonlight-docs/wiki/NVIDIA-GameStream-End-Of-Service-Announcement-FAQ");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class NetHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
else {
|
||||
NetworkInfo activeNetworkInfo = connMgr.getActiveNetworkInfo();
|
||||
if (activeNetworkInfo != null) {
|
||||
return activeNetworkInfo.getType() == ConnectivityManager.TYPE_VPN;
|
||||
|
||||
@@ -6,13 +6,12 @@ import android.widget.Toast;
|
||||
|
||||
import com.limelight.AppView;
|
||||
import com.limelight.Game;
|
||||
import com.limelight.PcView;
|
||||
import com.limelight.R;
|
||||
import com.limelight.ShortcutTrampoline;
|
||||
import com.limelight.binding.PlatformBinding;
|
||||
import com.limelight.computers.ComputerManagerService;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.GfeHttpResponseException;
|
||||
import com.limelight.nvstream.http.HostHttpResponseException;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
import com.limelight.nvstream.http.NvHTTP;
|
||||
import com.limelight.nvstream.jni.MoonBridge;
|
||||
@@ -135,7 +134,7 @@ public class ServerHelper {
|
||||
} else {
|
||||
message = parent.getResources().getString(R.string.applist_quit_fail) + " " + app.getAppName();
|
||||
}
|
||||
} catch (GfeHttpResponseException e) {
|
||||
} catch (HostHttpResponseException e) {
|
||||
if (e.getErrorCode() == 599) {
|
||||
message = "This session wasn't started by this device," +
|
||||
" so it cannot be quit. End streaming on the original " +
|
||||
|
||||
@@ -2,15 +2,12 @@ package com.limelight.utils;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
|
||||
import com.limelight.AppView;
|
||||
import com.limelight.ShortcutTrampoline;
|
||||
import com.limelight.R;
|
||||
import com.limelight.nvstream.http.ComputerDetails;
|
||||
import com.limelight.nvstream.http.NvApp;
|
||||
|
||||
@@ -53,7 +53,11 @@ public class TvChannelHelper {
|
||||
intent.putExtra(TvContract.EXTRA_CHANNEL_ID, getChannelId(computer.uuid));
|
||||
try {
|
||||
context.startActivityForResult(intent, 0);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
} catch (Exception ignored) {
|
||||
// ActivityNotFoundException is the only officially documented
|
||||
// exception that can result from this call. However some buggy
|
||||
// devices throw others.
|
||||
// See https://github.com/moonlight-stream/moonlight-android/issues/1302
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,37 +29,43 @@ public class UiHelper {
|
||||
private static final int TV_VERTICAL_PADDING_DP = 15;
|
||||
private static final int TV_HORIZONTAL_PADDING_DP = 15;
|
||||
|
||||
private static void setGameModeStatus(Context context, boolean streaming, boolean loading, boolean interruptible) {
|
||||
private static void setGameModeStatus(Context context, boolean streaming, boolean interruptible) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
GameManager gameManager = context.getSystemService(GameManager.class);
|
||||
try {
|
||||
GameManager gameManager = context.getSystemService(GameManager.class);
|
||||
if (gameManager == null) {
|
||||
return; // Not supported on this device (e.g., Meta Quest)
|
||||
}
|
||||
|
||||
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));
|
||||
if (streaming) {
|
||||
gameManager.setGameState(new GameState(false, interruptible ? GameState.MODE_GAMEPLAY_INTERRUPTIBLE : GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE));
|
||||
} else {
|
||||
gameManager.setGameState(new GameState(false, GameState.MODE_NONE));
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Swallow any failure. Some OEM builds ship partial/incompatible GameManager impls.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void notifyStreamConnecting(Context context) {
|
||||
setGameModeStatus(context, true, true, true);
|
||||
setGameModeStatus(context, true, true);
|
||||
}
|
||||
|
||||
public static void notifyStreamConnected(Context context) {
|
||||
setGameModeStatus(context, true, false, false);
|
||||
setGameModeStatus(context, true, false);
|
||||
}
|
||||
|
||||
public static void notifyStreamEnteringPiP(Context context) {
|
||||
setGameModeStatus(context, true, false, true);
|
||||
setGameModeStatus(context, true, true);
|
||||
}
|
||||
|
||||
public static void notifyStreamExitingPiP(Context context) {
|
||||
setGameModeStatus(context, true, false, false);
|
||||
setGameModeStatus(context, true, false);
|
||||
}
|
||||
|
||||
public static void notifyStreamEnded(Context context) {
|
||||
setGameModeStatus(context, false, false, false);
|
||||
setGameModeStatus(context, false, false);
|
||||
}
|
||||
|
||||
public static void setLocale(Activity activity)
|
||||
@@ -115,7 +121,7 @@ public class UiHelper {
|
||||
UiModeManager modeMgr = (UiModeManager) activity.getSystemService(Context.UI_MODE_SERVICE);
|
||||
|
||||
// Set GameState.MODE_NONE initially for all activities
|
||||
setGameModeStatus(activity, false, false, false);
|
||||
setGameModeStatus(activity, false, false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
// Allow this non-streaming activity to layout under notches.
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
# Application.mk for Moonlight
|
||||
|
||||
# Our minimum version is Android 4.1
|
||||
APP_PLATFORM := android-16
|
||||
# Our minimum version is Android 5.0
|
||||
APP_PLATFORM := android-21
|
||||
|
||||
# We support 16KB pages
|
||||
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||
|
||||
@@ -28,7 +28,9 @@ LOCAL_SRC_FILES := moonlight-common-c/src/AudioStream.c \
|
||||
moonlight-common-c/src/SimpleStun.c \
|
||||
moonlight-common-c/src/VideoDepacketizer.c \
|
||||
moonlight-common-c/src/VideoStream.c \
|
||||
moonlight-common-c/reedsolomon/rs.c \
|
||||
moonlight-common-c/nanors/deps/obl/oblas_common.c \
|
||||
moonlight-common-c/nanors/deps/obl/oblas_lite.c \
|
||||
moonlight-common-c/nanors/rs.c \
|
||||
moonlight-common-c/enet/callbacks.c \
|
||||
moonlight-common-c/enet/compress.c \
|
||||
moonlight-common-c/enet/host.c \
|
||||
@@ -40,10 +42,12 @@ LOCAL_SRC_FILES := moonlight-common-c/src/AudioStream.c \
|
||||
moonlight-common-c/enet/win32.c \
|
||||
simplejni.c \
|
||||
callbacks.c \
|
||||
minisdl.c \
|
||||
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/moonlight-common-c/enet/include \
|
||||
$(LOCAL_PATH)/moonlight-common-c/reedsolomon \
|
||||
$(LOCAL_PATH)/moonlight-common-c/nanors/deps/obl \
|
||||
$(LOCAL_PATH)/moonlight-common-c/nanors \
|
||||
$(LOCAL_PATH)/moonlight-common-c/src \
|
||||
|
||||
LOCAL_CFLAGS := -DHAS_SOCKLEN_T=1 -DLC_ANDROID -DHAVE_CLOCK_GETTIME=1
|
||||
@@ -54,7 +58,11 @@ endif
|
||||
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libopus libssl libcrypto
|
||||
LOCAL_STATIC_LIBRARIES := libopus libcrypto cpufeatures
|
||||
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
||||
|
||||
LOCAL_BRANCH_PROTECTION := standard
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
$(call import-module,android/cpufeatures)
|
||||
@@ -0,0 +1 @@
|
||||
Static libraries were built from https://github.com/cgutman/moonlight-mobile-deps using AppVeyor CI
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <opus_multistream.h>
|
||||
#include <android/log.h>
|
||||
|
||||
#include <cpu-features.h>
|
||||
|
||||
static OpusMSDecoder* Decoder;
|
||||
static OPUS_MULTISTREAM_CONFIGURATION OpusConfig;
|
||||
|
||||
@@ -33,6 +35,9 @@ static jmethodID BridgeClConnectionTerminatedMethod;
|
||||
static jmethodID BridgeClRumbleMethod;
|
||||
static jmethodID BridgeClConnectionStatusUpdateMethod;
|
||||
static jmethodID BridgeClSetHdrModeMethod;
|
||||
static jmethodID BridgeClRumbleTriggersMethod;
|
||||
static jmethodID BridgeClSetMotionEventStateMethod;
|
||||
static jmethodID BridgeClSetControllerLEDMethod;
|
||||
static jbyteArray DecodedFrameBuffer;
|
||||
static jshortArray DecodedAudioBuffer;
|
||||
|
||||
@@ -80,7 +85,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
|
||||
BridgeDrStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStart", "()V");
|
||||
BridgeDrStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrStop", "()V");
|
||||
BridgeDrCleanupMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrCleanup", "()V");
|
||||
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIIJJ)I");
|
||||
BridgeDrSubmitDecodeUnitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeDrSubmitDecodeUnit", "([BIIIICJJ)I");
|
||||
BridgeArInitMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArInit", "(III)I");
|
||||
BridgeArStartMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStart", "()V");
|
||||
BridgeArStopMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeArStop", "()V");
|
||||
@@ -93,7 +98,10 @@ Java_com_limelight_nvstream_jni_MoonBridge_init(JNIEnv *env, jclass clazz) {
|
||||
BridgeClConnectionTerminatedMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionTerminated", "(I)V");
|
||||
BridgeClRumbleMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClRumble", "(SSS)V");
|
||||
BridgeClConnectionStatusUpdateMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClConnectionStatusUpdate", "(I)V");
|
||||
BridgeClSetHdrModeMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetHdrMode", "(Z)V");
|
||||
BridgeClSetHdrModeMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetHdrMode", "(Z[B)V");
|
||||
BridgeClRumbleTriggersMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClRumbleTriggers", "(SSS)V");
|
||||
BridgeClSetMotionEventStateMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetMotionEventState", "(SBS)V");
|
||||
BridgeClSetControllerLEDMethod = (*env)->GetStaticMethodID(env, clazz, "bridgeClSetControllerLED", "(SBBB)V");
|
||||
}
|
||||
|
||||
int BridgeDrSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags) {
|
||||
@@ -159,8 +167,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
|
||||
|
||||
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
|
||||
DecodedFrameBuffer, currentEntry->length, currentEntry->bufferType,
|
||||
decodeUnit->frameNumber, decodeUnit->frameType,
|
||||
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
|
||||
decodeUnit->frameNumber, decodeUnit->frameType, (jchar)decodeUnit->frameHostProcessingLatency,
|
||||
(jlong)decodeUnit->receiveTimeUs, (jlong)decodeUnit->enqueueTimeUs);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
@@ -180,8 +188,8 @@ int BridgeDrSubmitDecodeUnit(PDECODE_UNIT decodeUnit) {
|
||||
|
||||
ret = (*env)->CallStaticIntMethod(env, GlobalBridgeClass, BridgeDrSubmitDecodeUnitMethod,
|
||||
DecodedFrameBuffer, offset, BUFFER_TYPE_PICDATA,
|
||||
decodeUnit->frameNumber, decodeUnit->frameType,
|
||||
(jlong)decodeUnit->receiveTimeMs, (jlong)decodeUnit->enqueueTimeMs);
|
||||
decodeUnit->frameNumber, decodeUnit->frameType, (jchar)decodeUnit->frameHostProcessingLatency,
|
||||
(jlong)decodeUnit->receiveTimeUs, (jlong)decodeUnit->enqueueTimeUs);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
@@ -331,7 +339,50 @@ void BridgeClConnectionStatusUpdate(int connectionStatus) {
|
||||
void BridgeClSetHdrMode(bool enabled) {
|
||||
JNIEnv* env = GetThreadEnv();
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetHdrModeMethod, enabled);
|
||||
jbyteArray hdrMetadataByteArray = NULL;
|
||||
SS_HDR_METADATA hdrMetadata;
|
||||
|
||||
// Check if HDR metadata was provided
|
||||
if (enabled && LiGetHdrMetadata(&hdrMetadata)) {
|
||||
hdrMetadataByteArray = (*env)->NewByteArray(env, sizeof(SS_HDR_METADATA));
|
||||
(*env)->SetByteArrayRegion(env, hdrMetadataByteArray, 0, sizeof(SS_HDR_METADATA), (jbyte*)&hdrMetadata);
|
||||
}
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetHdrModeMethod, enabled, hdrMetadataByteArray);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
}
|
||||
}
|
||||
|
||||
void BridgeClRumbleTriggers(unsigned short controllerNumber, unsigned short leftTrigger, unsigned short rightTrigger) {
|
||||
JNIEnv* env = GetThreadEnv();
|
||||
|
||||
// The seemingly redundant short casts are required in order to convert the unsigned short to a signed short.
|
||||
// If we leave it as an unsigned short, CheckJNI will fail when the value exceeds 32767. The cast itself is
|
||||
// fine because the Java code treats the value as unsigned even though it's stored in a signed type.
|
||||
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClRumbleTriggersMethod, controllerNumber, (short)leftTrigger, (short)rightTrigger);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
}
|
||||
}
|
||||
|
||||
void BridgeClSetMotionEventState(uint16_t controllerNumber, uint8_t motionType, uint16_t reportRateHz) {
|
||||
JNIEnv* env = GetThreadEnv();
|
||||
|
||||
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetMotionEventStateMethod, controllerNumber, motionType, reportRateHz);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
}
|
||||
}
|
||||
|
||||
void BridgeClSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g, uint8_t b) {
|
||||
JNIEnv* env = GetThreadEnv();
|
||||
|
||||
// These jbyte casts are necessary to satisfy CheckJNI
|
||||
(*env)->CallStaticVoidMethod(env, GlobalBridgeClass, BridgeClSetControllerLEDMethod, controllerNumber, (jbyte)r, (jbyte)g, (jbyte)b);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
// We will crash here
|
||||
(*JVM)->DetachCurrentThread(JVM);
|
||||
@@ -372,19 +423,42 @@ static CONNECTION_LISTENER_CALLBACKS BridgeConnListenerCallbacks = {
|
||||
.rumble = BridgeClRumble,
|
||||
.connectionStatusUpdate = BridgeClConnectionStatusUpdate,
|
||||
.setHdrMode = BridgeClSetHdrMode,
|
||||
.rumbleTriggers = BridgeClRumbleTriggers,
|
||||
.setMotionEventState = BridgeClSetMotionEventState,
|
||||
.setControllerLED = BridgeClSetControllerLED,
|
||||
};
|
||||
|
||||
static bool
|
||||
hasFastAes() {
|
||||
if (android_getCpuCount() <= 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (android_getCpuFamily()) {
|
||||
case ANDROID_CPU_FAMILY_ARM:
|
||||
return !!(android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_AES);
|
||||
case ANDROID_CPU_FAMILY_ARM64:
|
||||
return !!(android_getCpuFeatures() & ANDROID_CPU_ARM64_FEATURE_AES);
|
||||
case ANDROID_CPU_FAMILY_X86:
|
||||
case ANDROID_CPU_FAMILY_X86_64:
|
||||
return !!(android_getCpuFeatures() & ANDROID_CPU_X86_FEATURE_AES_NI);
|
||||
case ANDROID_CPU_FAMILY_MIPS:
|
||||
case ANDROID_CPU_FAMILY_MIPS64:
|
||||
return false;
|
||||
default:
|
||||
// Assume new architectures will all have crypto acceleration (RISC-V will)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass clazz,
|
||||
jstring address, jstring appVersion, jstring gfeVersion,
|
||||
jstring rtspSessionUrl,
|
||||
jstring rtspSessionUrl, jint serverCodecModeSupport,
|
||||
jint width, jint height, jint fps,
|
||||
jint bitrate, jint packetSize, jint streamingRemotely,
|
||||
jint audioConfiguration, jboolean supportsHevc,
|
||||
jboolean enableHdr,
|
||||
jint hevcBitratePercentageMultiplier,
|
||||
jint audioConfiguration, jint supportedVideoFormats,
|
||||
jint clientRefreshRateX100,
|
||||
jint encryptionFlags,
|
||||
jbyteArray riAesKey, jbyteArray riAesIv,
|
||||
jint videoCapabilities,
|
||||
jint colorSpace, jint colorRange) {
|
||||
@@ -393,6 +467,7 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
||||
.serverInfoAppVersion = (*env)->GetStringUTFChars(env, appVersion, 0),
|
||||
.serverInfoGfeVersion = gfeVersion ? (*env)->GetStringUTFChars(env, gfeVersion, 0) : NULL,
|
||||
.rtspSessionUrl = rtspSessionUrl ? (*env)->GetStringUTFChars(env, rtspSessionUrl, 0) : NULL,
|
||||
.serverCodecModeSupport = serverCodecModeSupport,
|
||||
};
|
||||
STREAM_CONFIGURATION streamConfig = {
|
||||
.width = width,
|
||||
@@ -402,11 +477,9 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
||||
.packetSize = packetSize,
|
||||
.streamingRemotely = streamingRemotely,
|
||||
.audioConfiguration = audioConfiguration,
|
||||
.supportsHevc = supportsHevc,
|
||||
.enableHdr = enableHdr,
|
||||
.hevcBitratePercentageMultiplier = hevcBitratePercentageMultiplier,
|
||||
.supportedVideoFormats = supportedVideoFormats,
|
||||
.clientRefreshRateX100 = clientRefreshRateX100,
|
||||
.encryptionFlags = encryptionFlags,
|
||||
.encryptionFlags = ENCFLG_AUDIO,
|
||||
.colorSpace = colorSpace,
|
||||
.colorRange = colorRange
|
||||
};
|
||||
@@ -421,6 +494,11 @@ Java_com_limelight_nvstream_jni_MoonBridge_startConnection(JNIEnv *env, jclass c
|
||||
|
||||
BridgeVideoRendererCallbacks.capabilities = videoCapabilities;
|
||||
|
||||
// Enable all encryption features if the platform has fast AES support
|
||||
if (hasFastAes()) {
|
||||
streamConfig.encryptionFlags = ENCFLG_ALL;
|
||||
}
|
||||
|
||||
int ret = LiStartConnection(&serverInfo,
|
||||
&streamConfig,
|
||||
&BridgeConnListenerCallbacks,
|
||||
|
||||
@@ -0,0 +1,677 @@
|
||||
/*
|
||||
Copyright (C) Valve Corporation
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#define MAKE_CONTROLLER_ID( nVID, nPID ) (unsigned int)( (unsigned int)nVID << 16 | (unsigned int)nPID )
|
||||
|
||||
static const ControllerDescription_t arrControllers[] = {
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x181a ), k_eControllerType_PS3Controller, NULL }, // Venom Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x044f, 0xb315 ), k_eControllerType_PS3Controller, NULL }, // Firestorm Dual Analog 3
|
||||
{ MAKE_CONTROLLER_ID( 0x044f, 0xd007 ), k_eControllerType_PS3Controller, NULL }, // Thrustmaster wireless 3-1
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xcad1 ), k_eControllerType_PS3Controller, NULL }, // Logitech Chillstream
|
||||
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc24f ), k_eControllerType_PS3Controller, NULL }, // Logitech G29 (PS3)
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x0268 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x056e, 0x200f ), k_eControllerType_PS3Controller, NULL }, // From SDL
|
||||
{ MAKE_CONTROLLER_ID( 0x056e, 0x2013 ), k_eControllerType_PS3Controller, NULL }, // JC-U4113SBK
|
||||
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1004 ), k_eControllerType_PS3Controller, NULL }, // From SDL
|
||||
{ MAKE_CONTROLLER_ID( 0x05b8, 0x1006 ), k_eControllerType_PS3Controller, NULL }, // JC-U3412SBK
|
||||
{ MAKE_CONTROLLER_ID( 0x06a3, 0xf622 ), k_eControllerType_PS3Controller, NULL }, // Cyborg V3
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x3180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS3 mode
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x3250 ), k_eControllerType_PS3Controller, NULL }, // madcats fightpad pro ps3
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x3481 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz FightStick TE 2+ PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8180 ), k_eControllerType_PS3Controller, NULL }, // Mad Catz Alpha PS4 mode (no touchpad on device)
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8838 ), k_eControllerType_PS3Controller, NULL }, // Madcatz Fightstick Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x0810, 0x0001 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
|
||||
{ MAKE_CONTROLLER_ID( 0x0810, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // actually ps2 - maybe break out later
|
||||
{ MAKE_CONTROLLER_ID( 0x0925, 0x0005 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0925, 0x8866 ), k_eControllerType_PS3Controller, NULL }, // PS2 maybe break out later
|
||||
{ MAKE_CONTROLLER_ID( 0x0925, 0x8888 ), k_eControllerType_PS3Controller, NULL }, // Actually ps2 -maybe break out later Lakeview Research WiseGroup Ltd, MP-8866 Dual Joypad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0109 ), k_eControllerType_PS3Controller, NULL }, // PDP Versus Fighting Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011e ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0128 ), k_eControllerType_PS3Controller, NULL }, // Rock Candy PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0214 ), k_eControllerType_PS3Controller, NULL }, // afterglow ps3
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1314 ), k_eControllerType_PS3Controller, NULL }, // PDP Afterglow Wireless PS3 controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x6302 ), k_eControllerType_PS3Controller, NULL }, // From SDL
|
||||
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x0008 ), k_eControllerType_PS3Controller, NULL }, // Green Asia
|
||||
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x3075 ), k_eControllerType_PS3Controller, NULL }, // SpeedLink Strike FX
|
||||
{ MAKE_CONTROLLER_ID( 0x0e8f, 0x310d ), k_eControllerType_PS3Controller, NULL }, // From SDL
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0009 ), k_eControllerType_PS3Controller, NULL }, // HORI BDA GP1
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x004d ), k_eControllerType_PS3Controller, NULL }, // Horipad 3
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005f ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander 4 PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006a ), k_eControllerType_PS3Controller, NULL }, // Real Arcade Pro 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006e ), k_eControllerType_PS3Controller, NULL }, // HORI horipad4 ps3
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0085 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0086 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Commander PC (Uses the Xbox 360 protocol, but has PS3 buttons)
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0088 ), k_eControllerType_PS3Controller, NULL }, // HORI Fighting Stick mini 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f30, 0x1100 ), k_eControllerType_PS3Controller, NULL }, // Qanba Q1 fight stick
|
||||
{ MAKE_CONTROLLER_ID( 0x11ff, 0x3331 ), k_eControllerType_PS3Controller, NULL }, // SRXJ-PH2400
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0100 ), k_eControllerType_PS3Controller, NULL }, // PS3 Guitar Hero Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0120 ), k_eControllerType_PS3Controller, NULL }, // PS3 Guitar Hero Drums
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0140 ), k_eControllerType_PS3Controller, NULL }, // PS3 DJ Hero Turntable
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0200 ), k_eControllerType_PS3Controller, NULL }, // PS3 Rock Band Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0210 ), k_eControllerType_PS3Controller, NULL }, // PS3 Rock Band Drums
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x0218 ), k_eControllerType_PS3Controller, NULL }, // PS3 Midi Pro Adapter - Drums Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x074b ), k_eControllerType_PS3Controller, NULL }, // PS3 / Wii U Guitar Hero Live Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2330 ), k_eControllerType_PS3Controller, NULL }, // PS3 Rock Band Keyboard
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2338 ), k_eControllerType_PS3Controller, NULL }, // PS3 Midi Pro Adapter - Keyboard Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2430 ), k_eControllerType_PS3Controller, NULL }, // PS3 Mustang Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2438 ), k_eControllerType_PS3Controller, NULL }, // PS3 Midi Pro Adapter - Mustang Guitar Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2530 ), k_eControllerType_PS3Controller, NULL }, // PS3 Squire Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x12ba, 0x2538 ), k_eControllerType_PS3Controller, NULL }, // PS3 Midi Pro Adapter - Squire Guitar Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x1345, 0x1000 ), k_eControllerType_PS3Controller, NULL }, // PS2 ACME GA-D5
|
||||
{ MAKE_CONTROLLER_ID( 0x1345, 0x6005 ), k_eControllerType_PS3Controller, NULL }, // ps2 maybe break out later
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // From SDL
|
||||
{ MAKE_CONTROLLER_ID( 0x1a34, 0x0836 ), k_eControllerType_PS3Controller, NULL }, // Afterglow PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x0004 ), k_eControllerType_PS3Controller, NULL }, // Wii RB1 Guitar (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x0005 ), k_eControllerType_PS3Controller, NULL }, // Wii RB1 Drums (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3010 ), k_eControllerType_PS3Controller, NULL }, // Wii RB2 Guitar (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3110 ), k_eControllerType_PS3Controller, NULL }, // Wii RB2 Drums (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3138 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Midi Pro Adapter - Drums Mode (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3330 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Keyboard (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3338 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Midi Pro Adapter - Keyboard Mode (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3430 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Mustang Guitar (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3438 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Midi Pro Adapter - Mustang Guitar Mode (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3530 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Squire Guitar (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x1BAD, 0x3538 ), k_eControllerType_PS3Controller, NULL }, // Wii RB3 Midi Pro Adapter - Squire Guitar Mode (Uses PS3 protocol)
|
||||
{ MAKE_CONTROLLER_ID( 0x20bc, 0x5500 ), k_eControllerType_PS3Controller, NULL }, // ShanWan PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x576d ), k_eControllerType_PS3Controller, NULL }, // Power A PS3
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xca6d ), k_eControllerType_PS3Controller, NULL }, // BDA Pro Ex
|
||||
{ MAKE_CONTROLLER_ID( 0x2563, 0x0523 ), k_eControllerType_PS3Controller, NULL }, // Digiflip GP006
|
||||
{ MAKE_CONTROLLER_ID( 0x2563, 0x0575 ), k_eControllerType_PS3Controller, "Retro Controller" }, // SWITCH CO., LTD. Retro-bit, Retro Fighters Controllers
|
||||
{ MAKE_CONTROLLER_ID( 0x25f0, 0x83c3 ), k_eControllerType_PS3Controller, NULL }, // gioteck vx2
|
||||
{ MAKE_CONTROLLER_ID( 0x25f0, 0xc121 ), k_eControllerType_PS3Controller, NULL }, //
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2003 ), k_eControllerType_PS3Controller, NULL }, // Qanba Drone
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2302 ), k_eControllerType_PS3Controller, NULL }, // Qanba Obsidian
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2502 ), k_eControllerType_PS3Controller, NULL }, // Qanba Dragon
|
||||
{ MAKE_CONTROLLER_ID( 0x8380, 0x0003 ), k_eControllerType_PS3Controller, NULL }, // BTP 2163
|
||||
{ MAKE_CONTROLLER_ID( 0x8888, 0x0308 ), k_eControllerType_PS3Controller, NULL }, // Sony PS3 Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x181b ), k_eControllerType_PS4Controller, NULL }, // Venom Arcade Stick - XXX:this may not work and may need to be called a ps3 controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x046d, 0xc260 ), k_eControllerType_PS4Controller, NULL }, // Logitech G29 (PS4)
|
||||
{ MAKE_CONTROLLER_ID( 0x044f, 0xd00e ), k_eControllerType_PS4Controller, NULL }, // Thrustmaster Eswap Pro - No gyro and lightbar doesn't change color. Works otherwise
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c4 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x05c5 ), k_eControllerType_PS4Controller, NULL }, // STRIKEPAD PS4 Grip Add-on
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x09cc ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Slim Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ba0 ), k_eControllerType_PS4Controller, NULL }, // Sony PS4 Controller (Wireless dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8250 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightPad Pro PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8384 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE S+ PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8480 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2 PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x8481 ), k_eControllerType_PS4Controller, NULL }, // Mad Catz FightStick TE 2+ PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e10 ), k_eControllerType_PS4Controller, NULL }, // Armor Armor 3 Pad PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e13 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e15 ), k_eControllerType_PS4Controller, NULL }, // Game:Pad 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0e20 ), k_eControllerType_PS4Controller, NULL }, // Brook Mars Controller - needs FW update to show up as Ps4 controller on PC. Has Gyro but touchpad is a single button.
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef6 ), k_eControllerType_PS4Controller, NULL }, // Hitbox Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1cf6 ), k_eControllerType_PS4Controller, NULL }, // EMIO PS4 Elite Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x1e10 ), k_eControllerType_PS4Controller, NULL }, // P4 Wired Gamepad generic knock off - lightbar but not trackpad or gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x2e18 ), k_eControllerType_PS4Controller, NULL }, // ZEROPLUS P4 Wired Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0203 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS (PS4 peripheral but no trackpad/lightbar)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0207 ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS V2 w/ Touchpad for PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x020a ), k_eControllerType_PS4Controller, NULL }, // Victrix Pro FS PS4/PS5 (PS4 mode)
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0055 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x005e ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander 4 PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0066 ), k_eControllerType_PS4Controller, NULL }, // HORIPAD 4 FPS Plus
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0084 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0087 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Stick mini 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008a ), k_eControllerType_PS4Controller, NULL }, // HORI Real Arcade Pro 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x009c ), k_eControllerType_PS4Controller, NULL }, // HORI TAC PRO mousething
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a0 ), k_eControllerType_PS4Controller, NULL }, // HORI TAC4 mousething
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ed ), k_eControllerType_XInputPS4Controller, NULL }, // Hori Fighting Stick mini 4 kai - becomes an Xbox 360 controller on PC
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ee ), k_eControllerType_PS4Controller, NULL }, // Hori mini wired https://www.playstation.com/en-us/explore/accessories/gaming-controllers/mini-wired-gamepad/
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011c ), k_eControllerType_PS4Controller, NULL }, // Hori Fighting Stick α
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0123 ), k_eControllerType_PS4Controller, NULL }, // HORI Wireless Controller Light (Japan only) - only over bt- over usb is xbox and pid 0x0124
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0162 ), k_eControllerType_PS4Controller, NULL }, // HORI Fighting Commander OCTA
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0164 ), k_eControllerType_XInputPS4Controller, NULL }, // HORI Fighting Commander OCTA
|
||||
{ MAKE_CONTROLLER_ID( 0x11c0, 0x4001 ), k_eControllerType_PS4Controller, NULL }, // "PS4 Fun Controller" added from user log
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0603 ), k_eControllerType_XInputPS4Controller, NULL }, // Nacon PS4 Compact Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0604 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Daija Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0605 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON PS4 controller in Xbox mode - might also be other bigben brand xbox controllers
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0606 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0609 ), k_eControllerType_XInputPS4Controller, NULL }, // NACON Wireless Controller for PS4
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d01 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller - has gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d02 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller v2 - has gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d06 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymmetric Controller Wireless Dongle -- show up as ps4 until you connect controller to it then it reboots into Xbox controller with different vvid/pid
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d08 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited Wireless Dongle
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d09 ), k_eControllerType_PS4Controller, NULL }, // NACON Daija Fight Stick - touchpad but no gyro/rumble
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Infinite - has gyro
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d10 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Unlimited
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0d13 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution Pro Controller 3
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x1103 ), k_eControllerType_PS4Controller, NULL }, // NACON Asymmetric Controller -- on windows this doesn't enumerate
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0X0401 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera PS4 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1000 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju PS4 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1004 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate USB
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1007 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition USB
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1008 ), k_eControllerType_PS4Controller, NULL }, // Razer Panthera Evo Fightstick
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1009 ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Ultimate BT
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x100A ), k_eControllerType_PS4Controller, NULL }, // Razer Raiju 2 Tournament edition BT
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1100 ), k_eControllerType_PS4Controller, NULL }, // Razer RAION Fightpad - Trackpad, no gyro, lightbar hardcoded to green
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x792a ), k_eControllerType_PS4Controller, NULL }, // PowerA Fusion Fight Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2000 ), k_eControllerType_PS4Controller, NULL }, // Qanba Drone
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2300 ), k_eControllerType_PS4Controller, NULL }, // Qanba Obsidian
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2303 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Obsidian Arcade Joystick
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2500 ), k_eControllerType_PS4Controller, NULL }, // Qanba Dragon
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2503 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Dragon Arcade Joystick
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d16 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution 5 Pro (PS4 mode with dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d17 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution 5 Pro (PS4 mode wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x7545, 0x0104 ), k_eControllerType_PS4Controller, NULL }, // Armor 3 or Level Up Cobra - At least one variant has gyro
|
||||
{ MAKE_CONTROLLER_ID (0x9886, 0x0024 ), k_eControllerType_XInputPS4Controller, NULL }, // Astro C40 in Xbox 360 mode
|
||||
{ MAKE_CONTROLLER_ID( 0x9886, 0x0025 ), k_eControllerType_PS4Controller, NULL }, // Astro C40
|
||||
// Removing the Giotek because there were a bunch of help tickets from users w/ issues including from non-PS4 controller users. This VID/PID is probably used in different FW's
|
||||
// { MAKE_CONTROLLER_ID( 0x7545, 0x1122 ), k_eControllerType_PS4Controller, NULL }, // Giotek VX4 - trackpad/gyro don't work. Had to not filter on interface info. Light bar is flaky, but works.
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x0ce6 ), k_eControllerType_PS5Controller, NULL }, // Sony DualSense Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x0e5f ), k_eControllerType_PS5Controller, NULL }, // Access Controller for PS5
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0209 ), k_eControllerType_PS5Controller, NULL }, // Victrix Pro FS PS4/PS5 (PS5 mode)
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0163 ), k_eControllerType_PS5Controller, NULL }, // HORI Fighting Commander OCTA
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0184 ), k_eControllerType_PS5Controller, NULL }, // Hori Fighting Stick α
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x100b ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x100c ), k_eControllerType_PS5Controller, NULL }, // Razer Wolverine V2 Pro (Wireless)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1012 ), k_eControllerType_PS5Controller, NULL }, // Razer Kitsune
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1024 ), k_eControllerType_PS5Controller, NULL }, // Razer Raiju V3 Pro (PS5 mode wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x1026 ), k_eControllerType_PS5Controller, NULL }, // Razer Raiju V3 Pro (PS5 mode with dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d18 ), k_eControllerType_PS5Controller, NULL }, // NACON Revolution 5 Pro (PS5 mode with dongle)
|
||||
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d19 ), k_eControllerType_PS5Controller, NULL }, // NACON Revolution 5 Pro (PS5 mode wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x358a, 0x0104 ), k_eControllerType_PS5Controller, NULL }, // Backbone One PlayStation Edition for iOS
|
||||
{ MAKE_CONTROLLER_ID( 0x358a, 0x0304 ), k_eControllerType_PS5Controller, NULL }, // Backbone One PlayStation Edition Gen 2
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x0006 ), k_eControllerType_UnknownNonSteamController, NULL }, // DragonRise Generic USB PCB, sometimes configured as a PC Twin Shock Controller - looks like a DS3 but the face buttons are 1-4 instead of symbols
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d4 ), k_eControllerType_XBox360Controller, NULL }, // GPD Win 2 X-Box Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0351, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x0351, 0x2000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff02 ), k_eControllerType_XBox360Controller, NULL }, // Wooting Two
|
||||
{ MAKE_CONTROLLER_ID( 0x044f, 0xb326 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Gamepad GP XID
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x028e ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft Xbox 360 Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x028f ), k_eControllerType_XBox360Controller, "Xbox 360 Controller" }, // Microsoft Xbox 360 Play and Charge Cable
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0291 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // X-box 360 Wireless Receiver (third party knockoff)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // Microsoft Xbox 360 Big Button IR
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a1 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Microsoft Xbox 360 Wireless Controller with XUSB driver on Windows
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a2 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Racing Wheel" }, // Xbox 360 Wireless Racing Wheel with XUSB driver on Windows
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02a9 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // X-box 360 Wireless Receiver (third party knockoff)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0719 ), k_eControllerType_XBox360Controller, "Xbox 360 Wireless Controller" }, // Microsoft Xbox 360 Wireless Receiver
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21d ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F310
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21e ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F510
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xc21f ), k_eControllerType_XBox360Controller, NULL }, // Logitech Gamepad F710
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xc242 ), k_eControllerType_XBox360Controller, NULL }, // Logitech Chillstream Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x056e, 0x2004 ), k_eControllerType_XBox360Controller, NULL }, // Elecom JC-U3613M
|
||||
// This isn't actually an Xbox 360 controller, it just looks like one
|
||||
// { MAKE_CONTROLLER_ID( 0x06a3, 0xf51a ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3600
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x02A6 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wireless Rock Band Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x02AB ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wireless Precision Bass Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4716 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4718 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightStick SE
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4728 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV FightPad
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4736 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4738 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Wired Xbox 360 Controller (SFIV)
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4740 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Beat Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x9806 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Precision Bass Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0xb726 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox controller - MW2
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz JOYTECH NEO SE Advanced GamePad
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb02 ), k_eControllerType_XBox360Controller, NULL }, // Saitek Cyborg Rumble Pad - PC/Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0xcb03 ), k_eControllerType_XBox360Controller, NULL }, // Saitek P3200 Rumble Pad - PC/Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0xf738 ), k_eControllerType_XBox360Controller, NULL }, // Super SFIV FightStick TE S
|
||||
{ MAKE_CONTROLLER_ID( 0x0955, 0x7210 ), k_eControllerType_XBox360Controller, NULL }, // Nvidia Shield local controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0955, 0xb400 ), k_eControllerType_XBox360Controller, NULL }, // NVIDIA Shield streaming controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0b05, 0x1b4c ), k_eControllerType_XBox360Controller, NULL }, // ASUS ROG Ally X built-in controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0105 ), k_eControllerType_XBox360Controller, NULL }, // HSM3 Xbox360 dancepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0113 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x011f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0125 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightStick" }, // PDP INJUSTICE FightStick for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0127 ), k_eControllerType_XBox360Controller, "PDP INJUSTICE FightPad" }, // PDP INJUSTICE FightPad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0131 ), k_eControllerType_XBox360Controller, "PDP EA Soccer Controller" }, // PDP EA Soccer Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0133 ), k_eControllerType_XBox360Controller, "PDP Battlefield 4 Controller" }, // PDP Battlefield 4 Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0143 ), k_eControllerType_XBox360Controller, "PDP MK X Fight Stick" }, // PDP MK X Fight Stick for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0147 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Marvel Controller" }, // PDP Marvel Controller for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0201 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0213 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x021f ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Rock Candy" }, // PDP Rock Candy Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0301 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0313 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0314 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Afterglow" }, // PDP Afterglow Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0401 ), k_eControllerType_XBox360Controller, "PDP Xbox 360 Controller" }, // PDP Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0413 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0501 ), k_eControllerType_XBox360Controller, NULL }, // PDP Xbox 360 Controller (unlisted)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // PDP Afterglow AX.1 (unlisted)
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000a ), k_eControllerType_XBox360Controller, NULL }, // Hori Co. DOA4 FightStick
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000c ), k_eControllerType_XBox360Controller, NULL }, // Hori PadEX Turbo
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x000d ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0016 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x001b ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x008c ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro 4
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00db ), k_eControllerType_XBox360Controller, "HORI Slime Controller" }, // Hori Dragon Quest Slime Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x011e ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick α
|
||||
{ MAKE_CONTROLLER_ID( 0x1038, 0x1430 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
|
||||
{ MAKE_CONTROLLER_ID( 0x1038, 0x1431 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo
|
||||
{ MAKE_CONTROLLER_ID( 0x1038, 0xb360 ), k_eControllerType_XBox360Controller, NULL }, // SteelSeries Nimbus/Stratus XL
|
||||
{ MAKE_CONTROLLER_ID( 0x11c9, 0x55f0 ), k_eControllerType_XBox360Controller, NULL }, // Nacon GC-100XF
|
||||
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0004 ), k_eControllerType_XBox360Controller, NULL }, // Honey Bee Xbox360 dancepad
|
||||
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // PDP AFTERGLOW AX.1
|
||||
{ MAKE_CONTROLLER_ID( 0x12ab, 0x0303 ), k_eControllerType_XBox360Controller, NULL }, // Mortal Kombat Klassic FightStick
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x02a0 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller Adapter
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x02a7 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Wireless Guitar (Linux)
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x02a8 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Wireless Drum Kit (Linux)
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x0705 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero 5 Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x070B ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero Live Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x0805 ), k_eControllerType_XBox360Controller, NULL }, // Band Hero Wireless Drum Kit
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x1715 ), k_eControllerType_XBox360Controller, NULL }, // DJ Hero Turntable (Wired)
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x1705 ), k_eControllerType_XBox360Controller, NULL }, // DJ Hero Turntable (Wireless)
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x4734 ), k_eControllerType_XBox360Controller, NULL }, // Guitar Hero World Tour Kiosk
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x4748 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Guitar Hero X-plorer
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0xf801 ), k_eControllerType_XBox360Controller, NULL }, // RedOctane Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0601 ), k_eControllerType_XBox360Controller, NULL }, // BigBen Interactive XBOX 360 Controller
|
||||
// { MAKE_CONTROLLER_ID( 0x1532, 0x0037 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
|
||||
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f00 ), k_eControllerType_XBox360Controller, NULL }, // Power A Mini Pro Elite
|
||||
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f0a ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
|
||||
{ MAKE_CONTROLLER_ID( 0x15e4, 0x3f10 ), k_eControllerType_XBox360Controller, NULL }, // Batarang Xbox 360 controller
|
||||
{ MAKE_CONTROLLER_ID( 0x162e, 0xbeef ), k_eControllerType_XBox360Controller, NULL }, // Joytech Neo-Se Take2
|
||||
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Tournament Edition
|
||||
{ MAKE_CONTROLLER_ID( 0x1689, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza Classic Edition
|
||||
{ MAKE_CONTROLLER_ID( 0x1689, 0xfe00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
|
||||
{ MAKE_CONTROLLER_ID( 0x1949, 0x041a ), k_eControllerType_XBox360Controller, "Amazon Luna Controller" }, // Amazon Luna Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band 1 Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0003 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Rock Band Drumkit
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x0130 ), k_eControllerType_XBox360Controller, NULL }, // ION Drum Rocker
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x02a6 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band 2 Wireless Guitar (Linux)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x02ab ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Wireless Bass Guitar (Linux)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1330 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Keyboard (Mustang)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1338 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Keyboard)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1430 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Pro Guitar (Mustang)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1530 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band Pro Guitar (Squire)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1438 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Mustang Guitar)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x1538 ), k_eControllerType_XBox360Controller, NULL }, // Rock Band MIDI Pro Adapter (Squire Guitar)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf016 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Xbox 360 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf018 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Street Fighter IV SE Fighting Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf019 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Brawlstick for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf021 ), k_eControllerType_XBox360Controller, NULL }, // Mad Cats Ghost Recon FS GamePad
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf023 ), k_eControllerType_XBox360Controller, NULL }, // MLG Pro Circuit Controller (Xbox)
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf025 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Call Of Duty
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf027 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FPS Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf028 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightPad
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf02e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Fightpad
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf036 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MicroCon GamePad Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf038 ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV FightStick TE
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf039 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MvC2 TE
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03a ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz SFxT Fightstick Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03d ), k_eControllerType_XBox360Controller, NULL }, // Street Fighter IV Arcade Stick TE - Chun Li
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03e ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz MLG FightStick TE
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf03f ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick SoulCaliber
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf042 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TES+
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf080 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz FightStick TE2
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf501 ), k_eControllerType_XBox360Controller, NULL }, // HoriPad EX2 Turbo
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.VX SA
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf504 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro. EX
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf505 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick EX2B
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf506 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro.EX Premium VLX
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf900 ), k_eControllerType_XBox360Controller, NULL }, // Harmonix Xbox 360 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf901 ), k_eControllerType_XBox360Controller, NULL }, // Gamestop Xbox 360 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf902 ), k_eControllerType_XBox360Controller, NULL }, // Mad Catz Gamepad2
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf903 ), k_eControllerType_XBox360Controller, NULL }, // Tron Xbox 360 controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf904 ), k_eControllerType_XBox360Controller, NULL }, // PDP Versus Fighting Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xf906 ), k_eControllerType_XBox360Controller, NULL }, // MortalKombat FightStick
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfa01 ), k_eControllerType_XBox360Controller, NULL }, // MadCatz GamePad
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd00 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza TE
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0xfd01 ), k_eControllerType_XBox360Controller, NULL }, // Razer Onza
|
||||
{ MAKE_CONTROLLER_ID( 0x2068, 0x0001 ), k_eControllerType_XBox360Controller, NULL }, // Power Gig Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x2068, 0x0002 ), k_eControllerType_XBox360Controller, NULL }, // Power Gig Drums
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5000 ), k_eControllerType_XBox360Controller, NULL }, // Razer Atrox Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5300 ), k_eControllerType_XBox360Controller, NULL }, // PowerA MINI PROEX Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5303 ), k_eControllerType_XBox360Controller, NULL }, // Xbox Airflo wired controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x530a ), k_eControllerType_XBox360Controller, NULL }, // Xbox 360 Pro EX Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x531a ), k_eControllerType_XBox360Controller, NULL }, // PowerA Pro Ex
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5397 ), k_eControllerType_XBox360Controller, NULL }, // FUS1ON Tournament Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5500 ), k_eControllerType_XBox360Controller, NULL }, // Hori XBOX 360 EX 2 with Turbo
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5501 ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX-SA
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5502 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick VX Alt
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5503 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Edge
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5506 ), k_eControllerType_XBox360Controller, NULL }, // Hori SOULCALIBUR V Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550d ), k_eControllerType_XBox360Controller, NULL }, // Hori GEM Xbox controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x550e ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro V Kai 360
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5508 ), k_eControllerType_XBox360Controller, NULL }, // Hori PAD A
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5510 ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Commander ONE
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b00 ), k_eControllerType_XBox360Controller, NULL }, // ThrustMaster Ferrari Italia 458 Racing Wheel
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b02 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster, Inc. GPX Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5b03 ), k_eControllerType_XBox360Controller, NULL }, // Thrustmaster Ferrari 458 Racing Wheel
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5d04 ), k_eControllerType_XBox360Controller, NULL }, // Razer Sabertooth
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafa ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafb ), k_eControllerType_XBox360Controller, NULL }, // Aplay Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafc ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 1
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafd ), k_eControllerType_XBox360Controller, NULL }, // Afterglow Gamepad 3
|
||||
{ MAKE_CONTROLLER_ID( 0x3537, 0x103e ), k_eControllerType_XBox360Controller, "Gamesir Xbox Controller" }, // Gamesir dongle for Supernova (and maybe others) in Xinput mode
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfafe ), k_eControllerType_XBox360Controller, NULL }, // Rock Candy Gamepad for Xbox 360
|
||||
{ MAKE_CONTROLLER_ID( 0x3651, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar
|
||||
{ MAKE_CONTROLLER_ID( 0x3651, 0x6000 ), k_eControllerType_XBox360Controller, NULL }, // CRKD Guitar
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x03f0, 0x0495 ), k_eControllerType_XBoxOneController, NULL }, // HP HyperX Clutch Gladiate
|
||||
{ MAKE_CONTROLLER_ID( 0x044f, 0xd012 ), k_eControllerType_XBoxOneController, NULL }, // ThrustMaster eSwap PRO Controller Xbox
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02d1 ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft Xbox One Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02dd ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft Xbox One Controller (Firmware 2015)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e0 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft Xbox One S Controller (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ea ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft Xbox One S Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02fd ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft Xbox One S Controller (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02ff ), k_eControllerType_XBoxOneController, "Xbox One Controller" }, // Microsoft Xbox One Controller with XBOXGIP driver on Windows
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0a ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft Xbox Adaptive Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b0c ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft Xbox Adaptive Controller (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b12 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft Xbox Series X Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b13 ), k_eControllerType_XBoxOneController, "Xbox Series X Controller" }, // Microsoft Xbox Series X Controller (BLE)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b20 ), k_eControllerType_XBoxOneController, "Xbox One S Controller" }, // Microsoft Xbox One S Controller (BLE)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b21 ), k_eControllerType_XBoxOneController, "Xbox Adaptive Controller" }, // Microsoft Xbox Adaptive Controller (BLE)
|
||||
{ MAKE_CONTROLLER_ID( 0x0738, 0x4a01 ), k_eControllerType_XBoxOneController, NULL }, // Mad Catz FightStick TE 2
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0139 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013B ), k_eControllerType_XBoxOneController, "PDP Xbox One Face-Off Controller" }, // PDP Face-Off Gamepad for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x013a ), k_eControllerType_XBoxOneController, NULL }, // PDP Xbox One Controller (unlisted)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0145 ), k_eControllerType_XBoxOneController, "PDP MK X Fight Pad" }, // PDP MK X Fight Pad for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0146 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015b ), k_eControllerType_XBoxOneController, "PDP Fallout 4 Vault Boy Controller" }, // PDP Fallout 4 Vault Boy Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015c ), k_eControllerType_XBoxOneController, "PDP Xbox One @Play Controller" }, // PDP @Play Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015d ), k_eControllerType_XBoxOneController, "PDP Mirror's Edge Controller" }, // PDP Mirror's Edge Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x015f ), k_eControllerType_XBoxOneController, "PDP Metallic Controller" }, // PDP Metallic Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0160 ), k_eControllerType_XBoxOneController, "PDP NFL Face-Off Controller" }, // PDP NFL Official Face-Off Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0161 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0162 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0163 ), k_eControllerType_XBoxOneController, "PDP Deliverer of Truth" }, // PDP Legendary Collection: Deliverer of Truth
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0164 ), k_eControllerType_XBoxOneController, "PDP Battlefield 1 Controller" }, // PDP Battlefield 1 Official Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0165 ), k_eControllerType_XBoxOneController, "PDP Titanfall 2 Controller" }, // PDP Titanfall 2 Official Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0166 ), k_eControllerType_XBoxOneController, "PDP Mass Effect: Andromeda Controller" }, // PDP Mass Effect: Andromeda Official Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0167 ), k_eControllerType_XBoxOneController, "PDP Halo Wars 2 Face-Off Controller" }, // PDP Halo Wars 2 Official Face-Off Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0205 ), k_eControllerType_XBoxOneController, "PDP Victrix Pro Fight Stick" }, // PDP Victrix Pro Fight Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0206 ), k_eControllerType_XBoxOneController, "PDP Mortal Kombat Controller" }, // PDP Mortal Kombat 25 Anniversary Edition Stick (Xbox One)
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0246 ), k_eControllerType_XBoxOneController, "PDP Xbox One Rock Candy" }, // PDP Rock Candy Wired Controller for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0261 ), k_eControllerType_XBoxOneController, "PDP Xbox One Camo" }, // PDP Camo Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0262 ), k_eControllerType_XBoxOneController, "PDP Xbox One Controller" }, // PDP Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a8 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02a9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Wired Controller for Xbox One - Midnight Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02aa ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Wired Controller for Xbox One - Verdant Green
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ab ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Wired Controller for Xbox One - Crimson Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ac ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Wired Controller for Xbox One - Ember Orange
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ad ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Wired Controller for Xbox One - Stealth Series | Phantom Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ae ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Wired Controller for Xbox One - Stealth Series | Ghost White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02af ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Wired Controller for Xbox One - Stealth Series | Revenant Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Wired Controller for Xbox One - Raven Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Wired Controller for Xbox One - Arctic White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Afterglow" }, // PDP Afterglow Prismatic Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b5 ), k_eControllerType_XBoxOneController, "PDP Xbox One GAMEware Controller" }, // PDP GAMEware Wired Controller Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02b6 ), k_eControllerType_XBoxOneController, NULL }, // PDP One-Handed Joystick Adaptive Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bd ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Wired Controller for Xbox One - Royal Purple
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02be ), k_eControllerType_XBoxOneController, "PDP Xbox One Raven Black" }, // PDP Deluxe Wired Controller for Xbox One - Raven Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02bf ), k_eControllerType_XBoxOneController, "PDP Xbox One Midnight Blue" }, // PDP Deluxe Wired Controller for Xbox One - Midnight Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c0 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantom Black" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantom Black
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c1 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ghost White" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Ghost White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c2 ), k_eControllerType_XBoxOneController, "PDP Xbox One Revenant Blue" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Revenant Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c3 ), k_eControllerType_XBoxOneController, "PDP Xbox One Verdant Green" }, // PDP Deluxe Wired Controller for Xbox One - Verdant Green
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c4 ), k_eControllerType_XBoxOneController, "PDP Xbox One Ember Orange" }, // PDP Deluxe Wired Controller for Xbox One - Ember Orange
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Royal Purple" }, // PDP Deluxe Wired Controller for Xbox One - Royal Purple
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c6 ), k_eControllerType_XBoxOneController, "PDP Xbox One Crimson Red" }, // PDP Deluxe Wired Controller for Xbox One - Crimson Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c7 ), k_eControllerType_XBoxOneController, "PDP Xbox One Arctic White" }, // PDP Deluxe Wired Controller for Xbox One - Arctic White
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c8 ), k_eControllerType_XBoxOneController, "PDP Kingdom Hearts Controller" }, // PDP Kingdom Hearts Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02c9 ), k_eControllerType_XBoxOneController, "PDP Xbox One Phantasm Red" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Phantasm Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ca ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Deluxe Wired Controller for Xbox One - Stealth Series | Specter Violet
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cb ), k_eControllerType_XBoxOneController, "PDP Xbox One Specter Violet" }, // PDP Wired Controller for Xbox One - Stealth Series | Specter Violet
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cd ), k_eControllerType_XBoxOneController, "PDP Xbox One Blu-merang" }, // PDP Rock Candy Wired Controller for Xbox One - Blu-merang
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02ce ), k_eControllerType_XBoxOneController, "PDP Xbox One Cranblast" }, // PDP Rock Candy Wired Controller for Xbox One - Cranblast
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02cf ), k_eControllerType_XBoxOneController, "PDP Xbox One Aqualime" }, // PDP Rock Candy Wired Controller for Xbox One - Aqualime
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d5 ), k_eControllerType_XBoxOneController, "PDP Xbox One Red Camo" }, // PDP Wired Controller for Xbox One - Red Camo
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0346 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0446 ), k_eControllerType_XBoxOneController, "PDP Xbox One RC Gamepad" }, // PDP RC Gamepad for Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02da ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Afterglow" }, // PDP Xbox Series X Afterglow
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d6 ), k_eControllerType_XBoxOneController, "Victrix Gambit Tournament Controller" }, // Victrix Gambit Tournament Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x02d9 ), k_eControllerType_XBoxOneController, "PDP Xbox Series X Midnight Blue" }, // PDP Xbox Series X Midnight Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0063 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro Hayabusa (USA) Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0067 ), k_eControllerType_XBoxOneController, NULL }, // HORIPAD ONE
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0078 ), k_eControllerType_XBoxOneController, NULL }, // Hori Real Arcade Pro V Kai Xbox One
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c5 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0150 ), k_eControllerType_XBoxOneController, NULL }, // HORI Fighting Commander OCTA for Xbox Series X
|
||||
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7009 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach Recon Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x10f5, 0x7013 ), k_eControllerType_XBoxOneController, NULL }, // Turtle Beach REACT-R
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a00 ), k_eControllerType_XBoxOneController, NULL }, // Razer Atrox Arcade Stick
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a03 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wildcat
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a14 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Ultimate
|
||||
{ MAKE_CONTROLLER_ID( 0x1532, 0x0a15 ), k_eControllerType_XBoxOneController, NULL }, // Razer Wolverine Tournament Edition
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2001 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Black Inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2002 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Gray/White Inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2003 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Green Inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2004 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Pink inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2005 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - Black
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2006 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Wired Controller Core - White
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2009 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Red inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Blue inline
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200b ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Red
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200c ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Camo Metallic Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200d ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Seafoam Fade
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200e ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Midnight Blue
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x200f ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Soldier Green
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2011 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired - Metallic Ice
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2012 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X Cuphead EnWired Controller - Mugman
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2015 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Blue Hint
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2016 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Green Hint
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2017 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller - Arctic Camo
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2018 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Arc Lightning
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x2019 ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Royal Purple
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x201a ), k_eControllerType_XBoxOneController, "PowerA Xbox Series X Controller" }, // PowerA Xbox Series X EnWired Controller Nebula
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4001 ), k_eControllerType_XBoxOneController, "PowerA Fusion Pro 2 Controller" }, // PowerA Fusion Pro 2 Wired Controller (Xbox Series X style)
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x4002 ), k_eControllerType_XBoxOneController, "PowerA Spectra Infinity Controller" }, // PowerA Spectra Infinity Wired Controller (Xbox Series X style)
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0x890b ), k_eControllerType_XBoxOneController, NULL }, // PowerA MOGA XP-Ultra Controller (Xbox Series X style)
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x541a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Xbox One Mini Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x542a ), k_eControllerType_XBoxOneController, NULL }, // Xbox ONE spectra
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x543a ), k_eControllerType_XBoxOneController, "PowerA Xbox One Controller" }, // PowerA Xbox ONE liquid metal controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x551a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x561a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x581a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Classic Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x591a ), k_eControllerType_XBoxOneController, NULL }, // PowerA FUSION Pro Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x592a ), k_eControllerType_XBoxOneController, NULL }, // BDA XB1 Spectra Pro
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x791a ), k_eControllerType_XBoxOneController, NULL }, // PowerA Fusion Fight Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x2002 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller for Xbox
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x3106 ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate Wired Controller. Windows, Android, Switch.
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x310a ), k_eControllerType_XBoxOneController, NULL }, // 8BitDo Ultimate 2C Wireless Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x0652 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1618 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin Duke
|
||||
{ MAKE_CONTROLLER_ID( 0x2e24, 0x1688 ), k_eControllerType_XBoxOneController, NULL }, // Hyperkin X91
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0611 ), k_eControllerType_XBoxOneController, NULL }, // Xbox Controller Mode for NACON Revolution 3
|
||||
|
||||
// These have been added via Minidump for unrecognized Xinput controller assert
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x1414 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0159 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0xfaff ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x006d ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00a4 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x1832 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x187f ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x1883 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x03eb, 0xff01 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0c12, 0x0ef8 ), k_eControllerType_XBox360Controller, NULL }, // Homemade fightstick based on brook pcb (with XInput driver??)
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0x1000 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x11ff, 0x0511 ), k_eControllerType_XBox360Controller, NULL }, // PXN V900
|
||||
{ MAKE_CONTROLLER_ID( 0x1345, 0x6006 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x056e, 0x2012 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x146b, 0x0602 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00ae ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0x0401 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0x0301 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xcaa3 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0xc261 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x046d, 0x0291 ), k_eControllerType_XBox360Controller, NULL }, // logitech xinput
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x18d3 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00b1 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x188e ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x187c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x189c ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0079, 0x1874 ), k_eControllerType_XBox360Controller, NULL }, // Unknown Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x0050 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x2e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x91 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x719 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xed ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xc0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x152 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0x1007 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x79, 0x18a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
|
||||
// Added from Minidumps 10-9-19
|
||||
{ MAKE_CONTROLLER_ID( 0x0, 0x6686 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x12ab, 0x304 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x291 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x2a9 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1430, 0x70b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x28e ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x1bad, 0x5500 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x20ab, 0x55ef ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x24c6, 0x5509 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2516, 0x69 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x25b1, 0x360 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2203 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x11 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x53 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0xb7 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0x0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0x1004 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0x1008 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x46d, 0xf301 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x738, 0x2a0 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x738, 0x7263 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x738, 0xb738 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x738, 0xcb29 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x738, 0xf401 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x79, 0x18c2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x79, 0x18c8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x79, 0x18cf ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xc12, 0xe17 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xc12, 0xe1c ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xc12, 0xe22 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xc12, 0xe30 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xd2d2, 0xd2d2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xd62, 0x9a1b ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe00, 0xe00 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x12a ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0x2b2 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0x97 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xba ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xf0d, 0xd8 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xfff, 0x2a1 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x45e, 0x867 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
// Added 12-17-2020
|
||||
{ MAKE_CONTROLLER_ID( 0x16d0, 0xf3f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x2f24, 0x8f ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
{ MAKE_CONTROLLER_ID( 0xe6f, 0xf501 ), k_eControllerType_XBoxOneController, NULL }, // Unknown Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2006 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch Joy-Con (Left)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2067 ), k_eControllerType_SwitchJoyConLeft, NULL }, // Nintendo Switch 2 Joy-Con (Left)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2007 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch Joy-Con (Right)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2066 ), k_eControllerType_SwitchJoyConRight, NULL }, // Nintendo Switch 2 Joy-Con (Right)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2008 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch Joy-Con (Left+Right Combined)
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2068 ), k_eControllerType_SwitchJoyConPair, NULL }, // Nintendo Switch 2 Joy-Con (Left+Right Combined)
|
||||
|
||||
// This same controller ID is spoofed by many 3rd-party Switch controllers.
|
||||
// The ones we currently know of are:
|
||||
// * Any 8bitdo controller with Switch support
|
||||
// * ORTZ Gaming Wireless Pro Controller
|
||||
// * ZhiXu Gamepad Wireless
|
||||
// * Sunwaytek Wireless Motion Controller for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2009 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Switch Pro Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x057e, 0x2069 ), k_eControllerType_Switch2ProController, NULL }, // Nintendo Switch 2 Pro Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2017 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SNES Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x2019 ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online N64 Controller
|
||||
//{ MAKE_CONTROLLER_ID( 0x057e, 0x201e ), k_eControllerType_SwitchProController, NULL }, // Nintendo Online SEGA Genesis Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00c1 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORIPAD for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0092 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Pokken Tournament DX Pro Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00f6 ), k_eControllerType_SwitchProController, NULL }, // HORI Wireless Switch Pad
|
||||
// The HORIPAD S, which comes in multiple styles:
|
||||
// - NSW-108, classic GameCube controller
|
||||
// - NSW-244, Fighting Commander arcade pad
|
||||
// - NSW-278, Hori Pad Mini gamepad
|
||||
// - NSW-326, HORIPAD FPS for Nintendo Switch
|
||||
//
|
||||
// The first two, at least, shouldn't have their buttons remapped, and since we
|
||||
// can't tell which model we're actually using, we won't do any button remapping
|
||||
// for any of them.
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00dc ), k_eControllerType_XInputSwitchController, NULL }, // HORIPAD S - Looks like a Switch controller but uses the Xbox 360 controller protocol, there is also a version of this that looks like a GameCube controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0180 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Pro Controller for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0181 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Deluxe Wired Pro Controller for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0184 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Faceoff Wired Deluxe+ Audio Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0185 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Wired Fight Pad Pro for Nintendo Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0186 ), k_eControllerType_SwitchProController, NULL }, // PDP Afterglow Wireless Switch Controller - working gyro. USB is for charging only. Many later "Wireless" line devices w/ gyro also use this vid/pid
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0187 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Rockcandy Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wired Deluxe+ Audio Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x018b ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wave Wired/Wireless Controller for Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x018c ), k_eControllerType_SwitchProController, "PDP REALMz Wireless Controller" }, // PDP REALMz Wireless Controller for Switch
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0193 ), k_eControllerType_Switch2ProController, NULL }, // Turtle Beach Afterglow Wireless RGB Gaming Controller for Nintendo Switch 2 and the Turtle Beach Rematch Wireless RGB Gaming Controller for Nintendo Switch 2
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0196 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Rematch Wired Controller for Nintendo Switch 2
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0197 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Afterglow Wave Wired Controller for Nintendo Switch 2
|
||||
{ MAKE_CONTROLLER_ID( 0x0e6f, 0x0198 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Afterglow Wired Controller for Switch 2
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Real Arcade Pro V Hayabusa in Switch Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Wired Controller Plus/PowerA Wired Controller Nintendo GameCube Style
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa712 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Fight Pad
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa713 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Super Mario Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa714 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Spectra Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa715 ), k_eControllerType_SwitchInputOnlyController, NULL }, // Power A Fusion Wireless Arcade Stick (USB Mode) Over BT is shows up as 057e 2009
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa716 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Pro Controller - USB requires toggling switch on back of device
|
||||
{ MAKE_CONTROLLER_ID( 0x20d6, 0xa718 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Nano Wired Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0001 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Black
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0002 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch ??
|
||||
{ MAKE_CONTROLLER_ID( 0x33dd, 0x0003 ), k_eControllerType_SwitchInputOnlyController, NULL }, // ZUIKI MasCon for Nintendo Switch Red
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x00f0 ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Taiko Controller For Switch
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x054c, 0x0df2 ), k_eControllerType_PS5EdgeController, NULL }, // Sony DualSense Edge Controller
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x02e3 ), k_eControllerType_XBoxEliteController, "Xbox One Elite Controller" }, // Microsoft Xbox One Elite Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b00 ), k_eControllerType_XBoxEliteController, "Xbox One Elite 2 Controller" }, // Microsoft Xbox One Elite Series 2 Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b05 ), k_eControllerType_XBoxEliteController, "Xbox One Elite 2 Controller" }, // Microsoft Xbox One Elite Series 2 Controller (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x045e, 0x0b22 ), k_eControllerType_XBoxEliteController, "Xbox One Elite 2 Controller" }, // Microsoft Xbox One Elite Series 2 Controller (BLE)
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6000 ), k_eControllerType_8BitDoController, "8Bitdo SF30 Controller" }, // 8BitDo SF30 Pro Controller in Steam Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6100 ), k_eControllerType_8BitDoController, "8Bitdo SF30 Controller" }, // 8BitDo SF30 Pro Controller in Steam Mode (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6001 ), k_eControllerType_8BitDoController, "8Bitdo SN30 Controller" }, // 8BitDo SN30 Pro Controller in Steam Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6101 ), k_eControllerType_8BitDoController, "8Bitdo SN30 Controller" }, // 8BitDo SN30 Pro Controller in Steam Mode (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6003 ), k_eControllerType_8BitDoController, "8Bitdo Pro 2 Controller" }, // 8BitDo Pro 2 Controller in Steam Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6006 ), k_eControllerType_8BitDoController, "8Bitdo Pro 2 Controller" }, // 8BitDo Pro 2 Controller in Steam Mode
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6009 ), k_eControllerType_8BitDoController, "8Bitdo Pro 3 Controller" }, // 8BitDo Pro 3 Controller in Steam Mode (Bluetooth)
|
||||
{ MAKE_CONTROLLER_ID( 0x2dc8, 0x6012 ), k_eControllerType_8BitDoController, "8Bitdo Ultimate 2 Wireless Controller" }, // 8BitDo Ultimate 2 Wireless Controller in Steam Mode (Bluetooth)
|
||||
|
||||
// Valve products
|
||||
{ MAKE_CONTROLLER_ID( 0x0000, 0x11fb ), k_eControllerType_MobileTouch, NULL }, // Streaming mobile touch virtual controls
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1101 ), k_eControllerType_SteamController, NULL }, // Valve Legacy Steam Controller (CHELL)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1102 ), k_eControllerType_SteamController, NULL }, // Valve wired Steam Controller (D0G)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1105 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1106 ), k_eControllerType_SteamController, NULL }, // Valve Bluetooth Steam Controller (D0G)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x11ff ), k_eControllerType_UnknownNonSteamController, NULL }, // Steam Virtual Gamepad
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1142 ), k_eControllerType_SteamController, NULL }, // Valve wireless Steam Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1205 ), k_eControllerType_SteamControllerNeptune, NULL }, // Valve Steam Deck Builtin Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1302 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1303 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Triton Controller (BLE)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1304 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Proteus Dongle (Proprietary)
|
||||
{ MAKE_CONTROLLER_ID( 0x28de, 0x1305 ), k_eControllerType_SteamControllerTriton, NULL }, // Valve Steam Nereid Dongle (Proprietary)
|
||||
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x01AB ), k_eControllerType_HoriSteamController, NULL }, // HORI Wireless HORIPAD for Steam
|
||||
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0196 ), k_eControllerType_HoriSteamController, NULL }, // HORI Wireless HORIPAD for Steam ( BT )
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (C) Valve Corporation
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef CONTROLLER_TYPE_H
|
||||
#define CONTROLLER_TYPE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Steam Controller models
|
||||
// WARNING: DO NOT RENUMBER EXISTING VALUES - STORED IN A DATABASE
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum
|
||||
{
|
||||
k_eControllerType_None = -1,
|
||||
k_eControllerType_Unknown = 0,
|
||||
|
||||
// Steam Controllers
|
||||
k_eControllerType_UnknownSteamController = 1,
|
||||
k_eControllerType_SteamController = 2,
|
||||
k_eControllerType_SteamControllerV2 = 3,
|
||||
k_eControllerType_SteamControllerNeptune = 4,
|
||||
|
||||
k_eControllerType_SteamControllerTriton = 10,
|
||||
|
||||
// Other Controllers
|
||||
k_eControllerType_UnknownNonSteamController = 30,
|
||||
k_eControllerType_XBox360Controller = 31,
|
||||
k_eControllerType_XBoxOneController = 32,
|
||||
k_eControllerType_PS3Controller = 33,
|
||||
k_eControllerType_PS4Controller = 34,
|
||||
k_eControllerType_WiiController = 35,
|
||||
k_eControllerType_AppleController = 36,
|
||||
k_eControllerType_AndroidController = 37,
|
||||
k_eControllerType_SwitchProController = 38,
|
||||
k_eControllerType_SwitchJoyConLeft = 39,
|
||||
k_eControllerType_SwitchJoyConRight = 40,
|
||||
k_eControllerType_SwitchJoyConPair = 41,
|
||||
k_eControllerType_SwitchInputOnlyController = 42,
|
||||
k_eControllerType_MobileTouch = 43,
|
||||
k_eControllerType_XInputSwitchController = 44, // Client-side only, used to mark Nintendo Switch style controllers as using XInput instead of the Nintendo Switch protocol
|
||||
k_eControllerType_PS5Controller = 45,
|
||||
k_eControllerType_XBoxEliteController = 46,
|
||||
k_eControllerType_XInputPS4Controller = 47, // Client-side only, used to mark DualShock 4 style controllers using XInput instead of the DualShock 4 controller protocol
|
||||
k_eControllerType_PS5EdgeController = 48,
|
||||
k_eControllerType_HoriSteamController = 49,
|
||||
k_eControllerType_8BitDoController = 50,
|
||||
k_eControllerType_Switch2ProController = 51,
|
||||
k_eControllerType_Switch2InputOnlyController = 52,
|
||||
k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value
|
||||
|
||||
// Keyboards and Mice
|
||||
k_eControllertype_GenericKeyboard = 400,
|
||||
k_eControllertype_GenericMouse = 800,
|
||||
} EControllerType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int m_unDeviceID;
|
||||
EControllerType m_eControllerType;
|
||||
const char *m_pszName;
|
||||
} ControllerDescription_t;
|
||||
|
||||
|
||||
extern EControllerType GuessControllerType( int nVID, int nPID );
|
||||
extern const char *GuessControllerName( int nVID, int nPID );
|
||||
|
||||
#endif // CONTROLLER_TYPE_H
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,100 +0,0 @@
|
||||
ANDROID_API_TARGET=21
|
||||
PARALLEL_JOBS=$(nproc)
|
||||
|
||||
rm -r ./android
|
||||
mkdir android
|
||||
|
||||
function build_one
|
||||
{
|
||||
PREFIX=$(pwd)/android/$CPU
|
||||
SYSROOT=$NDK/platforms/android-$ANDROID_API_TARGET/arch-$SYSROOT_CPU
|
||||
TOOLCHAIN_PATH=$NDK/toolchains/$TOOLCHAIN_DIR/prebuilt/linux-x86_64
|
||||
export PATH=$PATH:$TOOLCHAIN_PATH/bin
|
||||
./configure \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--host=$TOOLCHAIN_BIN_PREFIX \
|
||||
--target=$TOOLCHAIN_BIN_PREFIX \
|
||||
CFLAGS="--sysroot=$SYSROOT -O2 $ADDI_CFLAGS" \
|
||||
$ADDI_CONFIGURE_FLAGS
|
||||
make clean
|
||||
make -j$PARALLEL_JOBS
|
||||
mkdir android/$CPU
|
||||
cp .libs/libopus.a android/$CPU
|
||||
}
|
||||
|
||||
function build_mips
|
||||
{
|
||||
CPU=mips
|
||||
SYSROOT_CPU=mips
|
||||
TOOLCHAIN_BIN_PREFIX=mipsel-linux-android
|
||||
TOOLCHAIN_DIR=mipsel-linux-android-4.9
|
||||
ADDI_CFLAGS="-mips32 -mhard-float -EL -mno-dsp"
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
||||
build_one
|
||||
}
|
||||
|
||||
function build_mips64
|
||||
{
|
||||
CPU=mips64
|
||||
SYSROOT_CPU=mips64
|
||||
TOOLCHAIN_BIN_PREFIX=mips64el-linux-android
|
||||
TOOLCHAIN_DIR=mips64el-linux-android-4.9
|
||||
ADDI_CFLAGS="-mips64r6"
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point
|
||||
build_one
|
||||
}
|
||||
|
||||
function build_x86
|
||||
{
|
||||
CPU=x86
|
||||
SYSROOT_CPU=x86
|
||||
TOOLCHAIN_BIN_PREFIX=i686-linux-android
|
||||
TOOLCHAIN_DIR=x86-4.9
|
||||
ADDI_CFLAGS="-march=i686 -mtune=atom -mstackrealign -msse -msse2 -msse3 -mssse3 -mfpmath=sse -m32"
|
||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
||||
build_one
|
||||
}
|
||||
|
||||
function build_x86_64
|
||||
{
|
||||
CPU=x86_64
|
||||
SYSROOT_CPU=x86_64
|
||||
TOOLCHAIN_BIN_PREFIX=x86_64-linux-android
|
||||
TOOLCHAIN_DIR=x86_64-4.9
|
||||
ADDI_CFLAGS="-msse -msse2 -msse3 -mssse3 -msse4 -msse4.1 -msse4.2 -mpopcnt -m64"
|
||||
ADDI_CONFIGURE_FLAGS="" # floating point for SSE optimizations
|
||||
build_one
|
||||
}
|
||||
|
||||
function build_armv7
|
||||
{
|
||||
CPU=arm
|
||||
SYSROOT_CPU=arm
|
||||
TOOLCHAIN_BIN_PREFIX=arm-linux-androideabi
|
||||
TOOLCHAIN_DIR=arm-linux-androideabi-4.9
|
||||
ADDI_CFLAGS="-marm -mfpu=vfpv3-d16"
|
||||
ADDI_LDFLAGS=""
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point" # fixed point for NEON, EDSP, Media
|
||||
build_one
|
||||
}
|
||||
|
||||
# ARMv8 doesn't currently have assembly in the opus project. We still use fixed point
|
||||
# anyway in the hopes that it will be more performant even without assembly.
|
||||
function build_armv8
|
||||
{
|
||||
CPU=aarch64
|
||||
SYSROOT_CPU=arm64
|
||||
TOOLCHAIN_BIN_PREFIX=aarch64-linux-android
|
||||
TOOLCHAIN_DIR=aarch64-linux-android-4.9
|
||||
ADDI_CFLAGS=""
|
||||
ADDI_LDFLAGS=""
|
||||
ADDI_CONFIGURE_FLAGS="--enable-fixed-point"
|
||||
build_one
|
||||
}
|
||||
|
||||
build_mips
|
||||
build_mips64
|
||||
build_x86
|
||||
build_x86_64
|
||||
build_armv7
|
||||
build_armv8
|
||||
@@ -1,342 +0,0 @@
|
||||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2008-2012 Gregory Maxwell
|
||||
Written by Jean-Marc Valin and Gregory Maxwell */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file opus_custom.h
|
||||
@brief Opus-Custom reference implementation API
|
||||
*/
|
||||
|
||||
#ifndef OPUS_CUSTOM_H
|
||||
#define OPUS_CUSTOM_H
|
||||
|
||||
#include "opus_defines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef CUSTOM_MODES
|
||||
# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
|
||||
#else
|
||||
# define OPUS_CUSTOM_EXPORT
|
||||
# ifdef OPUS_BUILD
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
|
||||
# else
|
||||
# define OPUS_CUSTOM_EXPORT_STATIC
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/** @defgroup opus_custom Opus Custom
|
||||
* @{
|
||||
* Opus Custom is an optional part of the Opus specification and
|
||||
* reference implementation which uses a distinct API from the regular
|
||||
* API and supports frame sizes that are not normally supported.\ Use
|
||||
* of Opus Custom is discouraged for all but very special applications
|
||||
* for which a frame size different from 2.5, 5, 10, or 20 ms is needed
|
||||
* (for either complexity or latency reasons) and where interoperability
|
||||
* is less important.
|
||||
*
|
||||
* In addition to the interoperability limitations the use of Opus custom
|
||||
* disables a substantial chunk of the codec and generally lowers the
|
||||
* quality available at a given bitrate. Normally when an application needs
|
||||
* a different frame size from the codec it should buffer to match the
|
||||
* sizes but this adds a small amount of delay which may be important
|
||||
* in some very low latency applications. Some transports (especially
|
||||
* constant rate RF transports) may also work best with frames of
|
||||
* particular durations.
|
||||
*
|
||||
* Libopus only supports custom modes if they are enabled at compile time.
|
||||
*
|
||||
* The Opus Custom API is similar to the regular API but the
|
||||
* @ref opus_encoder_create and @ref opus_decoder_create calls take
|
||||
* an additional mode parameter which is a structure produced by
|
||||
* a call to @ref opus_custom_mode_create. Both the encoder and decoder
|
||||
* must create a mode using the same sample rate (fs) and frame size
|
||||
* (frame size) so these parameters must either be signaled out of band
|
||||
* or fixed in a particular implementation.
|
||||
*
|
||||
* Similar to regular Opus the custom modes support on the fly frame size
|
||||
* switching, but the sizes available depend on the particular frame size in
|
||||
* use. For some initial frame sizes on a single on the fly size is available.
|
||||
*/
|
||||
|
||||
/** Contains the state of an encoder. One encoder state is needed
|
||||
for each stream. It is initialized once at the beginning of the
|
||||
stream. Do *not* re-initialize the state for every frame.
|
||||
@brief Encoder state
|
||||
*/
|
||||
typedef struct OpusCustomEncoder OpusCustomEncoder;
|
||||
|
||||
/** State of the decoder. One decoder state is needed for each stream.
|
||||
It is initialized once at the beginning of the stream. Do *not*
|
||||
re-initialize the state for every frame.
|
||||
@brief Decoder state
|
||||
*/
|
||||
typedef struct OpusCustomDecoder OpusCustomDecoder;
|
||||
|
||||
/** The mode contains all the information necessary to create an
|
||||
encoder. Both the encoder and decoder need to be initialized
|
||||
with exactly the same mode, otherwise the output will be
|
||||
corrupted.
|
||||
@brief Mode configuration
|
||||
*/
|
||||
typedef struct OpusCustomMode OpusCustomMode;
|
||||
|
||||
/** Creates a new mode struct. This will be passed to an encoder or
|
||||
* decoder. The mode MUST NOT BE DESTROYED until the encoders and
|
||||
* decoders that use it are destroyed as well.
|
||||
* @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
|
||||
* packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
|
||||
* @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
|
||||
* @return A newly created mode
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
|
||||
|
||||
/** Destroys a mode struct. Only call this after all encoders and
|
||||
* decoders using this mode are destroyed as well.
|
||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
|
||||
|
||||
/* Encoder */
|
||||
/** Gets the size of an OpusCustomEncoder structure.
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @returns size
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
# ifdef CUSTOM_MODES
|
||||
/** Initializes a previously allocated encoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
|
||||
OpusCustomEncoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new encoder state. Each stream needs its own encoder
|
||||
* state (can't be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* decoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created encoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
/** Destroys a an encoder state.
|
||||
* @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
|
||||
|
||||
/** Encodes a frame of audio.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
|
||||
* Samples with a range beyond +/-1.0 are supported but will
|
||||
* be clipped by decoders using the integer API and should
|
||||
* only be used if it is known that the far end supports
|
||||
* extended dynamic range. There must be exactly
|
||||
* frame_size samples per channel.
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
||||
* (can change from one frame to another)
|
||||
* @return Number of bytes written to "compressed".
|
||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
||||
* decoding is possible.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
|
||||
OpusCustomEncoder *st,
|
||||
const float *pcm,
|
||||
int frame_size,
|
||||
unsigned char *compressed,
|
||||
int maxCompressedBytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Encodes a frame of audio.
|
||||
* @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
|
||||
* @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
|
||||
* There must be exactly frame_size samples per channel.
|
||||
* @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
|
||||
* @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
|
||||
* @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
|
||||
* (can change from one frame to another)
|
||||
* @return Number of bytes written to "compressed".
|
||||
* If negative, an error has occurred (see error codes). It is IMPORTANT that
|
||||
* the length returned be somehow transmitted to the decoder. Otherwise, no
|
||||
* decoding is possible.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
|
||||
OpusCustomEncoder *st,
|
||||
const opus_int16 *pcm,
|
||||
int frame_size,
|
||||
unsigned char *compressed,
|
||||
int maxCompressedBytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Perform a CTL function on an Opus custom encoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @see opus_encoderctls
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
|
||||
/* Decoder */
|
||||
|
||||
/** Gets the size of an OpusCustomDecoder structure.
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @returns size
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Initializes a previously allocated decoder state
|
||||
* The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
|
||||
* This is intended for applications which use their own allocator instead of malloc.
|
||||
* @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
|
||||
* To reset a previously initialized state use the OPUS_RESET_STATE CTL.
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
|
||||
* the stream (must be the same characteristics as used for the
|
||||
* encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @return OPUS_OK Success or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
|
||||
OpusCustomDecoder *st,
|
||||
const OpusCustomMode *mode,
|
||||
int channels
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Creates a new decoder state. Each stream needs its own decoder state (can't
|
||||
* be shared across simultaneous streams).
|
||||
* @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
|
||||
* stream (must be the same characteristics as used for the encoder)
|
||||
* @param [in] channels <tt>int</tt>: Number of channels
|
||||
* @param [out] error <tt>int*</tt>: Returns an error code
|
||||
* @return Newly created decoder state.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
|
||||
const OpusCustomMode *mode,
|
||||
int channels,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/** Destroys a an decoder state.
|
||||
* @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
|
||||
|
||||
/** Decode an opus custom frame with floating point output
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
||||
* @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(float)
|
||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
|
||||
OpusCustomDecoder *st,
|
||||
const unsigned char *data,
|
||||
int len,
|
||||
float *pcm,
|
||||
int frame_size
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Decode an opus custom frame
|
||||
* @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
|
||||
* @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
|
||||
* @param [in] len <tt>int</tt>: Number of bytes in payload
|
||||
* @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
|
||||
* is frame_size*channels*sizeof(opus_int16)
|
||||
* @param [in] frame_size Number of samples per channel of available space in *pcm.
|
||||
* @returns Number of decoded samples or @ref opus_errorcodes
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
|
||||
OpusCustomDecoder *st,
|
||||
const unsigned char *data,
|
||||
int len,
|
||||
opus_int16 *pcm,
|
||||
int frame_size
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
/** Perform a CTL function on an Opus custom decoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated
|
||||
* by a convenience macro.
|
||||
* @see opus_genericctls
|
||||
*/
|
||||
OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPUS_CUSTOM_H */
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
// This file includes a few functions standalone from SDL_joystick.c useful for joystick typing
|
||||
|
||||
#include "minisdl.h"
|
||||
#include "controller_type.h"
|
||||
#include "controller_list.h"
|
||||
#include "usb_ids.h"
|
||||
|
||||
// Macro to combine a USB vendor ID and product ID into a single Uint32 value
|
||||
#define MAKE_VIDPID(VID, PID) (((Uint32)(VID)) << 16 | (PID))
|
||||
|
||||
static Uint32 initial_old_xboxone_controllers[] = {
|
||||
MAKE_VIDPID(0x0000, 0x6686),
|
||||
MAKE_VIDPID(0x0079, 0x18a1),
|
||||
MAKE_VIDPID(0x0079, 0x18c2),
|
||||
MAKE_VIDPID(0x0079, 0x18c8),
|
||||
MAKE_VIDPID(0x0079, 0x18cf),
|
||||
MAKE_VIDPID(0x03f0, 0x0495),
|
||||
MAKE_VIDPID(0x045e, 0x02d1),
|
||||
MAKE_VIDPID(0x045e, 0x02dd),
|
||||
MAKE_VIDPID(0x045e, 0x02e0),
|
||||
MAKE_VIDPID(0x045e, 0x02e3),
|
||||
MAKE_VIDPID(0x045e, 0x02ea),
|
||||
MAKE_VIDPID(0x045e, 0x02fd),
|
||||
MAKE_VIDPID(0x045e, 0x02ff),
|
||||
MAKE_VIDPID(0x045e, 0x0867),
|
||||
MAKE_VIDPID(0x045e, 0x0b00),
|
||||
MAKE_VIDPID(0x045e, 0x0b05),
|
||||
MAKE_VIDPID(0x045e, 0x0b0a),
|
||||
MAKE_VIDPID(0x045e, 0x0b0c),
|
||||
MAKE_VIDPID(0x045e, 0x0b20),
|
||||
MAKE_VIDPID(0x045e, 0x0b21),
|
||||
MAKE_VIDPID(0x045e, 0x0b22),
|
||||
MAKE_VIDPID(0x046d, 0x0000),
|
||||
MAKE_VIDPID(0x046d, 0x1004),
|
||||
MAKE_VIDPID(0x046d, 0x1007),
|
||||
MAKE_VIDPID(0x046d, 0x1008),
|
||||
MAKE_VIDPID(0x046d, 0xf301),
|
||||
MAKE_VIDPID(0x0738, 0x02a0),
|
||||
MAKE_VIDPID(0x0738, 0x4a01),
|
||||
MAKE_VIDPID(0x0738, 0x7263),
|
||||
MAKE_VIDPID(0x0738, 0xb738),
|
||||
MAKE_VIDPID(0x0738, 0xcb29),
|
||||
MAKE_VIDPID(0x0738, 0xf401),
|
||||
MAKE_VIDPID(0x0c12, 0x0e17),
|
||||
MAKE_VIDPID(0x0c12, 0x0e1c),
|
||||
MAKE_VIDPID(0x0c12, 0x0e22),
|
||||
MAKE_VIDPID(0x0c12, 0x0e30),
|
||||
MAKE_VIDPID(0x0d62, 0x9a1a),
|
||||
MAKE_VIDPID(0x0d62, 0x9a1b),
|
||||
MAKE_VIDPID(0x0e00, 0x0e00),
|
||||
MAKE_VIDPID(0x0e6f, 0x012a),
|
||||
MAKE_VIDPID(0x0e6f, 0x0139),
|
||||
MAKE_VIDPID(0x0e6f, 0x013B),
|
||||
MAKE_VIDPID(0x0e6f, 0x013a),
|
||||
MAKE_VIDPID(0x0e6f, 0x0145),
|
||||
MAKE_VIDPID(0x0e6f, 0x0146),
|
||||
MAKE_VIDPID(0x0e6f, 0x0152),
|
||||
MAKE_VIDPID(0x0e6f, 0x015b),
|
||||
MAKE_VIDPID(0x0e6f, 0x015c),
|
||||
MAKE_VIDPID(0x0e6f, 0x015d),
|
||||
MAKE_VIDPID(0x0e6f, 0x015f),
|
||||
MAKE_VIDPID(0x0e6f, 0x0160),
|
||||
MAKE_VIDPID(0x0e6f, 0x0161),
|
||||
MAKE_VIDPID(0x0e6f, 0x0162),
|
||||
MAKE_VIDPID(0x0e6f, 0x0163),
|
||||
MAKE_VIDPID(0x0e6f, 0x0164),
|
||||
MAKE_VIDPID(0x0e6f, 0x0165),
|
||||
MAKE_VIDPID(0x0e6f, 0x0166),
|
||||
MAKE_VIDPID(0x0e6f, 0x0167),
|
||||
MAKE_VIDPID(0x0e6f, 0x0205),
|
||||
MAKE_VIDPID(0x0e6f, 0x0206),
|
||||
MAKE_VIDPID(0x0e6f, 0x0246),
|
||||
MAKE_VIDPID(0x0e6f, 0x0261),
|
||||
MAKE_VIDPID(0x0e6f, 0x0262),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a4),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a7),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02a9),
|
||||
MAKE_VIDPID(0x0e6f, 0x02aa),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ab),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ac),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ad),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ae),
|
||||
MAKE_VIDPID(0x0e6f, 0x02af),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02b8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02bd),
|
||||
MAKE_VIDPID(0x0e6f, 0x02be),
|
||||
MAKE_VIDPID(0x0e6f, 0x02bf),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c0),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c1),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c2),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c3),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c4),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c5),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c6),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c7),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c8),
|
||||
MAKE_VIDPID(0x0e6f, 0x02c9),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ca),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cb),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cd),
|
||||
MAKE_VIDPID(0x0e6f, 0x02ce),
|
||||
MAKE_VIDPID(0x0e6f, 0x02cf),
|
||||
MAKE_VIDPID(0x0e6f, 0x02d5),
|
||||
MAKE_VIDPID(0x0e6f, 0x0346),
|
||||
MAKE_VIDPID(0x0e6f, 0x0446),
|
||||
MAKE_VIDPID(0x0e6f, 0xf501),
|
||||
MAKE_VIDPID(0x0f0d, 0x0063),
|
||||
MAKE_VIDPID(0x0f0d, 0x0067),
|
||||
MAKE_VIDPID(0x0f0d, 0x0078),
|
||||
MAKE_VIDPID(0x0f0d, 0x0097),
|
||||
MAKE_VIDPID(0x0f0d, 0x00ba),
|
||||
MAKE_VIDPID(0x0f0d, 0x00c0),
|
||||
MAKE_VIDPID(0x0f0d, 0x00c5),
|
||||
MAKE_VIDPID(0x0f0d, 0x00d8),
|
||||
MAKE_VIDPID(0x0f0d, 0x00ed),
|
||||
MAKE_VIDPID(0x0fff, 0x02a1),
|
||||
MAKE_VIDPID(0x12ab, 0x0304),
|
||||
MAKE_VIDPID(0x1430, 0x0291),
|
||||
MAKE_VIDPID(0x1430, 0x02a9),
|
||||
MAKE_VIDPID(0x1430, 0x070b),
|
||||
MAKE_VIDPID(0x1430, 0x0719),
|
||||
MAKE_VIDPID(0x146b, 0x0611),
|
||||
MAKE_VIDPID(0x1532, 0x0a00),
|
||||
MAKE_VIDPID(0x1532, 0x0a03),
|
||||
MAKE_VIDPID(0x1532, 0x0a14),
|
||||
MAKE_VIDPID(0x1532, 0x0a15),
|
||||
MAKE_VIDPID(0x16d0, 0x0f3f),
|
||||
MAKE_VIDPID(0x1bad, 0x028e),
|
||||
MAKE_VIDPID(0x1bad, 0x02a0),
|
||||
MAKE_VIDPID(0x1bad, 0x5500),
|
||||
MAKE_VIDPID(0x20ab, 0x55ef),
|
||||
MAKE_VIDPID(0x24c6, 0x541a),
|
||||
MAKE_VIDPID(0x24c6, 0x542a),
|
||||
MAKE_VIDPID(0x24c6, 0x543a),
|
||||
MAKE_VIDPID(0x24c6, 0x5509),
|
||||
MAKE_VIDPID(0x24c6, 0x551a),
|
||||
MAKE_VIDPID(0x24c6, 0x561a),
|
||||
MAKE_VIDPID(0x24c6, 0x581a),
|
||||
MAKE_VIDPID(0x24c6, 0x591a),
|
||||
MAKE_VIDPID(0x24c6, 0x592a),
|
||||
MAKE_VIDPID(0x24c6, 0x791a),
|
||||
MAKE_VIDPID(0x2516, 0x0069),
|
||||
MAKE_VIDPID(0x25b1, 0x0360),
|
||||
MAKE_VIDPID(0x2c22, 0x2203),
|
||||
MAKE_VIDPID(0x2e24, 0x0652),
|
||||
MAKE_VIDPID(0x2e24, 0x1618),
|
||||
MAKE_VIDPID(0x2e24, 0x1688),
|
||||
MAKE_VIDPID(0x2f24, 0x0011),
|
||||
MAKE_VIDPID(0x2f24, 0x002e),
|
||||
MAKE_VIDPID(0x2f24, 0x0050),
|
||||
MAKE_VIDPID(0x2f24, 0x0053),
|
||||
MAKE_VIDPID(0x2f24, 0x008f),
|
||||
MAKE_VIDPID(0x2f24, 0x0091),
|
||||
MAKE_VIDPID(0x2f24, 0x00b7),
|
||||
MAKE_VIDPID(0xd2d2, 0xd2d2),
|
||||
};
|
||||
|
||||
EControllerType GuessControllerType( int nVID, int nPID )
|
||||
{
|
||||
unsigned int unDeviceID = MAKE_CONTROLLER_ID( nVID, nPID );
|
||||
int iIndex;
|
||||
|
||||
for ( iIndex = 0; iIndex < sizeof( arrControllers ) / sizeof( arrControllers[0] ); ++iIndex )
|
||||
{
|
||||
if ( unDeviceID == arrControllers[ iIndex ].m_unDeviceID )
|
||||
{
|
||||
return arrControllers[ iIndex ].m_eControllerType;
|
||||
}
|
||||
}
|
||||
|
||||
return k_eControllerType_UnknownNonSteamController;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickXboxOne(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
return eType == k_eControllerType_XBoxOneController ||
|
||||
eType == k_eControllerType_XBoxEliteController;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
return eType == k_eControllerType_XBoxEliteController;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
if (!SDL_IsJoystickXboxOne(vendor_id, product_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Most new controllers have the share button, so we'll default to true and
|
||||
// have a list of older XBox One controllers that are known not to have it.
|
||||
Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id);
|
||||
for (int i = 0; i < (sizeof(initial_old_xboxone_controllers) / sizeof(*initial_old_xboxone_controllers)); i++) {
|
||||
if (vidpid == initial_old_xboxone_controllers[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
|
||||
{
|
||||
EControllerType eType = GuessControllerType(vendor_id, product_id);
|
||||
return eType == k_eControllerType_PS5EdgeController;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint16_t Uint16;
|
||||
typedef uint32_t Uint32;
|
||||
|
||||
bool SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id);
|
||||
bool SDL_IsJoystickXboxSeriesX(Uint16 vendor_id, Uint16 product_id);
|
||||
bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id);
|
||||
Submodule app/src/main/jni/moonlight-core/moonlight-common-c updated: 50c0a51b10...874ac9548f
@@ -1,11 +1,5 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libssl
|
||||
LOCAL_SRC_FILES:= $(TARGET_ARCH_ABI)/libssl.a
|
||||
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
|
||||
include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libcrypto
|
||||
LOCAL_SRC_FILES:= $(TARGET_ARCH_ABI)/libcrypto.a
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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
|
||||
|
||||
@@ -1,92 +1,109 @@
|
||||
/*
|
||||
* Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 2002-2026 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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 HEADER_AES_H
|
||||
# define HEADER_AES_H
|
||||
#ifndef OPENSSL_AES_H
|
||||
#define OPENSSL_AES_H
|
||||
#pragma once
|
||||
|
||||
# include <openssl/opensslconf.h>
|
||||
#include <openssl/macros.h>
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
#define HEADER_AES_H
|
||||
#endif
|
||||
|
||||
# include <stddef.h>
|
||||
# ifdef __cplusplus
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
# define AES_ENCRYPT 1
|
||||
# define AES_DECRYPT 0
|
||||
#define AES_BLOCK_SIZE 16
|
||||
|
||||
/*
|
||||
* Because array size can't be a const in C, the following two are macros.
|
||||
* Both sizes are in bytes.
|
||||
*/
|
||||
# define AES_MAXNR 14
|
||||
# define AES_BLOCK_SIZE 16
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
||||
#define AES_ENCRYPT 1
|
||||
#define AES_DECRYPT 0
|
||||
|
||||
#define AES_MAXNR 14
|
||||
|
||||
/* This should be a hidden type, but EVP requires that the size be known */
|
||||
struct aes_key_st {
|
||||
# ifdef AES_LONG
|
||||
#ifdef AES_LONG
|
||||
unsigned long rd_key[4 * (AES_MAXNR + 1)];
|
||||
# else
|
||||
#else
|
||||
unsigned int rd_key[4 * (AES_MAXNR + 1)];
|
||||
# endif
|
||||
#endif
|
||||
int rounds;
|
||||
};
|
||||
typedef struct aes_key_st AES_KEY;
|
||||
|
||||
const char *AES_options(void);
|
||||
|
||||
int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||
AES_KEY *key);
|
||||
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
OSSL_DEPRECATEDIN_3_0 const char *AES_options(void);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
int AES_set_encrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
int AES_set_decrypt_key(const unsigned char *userKey, int bits,
|
||||
AES_KEY *key);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key);
|
||||
const AES_KEY *key);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key);
|
||||
|
||||
const AES_KEY *key);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key, const int enc);
|
||||
const AES_KEY *key, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num);
|
||||
|
||||
/* NB: the IV is _two_ blocks long */
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc);
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int enc);
|
||||
/* NB: the IV is _four_ blocks long */
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
const AES_KEY *key2, const unsigned char *ivec,
|
||||
const int enc);
|
||||
|
||||
size_t length, const AES_KEY *key, const AES_KEY *key2,
|
||||
const unsigned char *ivec, int enc);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen);
|
||||
unsigned char *out, const unsigned char *in,
|
||||
unsigned int inlen);
|
||||
OSSL_DEPRECATEDIN_3_0
|
||||
int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen);
|
||||
unsigned char *out, const unsigned char *in,
|
||||
unsigned int inlen);
|
||||
#endif
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
/*
|
||||
* Copyright 2015-2016 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
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#error "This file is obsolete; please update your software."
|
||||
@@ -1,256 +1,140 @@
|
||||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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 HEADER_ASN1ERR_H
|
||||
# define HEADER_ASN1ERR_H
|
||||
#ifndef OPENSSL_ASN1ERR_H
|
||||
#define OPENSSL_ASN1ERR_H
|
||||
#pragma once
|
||||
|
||||
# include <openssl/symhacks.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
int ERR_load_ASN1_strings(void);
|
||||
|
||||
/*
|
||||
* ASN1 function codes.
|
||||
*/
|
||||
# define ASN1_F_A2D_ASN1_OBJECT 100
|
||||
# define ASN1_F_A2I_ASN1_INTEGER 102
|
||||
# define ASN1_F_A2I_ASN1_STRING 103
|
||||
# define ASN1_F_APPEND_EXP 176
|
||||
# define ASN1_F_ASN1_BIO_INIT 113
|
||||
# define ASN1_F_ASN1_BIT_STRING_SET_BIT 183
|
||||
# define ASN1_F_ASN1_CB 177
|
||||
# define ASN1_F_ASN1_CHECK_TLEN 104
|
||||
# define ASN1_F_ASN1_COLLECT 106
|
||||
# define ASN1_F_ASN1_D2I_EX_PRIMITIVE 108
|
||||
# define ASN1_F_ASN1_D2I_FP 109
|
||||
# define ASN1_F_ASN1_D2I_READ_BIO 107
|
||||
# define ASN1_F_ASN1_DIGEST 184
|
||||
# define ASN1_F_ASN1_DO_ADB 110
|
||||
# define ASN1_F_ASN1_DO_LOCK 233
|
||||
# define ASN1_F_ASN1_DUP 111
|
||||
# define ASN1_F_ASN1_ENC_SAVE 115
|
||||
# define ASN1_F_ASN1_EX_C2I 204
|
||||
# define ASN1_F_ASN1_FIND_END 190
|
||||
# define ASN1_F_ASN1_GENERALIZEDTIME_ADJ 216
|
||||
# define ASN1_F_ASN1_GENERATE_V3 178
|
||||
# define ASN1_F_ASN1_GET_INT64 224
|
||||
# define ASN1_F_ASN1_GET_OBJECT 114
|
||||
# define ASN1_F_ASN1_GET_UINT64 225
|
||||
# define ASN1_F_ASN1_I2D_BIO 116
|
||||
# define ASN1_F_ASN1_I2D_FP 117
|
||||
# define ASN1_F_ASN1_ITEM_D2I_FP 206
|
||||
# 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
|
||||
# define ASN1_F_ASN1_ITEM_PACK 198
|
||||
# define ASN1_F_ASN1_ITEM_SIGN 195
|
||||
# define ASN1_F_ASN1_ITEM_SIGN_CTX 220
|
||||
# define ASN1_F_ASN1_ITEM_UNPACK 199
|
||||
# define ASN1_F_ASN1_ITEM_VERIFY 197
|
||||
# define ASN1_F_ASN1_MBSTRING_NCOPY 122
|
||||
# define ASN1_F_ASN1_OBJECT_NEW 123
|
||||
# define ASN1_F_ASN1_OUTPUT_DATA 214
|
||||
# define ASN1_F_ASN1_PCTX_NEW 205
|
||||
# define ASN1_F_ASN1_PRIMITIVE_NEW 119
|
||||
# define ASN1_F_ASN1_SCTX_NEW 221
|
||||
# define ASN1_F_ASN1_SIGN 128
|
||||
# define ASN1_F_ASN1_STR2TYPE 179
|
||||
# define ASN1_F_ASN1_STRING_GET_INT64 227
|
||||
# define ASN1_F_ASN1_STRING_GET_UINT64 230
|
||||
# define ASN1_F_ASN1_STRING_SET 186
|
||||
# define ASN1_F_ASN1_STRING_TABLE_ADD 129
|
||||
# define ASN1_F_ASN1_STRING_TO_BN 228
|
||||
# define ASN1_F_ASN1_STRING_TYPE_NEW 130
|
||||
# define ASN1_F_ASN1_TEMPLATE_EX_D2I 132
|
||||
# define ASN1_F_ASN1_TEMPLATE_NEW 133
|
||||
# define ASN1_F_ASN1_TEMPLATE_NOEXP_D2I 131
|
||||
# define ASN1_F_ASN1_TIME_ADJ 217
|
||||
# define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING 134
|
||||
# define ASN1_F_ASN1_TYPE_GET_OCTETSTRING 135
|
||||
# define ASN1_F_ASN1_UTCTIME_ADJ 218
|
||||
# define ASN1_F_ASN1_VERIFY 137
|
||||
# define ASN1_F_B64_READ_ASN1 209
|
||||
# define ASN1_F_B64_WRITE_ASN1 210
|
||||
# define ASN1_F_BIO_NEW_NDEF 208
|
||||
# define ASN1_F_BITSTR_CB 180
|
||||
# define ASN1_F_BN_TO_ASN1_STRING 229
|
||||
# define ASN1_F_C2I_ASN1_BIT_STRING 189
|
||||
# define ASN1_F_C2I_ASN1_INTEGER 194
|
||||
# define ASN1_F_C2I_ASN1_OBJECT 196
|
||||
# define ASN1_F_C2I_IBUF 226
|
||||
# define ASN1_F_C2I_UINT64_INT 101
|
||||
# define ASN1_F_COLLECT_DATA 140
|
||||
# define ASN1_F_D2I_ASN1_OBJECT 147
|
||||
# define ASN1_F_D2I_ASN1_UINTEGER 150
|
||||
# define ASN1_F_D2I_AUTOPRIVATEKEY 207
|
||||
# define ASN1_F_D2I_PRIVATEKEY 154
|
||||
# define ASN1_F_D2I_PUBLICKEY 155
|
||||
# define ASN1_F_DO_BUF 142
|
||||
# define ASN1_F_DO_CREATE 124
|
||||
# define ASN1_F_DO_DUMP 125
|
||||
# define ASN1_F_DO_TCREATE 222
|
||||
# define ASN1_F_I2A_ASN1_OBJECT 126
|
||||
# define ASN1_F_I2D_ASN1_BIO_STREAM 211
|
||||
# define ASN1_F_I2D_ASN1_OBJECT 143
|
||||
# define ASN1_F_I2D_DSA_PUBKEY 161
|
||||
# define ASN1_F_I2D_EC_PUBKEY 181
|
||||
# define ASN1_F_I2D_PRIVATEKEY 163
|
||||
# define ASN1_F_I2D_PUBLICKEY 164
|
||||
# define ASN1_F_I2D_RSA_PUBKEY 165
|
||||
# define ASN1_F_LONG_C2I 166
|
||||
# define ASN1_F_NDEF_PREFIX 127
|
||||
# define ASN1_F_NDEF_SUFFIX 136
|
||||
# define ASN1_F_OID_MODULE_INIT 174
|
||||
# define ASN1_F_PARSE_TAGGING 182
|
||||
# define ASN1_F_PKCS5_PBE2_SET_IV 167
|
||||
# define ASN1_F_PKCS5_PBE2_SET_SCRYPT 231
|
||||
# define ASN1_F_PKCS5_PBE_SET 202
|
||||
# define ASN1_F_PKCS5_PBE_SET0_ALGOR 215
|
||||
# define ASN1_F_PKCS5_PBKDF2_SET 219
|
||||
# define ASN1_F_PKCS5_SCRYPT_SET 232
|
||||
# define ASN1_F_SMIME_READ_ASN1 212
|
||||
# define ASN1_F_SMIME_TEXT 213
|
||||
# define ASN1_F_STABLE_GET 138
|
||||
# define ASN1_F_STBL_MODULE_INIT 223
|
||||
# define ASN1_F_UINT32_C2I 105
|
||||
# define ASN1_F_UINT32_NEW 139
|
||||
# define ASN1_F_UINT64_C2I 112
|
||||
# define ASN1_F_UINT64_NEW 141
|
||||
# define ASN1_F_X509_CRL_ADD0_REVOKED 169
|
||||
# define ASN1_F_X509_INFO_NEW 170
|
||||
# define ASN1_F_X509_NAME_ENCODE 203
|
||||
# define ASN1_F_X509_NAME_EX_D2I 158
|
||||
# define ASN1_F_X509_NAME_EX_NEW 171
|
||||
# define ASN1_F_X509_PKEY_NEW 173
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/symhacks.h>
|
||||
#include <openssl/cryptoerr_legacy.h>
|
||||
|
||||
/*
|
||||
* ASN1 reason codes.
|
||||
*/
|
||||
# define ASN1_R_ADDING_OBJECT 171
|
||||
# define ASN1_R_ASN1_PARSE_ERROR 203
|
||||
# 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
|
||||
# define ASN1_R_BUFFER_TOO_SMALL 107
|
||||
# define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108
|
||||
# define ASN1_R_CONTEXT_NOT_INITIALISED 217
|
||||
# define ASN1_R_DATA_IS_WRONG 109
|
||||
# define ASN1_R_DECODE_ERROR 110
|
||||
# define ASN1_R_DEPTH_EXCEEDED 174
|
||||
# define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 198
|
||||
# define ASN1_R_ENCODE_ERROR 112
|
||||
# define ASN1_R_ERROR_GETTING_TIME 173
|
||||
# define ASN1_R_ERROR_LOADING_SECTION 172
|
||||
# define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114
|
||||
# define ASN1_R_EXPECTING_AN_INTEGER 115
|
||||
# define ASN1_R_EXPECTING_AN_OBJECT 116
|
||||
# define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119
|
||||
# define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120
|
||||
# define ASN1_R_FIELD_MISSING 121
|
||||
# define ASN1_R_FIRST_NUM_TOO_LARGE 122
|
||||
# define ASN1_R_HEADER_TOO_LONG 123
|
||||
# define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175
|
||||
# define ASN1_R_ILLEGAL_BOOLEAN 176
|
||||
# define ASN1_R_ILLEGAL_CHARACTERS 124
|
||||
# define ASN1_R_ILLEGAL_FORMAT 177
|
||||
# define ASN1_R_ILLEGAL_HEX 178
|
||||
# define ASN1_R_ILLEGAL_IMPLICIT_TAG 179
|
||||
# define ASN1_R_ILLEGAL_INTEGER 180
|
||||
# define ASN1_R_ILLEGAL_NEGATIVE_VALUE 226
|
||||
# define ASN1_R_ILLEGAL_NESTED_TAGGING 181
|
||||
# define ASN1_R_ILLEGAL_NULL 125
|
||||
# define ASN1_R_ILLEGAL_NULL_VALUE 182
|
||||
# define ASN1_R_ILLEGAL_OBJECT 183
|
||||
# define ASN1_R_ILLEGAL_OPTIONAL_ANY 126
|
||||
# define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170
|
||||
# define ASN1_R_ILLEGAL_PADDING 221
|
||||
# define ASN1_R_ILLEGAL_TAGGED_ANY 127
|
||||
# define ASN1_R_ILLEGAL_TIME_VALUE 184
|
||||
# define ASN1_R_ILLEGAL_ZERO_CONTENT 222
|
||||
# define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185
|
||||
# define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128
|
||||
# define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 220
|
||||
# define ASN1_R_INVALID_BMPSTRING_LENGTH 129
|
||||
# define ASN1_R_INVALID_DIGIT 130
|
||||
# define ASN1_R_INVALID_MIME_TYPE 205
|
||||
# define ASN1_R_INVALID_MODIFIER 186
|
||||
# define ASN1_R_INVALID_NUMBER 187
|
||||
# define ASN1_R_INVALID_OBJECT_ENCODING 216
|
||||
# define ASN1_R_INVALID_SCRYPT_PARAMETERS 227
|
||||
# define ASN1_R_INVALID_SEPARATOR 131
|
||||
# define ASN1_R_INVALID_STRING_TABLE_VALUE 218
|
||||
# define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133
|
||||
# define ASN1_R_INVALID_UTF8STRING 134
|
||||
# define ASN1_R_INVALID_VALUE 219
|
||||
# define ASN1_R_LIST_ERROR 188
|
||||
# define ASN1_R_MIME_NO_CONTENT_TYPE 206
|
||||
# define ASN1_R_MIME_PARSE_ERROR 207
|
||||
# define ASN1_R_MIME_SIG_PARSE_ERROR 208
|
||||
# define ASN1_R_MISSING_EOC 137
|
||||
# define ASN1_R_MISSING_SECOND_NUMBER 138
|
||||
# define ASN1_R_MISSING_VALUE 189
|
||||
# define ASN1_R_MSTRING_NOT_UNIVERSAL 139
|
||||
# define ASN1_R_MSTRING_WRONG_TAG 140
|
||||
# define ASN1_R_NESTED_ASN1_STRING 197
|
||||
# define ASN1_R_NESTED_TOO_DEEP 201
|
||||
# define ASN1_R_NON_HEX_CHARACTERS 141
|
||||
# define ASN1_R_NOT_ASCII_FORMAT 190
|
||||
# define ASN1_R_NOT_ENOUGH_DATA 142
|
||||
# define ASN1_R_NO_CONTENT_TYPE 209
|
||||
# define ASN1_R_NO_MATCHING_CHOICE_TYPE 143
|
||||
# define ASN1_R_NO_MULTIPART_BODY_FAILURE 210
|
||||
# define ASN1_R_NO_MULTIPART_BOUNDARY 211
|
||||
# define ASN1_R_NO_SIG_CONTENT_TYPE 212
|
||||
# define ASN1_R_NULL_IS_WRONG_LENGTH 144
|
||||
# define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191
|
||||
# define ASN1_R_ODD_NUMBER_OF_CHARS 145
|
||||
# define ASN1_R_SECOND_NUMBER_TOO_LARGE 147
|
||||
# define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148
|
||||
# define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149
|
||||
# define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192
|
||||
# define ASN1_R_SHORT_LINE 150
|
||||
# define ASN1_R_SIG_INVALID_MIME_TYPE 213
|
||||
# define ASN1_R_STREAMING_NOT_SUPPORTED 202
|
||||
# define ASN1_R_STRING_TOO_LONG 151
|
||||
# define ASN1_R_STRING_TOO_SHORT 152
|
||||
# define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154
|
||||
# define ASN1_R_TIME_NOT_ASCII_FORMAT 193
|
||||
# define ASN1_R_TOO_LARGE 223
|
||||
# define ASN1_R_TOO_LONG 155
|
||||
# define ASN1_R_TOO_SMALL 224
|
||||
# define ASN1_R_TYPE_NOT_CONSTRUCTED 156
|
||||
# define ASN1_R_TYPE_NOT_PRIMITIVE 195
|
||||
# define ASN1_R_UNEXPECTED_EOC 159
|
||||
# define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215
|
||||
# define ASN1_R_UNKNOWN_FORMAT 160
|
||||
# define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161
|
||||
# define ASN1_R_UNKNOWN_OBJECT_TYPE 162
|
||||
# define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163
|
||||
# define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 199
|
||||
# define ASN1_R_UNKNOWN_TAG 194
|
||||
# define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164
|
||||
# define ASN1_R_UNSUPPORTED_CIPHER 228
|
||||
# define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167
|
||||
# define ASN1_R_UNSUPPORTED_TYPE 196
|
||||
# define ASN1_R_WRONG_INTEGER_TYPE 225
|
||||
# define ASN1_R_WRONG_PUBLIC_KEY_TYPE 200
|
||||
# define ASN1_R_WRONG_TAG 168
|
||||
#define ASN1_R_ADDING_OBJECT 171
|
||||
#define ASN1_R_ASN1_PARSE_ERROR 203
|
||||
#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
|
||||
#define ASN1_R_BUFFER_TOO_SMALL 107
|
||||
#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 108
|
||||
#define ASN1_R_CONTEXT_NOT_INITIALISED 217
|
||||
#define ASN1_R_DATA_IS_WRONG 109
|
||||
#define ASN1_R_DECODE_ERROR 110
|
||||
#define ASN1_R_DEPTH_EXCEEDED 174
|
||||
#define ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 198
|
||||
#define ASN1_R_ENCODE_ERROR 112
|
||||
#define ASN1_R_ERROR_GETTING_TIME 173
|
||||
#define ASN1_R_ERROR_LOADING_SECTION 172
|
||||
#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS 114
|
||||
#define ASN1_R_EXPECTING_AN_INTEGER 115
|
||||
#define ASN1_R_EXPECTING_AN_OBJECT 116
|
||||
#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 119
|
||||
#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 120
|
||||
#define ASN1_R_FIELD_MISSING 121
|
||||
#define ASN1_R_FIRST_NUM_TOO_LARGE 122
|
||||
#define ASN1_R_GENERALIZEDTIME_IS_TOO_SHORT 232
|
||||
#define ASN1_R_HEADER_TOO_LONG 123
|
||||
#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 175
|
||||
#define ASN1_R_ILLEGAL_BOOLEAN 176
|
||||
#define ASN1_R_ILLEGAL_CHARACTERS 124
|
||||
#define ASN1_R_ILLEGAL_FORMAT 177
|
||||
#define ASN1_R_ILLEGAL_HEX 178
|
||||
#define ASN1_R_ILLEGAL_IMPLICIT_TAG 179
|
||||
#define ASN1_R_ILLEGAL_INTEGER 180
|
||||
#define ASN1_R_ILLEGAL_NEGATIVE_VALUE 226
|
||||
#define ASN1_R_ILLEGAL_NESTED_TAGGING 181
|
||||
#define ASN1_R_ILLEGAL_NULL 125
|
||||
#define ASN1_R_ILLEGAL_NULL_VALUE 182
|
||||
#define ASN1_R_ILLEGAL_OBJECT 183
|
||||
#define ASN1_R_ILLEGAL_OPTIONAL_ANY 126
|
||||
#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 170
|
||||
#define ASN1_R_ILLEGAL_PADDING 221
|
||||
#define ASN1_R_ILLEGAL_TAGGED_ANY 127
|
||||
#define ASN1_R_ILLEGAL_TIME_VALUE 184
|
||||
#define ASN1_R_ILLEGAL_ZERO_CONTENT 222
|
||||
#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 185
|
||||
#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 128
|
||||
#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 220
|
||||
#define ASN1_R_INVALID_BMPSTRING_LENGTH 129
|
||||
#define ASN1_R_INVALID_DIGIT 130
|
||||
#define ASN1_R_INVALID_MIME_TYPE 205
|
||||
#define ASN1_R_INVALID_MODIFIER 186
|
||||
#define ASN1_R_INVALID_NUMBER 187
|
||||
#define ASN1_R_INVALID_OBJECT_ENCODING 216
|
||||
#define ASN1_R_INVALID_SCRYPT_PARAMETERS 227
|
||||
#define ASN1_R_INVALID_SEPARATOR 131
|
||||
#define ASN1_R_INVALID_STRING_TABLE_VALUE 218
|
||||
#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 133
|
||||
#define ASN1_R_INVALID_UTF8STRING 134
|
||||
#define ASN1_R_INVALID_VALUE 219
|
||||
#define ASN1_R_LENGTH_TOO_LONG 231
|
||||
#define ASN1_R_LIST_ERROR 188
|
||||
#define ASN1_R_MIME_NO_CONTENT_TYPE 206
|
||||
#define ASN1_R_MIME_PARSE_ERROR 207
|
||||
#define ASN1_R_MIME_SIG_PARSE_ERROR 208
|
||||
#define ASN1_R_MISSING_EOC 137
|
||||
#define ASN1_R_MISSING_SECOND_NUMBER 138
|
||||
#define ASN1_R_MISSING_VALUE 189
|
||||
#define ASN1_R_MSTRING_NOT_UNIVERSAL 139
|
||||
#define ASN1_R_MSTRING_WRONG_TAG 140
|
||||
#define ASN1_R_NESTED_ASN1_STRING 197
|
||||
#define ASN1_R_NESTED_TOO_DEEP 201
|
||||
#define ASN1_R_NON_HEX_CHARACTERS 141
|
||||
#define ASN1_R_NOT_ASCII_FORMAT 190
|
||||
#define ASN1_R_NOT_ENOUGH_DATA 142
|
||||
#define ASN1_R_NO_CONTENT_TYPE 209
|
||||
#define ASN1_R_NO_MATCHING_CHOICE_TYPE 143
|
||||
#define ASN1_R_NO_MULTIPART_BODY_FAILURE 210
|
||||
#define ASN1_R_NO_MULTIPART_BOUNDARY 211
|
||||
#define ASN1_R_NO_SIG_CONTENT_TYPE 212
|
||||
#define ASN1_R_NULL_IS_WRONG_LENGTH 144
|
||||
#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 191
|
||||
#define ASN1_R_ODD_NUMBER_OF_CHARS 145
|
||||
#define ASN1_R_SECOND_NUMBER_TOO_LARGE 147
|
||||
#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 148
|
||||
#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 149
|
||||
#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 192
|
||||
#define ASN1_R_SHORT_LINE 150
|
||||
#define ASN1_R_SIG_INVALID_MIME_TYPE 213
|
||||
#define ASN1_R_STREAMING_NOT_SUPPORTED 202
|
||||
#define ASN1_R_STRING_TOO_LONG 151
|
||||
#define ASN1_R_STRING_TOO_SHORT 152
|
||||
#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154
|
||||
#define ASN1_R_TIME_NOT_ASCII_FORMAT 193
|
||||
#define ASN1_R_TOO_LARGE 223
|
||||
#define ASN1_R_TOO_LONG 155
|
||||
#define ASN1_R_TOO_SMALL 224
|
||||
#define ASN1_R_TYPE_NOT_CONSTRUCTED 156
|
||||
#define ASN1_R_TYPE_NOT_PRIMITIVE 195
|
||||
#define ASN1_R_UNEXPECTED_EOC 159
|
||||
#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 215
|
||||
#define ASN1_R_UNKNOWN_DIGEST 229
|
||||
#define ASN1_R_UNKNOWN_FORMAT 160
|
||||
#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 161
|
||||
#define ASN1_R_UNKNOWN_OBJECT_TYPE 162
|
||||
#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE 163
|
||||
#define ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM 199
|
||||
#define ASN1_R_UNKNOWN_TAG 194
|
||||
#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 164
|
||||
#define ASN1_R_UNSUPPORTED_CIPHER 228
|
||||
#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 167
|
||||
#define ASN1_R_UNSUPPORTED_TYPE 196
|
||||
#define ASN1_R_UTCTIME_IS_TOO_SHORT 233
|
||||
#define ASN1_R_WRONG_INTEGER_TYPE 225
|
||||
#define ASN1_R_WRONG_PUBLIC_KEY_TYPE 200
|
||||
#define ASN1_R_WRONG_TAG 168
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright 2015-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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
|
||||
@@ -9,33 +9,44 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef HEADER_ASYNC_H
|
||||
# define HEADER_ASYNC_H
|
||||
#ifndef OPENSSL_ASYNC_H
|
||||
#define OPENSSL_ASYNC_H
|
||||
#pragma once
|
||||
|
||||
#include <openssl/macros.h>
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
#define HEADER_ASYNC_H
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
# if defined(BASETYPES) || defined(_WINDEF_H)
|
||||
#if defined(BASETYPES) || defined(_WINDEF_H)
|
||||
/* application has to include <windows.h> to use this */
|
||||
#define OSSL_ASYNC_FD HANDLE
|
||||
#define OSSL_BAD_ASYNC_FD INVALID_HANDLE_VALUE
|
||||
# endif
|
||||
#else
|
||||
#define OSSL_ASYNC_FD int
|
||||
#define OSSL_BAD_ASYNC_FD -1
|
||||
#define OSSL_ASYNC_FD HANDLE
|
||||
#define OSSL_BAD_ASYNC_FD INVALID_HANDLE_VALUE
|
||||
#endif
|
||||
# include <openssl/asyncerr.h>
|
||||
#else
|
||||
#define OSSL_ASYNC_FD int
|
||||
#define OSSL_BAD_ASYNC_FD -1
|
||||
#endif
|
||||
#include <openssl/asyncerr.h>
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct async_job_st ASYNC_JOB;
|
||||
typedef struct async_wait_ctx_st ASYNC_WAIT_CTX;
|
||||
typedef int (*ASYNC_callback_fn)(void *arg);
|
||||
|
||||
#define ASYNC_ERR 0
|
||||
#define ASYNC_NO_JOBS 1
|
||||
#define ASYNC_PAUSE 2
|
||||
#define ASYNC_FINISH 3
|
||||
#define ASYNC_ERR 0
|
||||
#define ASYNC_NO_JOBS 1
|
||||
#define ASYNC_PAUSE 2
|
||||
#define ASYNC_FINISH 3
|
||||
|
||||
#define ASYNC_STATUS_UNSUPPORTED 0
|
||||
#define ASYNC_STATUS_ERR 1
|
||||
#define ASYNC_STATUS_OK 2
|
||||
#define ASYNC_STATUS_EAGAIN 3
|
||||
|
||||
int ASYNC_init_thread(size_t max_size, size_t init_size);
|
||||
void ASYNC_cleanup_thread(void);
|
||||
@@ -44,24 +55,40 @@ void ASYNC_cleanup_thread(void);
|
||||
ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
|
||||
void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
|
||||
int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
|
||||
OSSL_ASYNC_FD fd,
|
||||
void *custom_data,
|
||||
void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
|
||||
OSSL_ASYNC_FD, void *));
|
||||
OSSL_ASYNC_FD fd,
|
||||
void *custom_data,
|
||||
void (*cleanup)(ASYNC_WAIT_CTX *, const void *,
|
||||
OSSL_ASYNC_FD, void *));
|
||||
int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
|
||||
OSSL_ASYNC_FD *fd, void **custom_data);
|
||||
OSSL_ASYNC_FD *fd, void **custom_data);
|
||||
int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
|
||||
size_t *numfds);
|
||||
size_t *numfds);
|
||||
int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
|
||||
ASYNC_callback_fn *callback,
|
||||
void **callback_arg);
|
||||
int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
|
||||
ASYNC_callback_fn callback,
|
||||
void *callback_arg);
|
||||
int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
|
||||
int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
|
||||
int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
|
||||
size_t *numaddfds, OSSL_ASYNC_FD *delfd,
|
||||
size_t *numdelfds);
|
||||
size_t *numaddfds, OSSL_ASYNC_FD *delfd,
|
||||
size_t *numdelfds);
|
||||
int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
|
||||
#endif
|
||||
|
||||
int ASYNC_is_capable(void);
|
||||
|
||||
typedef void *(*ASYNC_stack_alloc_fn)(size_t *num);
|
||||
typedef void (*ASYNC_stack_free_fn)(void *addr);
|
||||
|
||||
int ASYNC_set_mem_functions(ASYNC_stack_alloc_fn alloc_fn,
|
||||
ASYNC_stack_free_fn free_fn);
|
||||
void ASYNC_get_mem_functions(ASYNC_stack_alloc_fn *alloc_fn,
|
||||
ASYNC_stack_free_fn *free_fn);
|
||||
|
||||
int ASYNC_start_job(ASYNC_JOB **job, ASYNC_WAIT_CTX *ctx, int *ret,
|
||||
int (*func)(void *), void *args, size_t size);
|
||||
int (*func)(void *), void *args, size_t size);
|
||||
int ASYNC_pause_job(void);
|
||||
|
||||
ASYNC_JOB *ASYNC_get_current_job(void);
|
||||
@@ -69,8 +96,7 @@ ASYNC_WAIT_CTX *ASYNC_get_wait_ctx(ASYNC_JOB *job);
|
||||
void ASYNC_block_pause(void);
|
||||
void ASYNC_unblock_pause(void);
|
||||
|
||||
|
||||
# ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,42 +1,27 @@
|
||||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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 HEADER_ASYNCERR_H
|
||||
# define HEADER_ASYNCERR_H
|
||||
#ifndef OPENSSL_ASYNCERR_H
|
||||
#define OPENSSL_ASYNCERR_H
|
||||
#pragma once
|
||||
|
||||
# ifndef HEADER_SYMHACKS_H
|
||||
# include <openssl/symhacks.h>
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
int ERR_load_ASYNC_strings(void);
|
||||
|
||||
/*
|
||||
* ASYNC function codes.
|
||||
*/
|
||||
# define ASYNC_F_ASYNC_CTX_NEW 100
|
||||
# define ASYNC_F_ASYNC_INIT_THREAD 101
|
||||
# define ASYNC_F_ASYNC_JOB_NEW 102
|
||||
# define ASYNC_F_ASYNC_PAUSE_JOB 103
|
||||
# define ASYNC_F_ASYNC_START_FUNC 104
|
||||
# define ASYNC_F_ASYNC_START_JOB 105
|
||||
# define ASYNC_F_ASYNC_WAIT_CTX_SET_WAIT_FD 106
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/symhacks.h>
|
||||
#include <openssl/cryptoerr_legacy.h>
|
||||
|
||||
/*
|
||||
* ASYNC reason codes.
|
||||
*/
|
||||
# define ASYNC_R_FAILED_TO_SET_POOL 101
|
||||
# define ASYNC_R_FAILED_TO_SWAP_CONTEXT 102
|
||||
# define ASYNC_R_INIT_FAILED 105
|
||||
# define ASYNC_R_INVALID_POOL_SIZE 103
|
||||
#define ASYNC_R_FAILED_TO_SET_POOL 101
|
||||
#define ASYNC_R_FAILED_TO_SWAP_CONTEXT 102
|
||||
#define ASYNC_R_INIT_FAILED 105
|
||||
#define ASYNC_R_INVALID_POOL_SIZE 103
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,124 +1,70 @@
|
||||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved.
|
||||
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* 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 HEADER_BIOERR_H
|
||||
# define HEADER_BIOERR_H
|
||||
#ifndef OPENSSL_BIOERR_H
|
||||
#define OPENSSL_BIOERR_H
|
||||
#pragma once
|
||||
|
||||
# ifndef HEADER_SYMHACKS_H
|
||||
# include <openssl/symhacks.h>
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
int ERR_load_BIO_strings(void);
|
||||
|
||||
/*
|
||||
* BIO function codes.
|
||||
*/
|
||||
# define BIO_F_ACPT_STATE 100
|
||||
# define BIO_F_ADDRINFO_WRAP 148
|
||||
# define BIO_F_ADDR_STRINGS 134
|
||||
# define BIO_F_BIO_ACCEPT 101
|
||||
# define BIO_F_BIO_ACCEPT_EX 137
|
||||
# define BIO_F_BIO_ACCEPT_NEW 152
|
||||
# define BIO_F_BIO_ADDR_NEW 144
|
||||
# define BIO_F_BIO_BIND 147
|
||||
# define BIO_F_BIO_CALLBACK_CTRL 131
|
||||
# define BIO_F_BIO_CONNECT 138
|
||||
# define BIO_F_BIO_CONNECT_NEW 153
|
||||
# define BIO_F_BIO_CTRL 103
|
||||
# define BIO_F_BIO_GETS 104
|
||||
# define BIO_F_BIO_GET_HOST_IP 106
|
||||
# define BIO_F_BIO_GET_NEW_INDEX 102
|
||||
# define BIO_F_BIO_GET_PORT 107
|
||||
# define BIO_F_BIO_LISTEN 139
|
||||
# define BIO_F_BIO_LOOKUP 135
|
||||
# define BIO_F_BIO_LOOKUP_EX 143
|
||||
# define BIO_F_BIO_MAKE_PAIR 121
|
||||
# define BIO_F_BIO_METH_NEW 146
|
||||
# define BIO_F_BIO_NEW 108
|
||||
# define BIO_F_BIO_NEW_DGRAM_SCTP 145
|
||||
# define BIO_F_BIO_NEW_FILE 109
|
||||
# define BIO_F_BIO_NEW_MEM_BUF 126
|
||||
# define BIO_F_BIO_NREAD 123
|
||||
# define BIO_F_BIO_NREAD0 124
|
||||
# define BIO_F_BIO_NWRITE 125
|
||||
# define BIO_F_BIO_NWRITE0 122
|
||||
# define BIO_F_BIO_PARSE_HOSTSERV 136
|
||||
# define BIO_F_BIO_PUTS 110
|
||||
# define BIO_F_BIO_READ 111
|
||||
# define BIO_F_BIO_READ_EX 105
|
||||
# define BIO_F_BIO_READ_INTERN 120
|
||||
# define BIO_F_BIO_SOCKET 140
|
||||
# define BIO_F_BIO_SOCKET_NBIO 142
|
||||
# define BIO_F_BIO_SOCK_INFO 141
|
||||
# define BIO_F_BIO_SOCK_INIT 112
|
||||
# define BIO_F_BIO_WRITE 113
|
||||
# define BIO_F_BIO_WRITE_EX 119
|
||||
# define BIO_F_BIO_WRITE_INTERN 128
|
||||
# define BIO_F_BUFFER_CTRL 114
|
||||
# define BIO_F_CONN_CTRL 127
|
||||
# define BIO_F_CONN_STATE 115
|
||||
# define BIO_F_DGRAM_SCTP_NEW 149
|
||||
# define BIO_F_DGRAM_SCTP_READ 132
|
||||
# define BIO_F_DGRAM_SCTP_WRITE 133
|
||||
# define BIO_F_DOAPR_OUTCH 150
|
||||
# define BIO_F_FILE_CTRL 116
|
||||
# define BIO_F_FILE_READ 130
|
||||
# define BIO_F_LINEBUFFER_CTRL 129
|
||||
# define BIO_F_LINEBUFFER_NEW 151
|
||||
# define BIO_F_MEM_WRITE 117
|
||||
# define BIO_F_NBIOF_NEW 154
|
||||
# define BIO_F_SLG_WRITE 155
|
||||
# define BIO_F_SSL_NEW 118
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <openssl/symhacks.h>
|
||||
#include <openssl/cryptoerr_legacy.h>
|
||||
|
||||
/*
|
||||
* BIO reason codes.
|
||||
*/
|
||||
# define BIO_R_ACCEPT_ERROR 100
|
||||
# define BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET 141
|
||||
# define BIO_R_AMBIGUOUS_HOST_OR_SERVICE 129
|
||||
# define BIO_R_BAD_FOPEN_MODE 101
|
||||
# define BIO_R_BROKEN_PIPE 124
|
||||
# define BIO_R_CONNECT_ERROR 103
|
||||
# define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107
|
||||
# define BIO_R_GETSOCKNAME_ERROR 132
|
||||
# define BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS 133
|
||||
# define BIO_R_GETTING_SOCKTYPE 134
|
||||
# define BIO_R_INVALID_ARGUMENT 125
|
||||
# define BIO_R_INVALID_SOCKET 135
|
||||
# define BIO_R_IN_USE 123
|
||||
# define BIO_R_LENGTH_TOO_LONG 102
|
||||
# define BIO_R_LISTEN_V6_ONLY 136
|
||||
# define BIO_R_LOOKUP_RETURNED_NOTHING 142
|
||||
# define BIO_R_MALFORMED_HOST_OR_SERVICE 130
|
||||
# define BIO_R_NBIO_CONNECT_ERROR 110
|
||||
# define BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED 143
|
||||
# define BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED 144
|
||||
# define BIO_R_NO_PORT_DEFINED 113
|
||||
# define BIO_R_NO_SUCH_FILE 128
|
||||
# define BIO_R_NULL_PARAMETER 115
|
||||
# define BIO_R_UNABLE_TO_BIND_SOCKET 117
|
||||
# define BIO_R_UNABLE_TO_CREATE_SOCKET 118
|
||||
# define BIO_R_UNABLE_TO_KEEPALIVE 137
|
||||
# define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
|
||||
# define BIO_R_UNABLE_TO_NODELAY 138
|
||||
# define BIO_R_UNABLE_TO_REUSEADDR 139
|
||||
# define BIO_R_UNAVAILABLE_IP_FAMILY 145
|
||||
# define BIO_R_UNINITIALIZED 120
|
||||
# define BIO_R_UNKNOWN_INFO_TYPE 140
|
||||
# define BIO_R_UNSUPPORTED_IP_FAMILY 146
|
||||
# define BIO_R_UNSUPPORTED_METHOD 121
|
||||
# define BIO_R_UNSUPPORTED_PROTOCOL_FAMILY 131
|
||||
# define BIO_R_WRITE_TO_READ_ONLY_BIO 126
|
||||
# define BIO_R_WSASTARTUP 122
|
||||
#define BIO_R_ACCEPT_ERROR 100
|
||||
#define BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET 141
|
||||
#define BIO_R_AMBIGUOUS_HOST_OR_SERVICE 129
|
||||
#define BIO_R_BAD_FOPEN_MODE 101
|
||||
#define BIO_R_BROKEN_PIPE 124
|
||||
#define BIO_R_CONNECT_ERROR 103
|
||||
#define BIO_R_CONNECT_TIMEOUT 147
|
||||
#define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET 107
|
||||
#define BIO_R_GETSOCKNAME_ERROR 132
|
||||
#define BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS 133
|
||||
#define BIO_R_GETTING_SOCKTYPE 134
|
||||
#define BIO_R_INVALID_ARGUMENT 125
|
||||
#define BIO_R_INVALID_SOCKET 135
|
||||
#define BIO_R_IN_USE 123
|
||||
#define BIO_R_LENGTH_TOO_LONG 102
|
||||
#define BIO_R_LISTEN_V6_ONLY 136
|
||||
#define BIO_R_LOCAL_ADDR_NOT_AVAILABLE 111
|
||||
#define BIO_R_LOOKUP_RETURNED_NOTHING 142
|
||||
#define BIO_R_MALFORMED_HOST_OR_SERVICE 130
|
||||
#define BIO_R_NBIO_CONNECT_ERROR 110
|
||||
#define BIO_R_NON_FATAL 112
|
||||
#define BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED 143
|
||||
#define BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED 144
|
||||
#define BIO_R_NO_PORT_DEFINED 113
|
||||
#define BIO_R_NO_SUCH_FILE 128
|
||||
#define BIO_R_NULL_PARAMETER 115 /* unused */
|
||||
#define BIO_R_TFO_DISABLED 106
|
||||
#define BIO_R_TFO_NO_KERNEL_SUPPORT 108
|
||||
#define BIO_R_TRANSFER_ERROR 104
|
||||
#define BIO_R_TRANSFER_TIMEOUT 105
|
||||
#define BIO_R_UNABLE_TO_BIND_SOCKET 117
|
||||
#define BIO_R_UNABLE_TO_CREATE_SOCKET 118
|
||||
#define BIO_R_UNABLE_TO_KEEPALIVE 137
|
||||
#define BIO_R_UNABLE_TO_LISTEN_SOCKET 119
|
||||
#define BIO_R_UNABLE_TO_NODELAY 138
|
||||
#define BIO_R_UNABLE_TO_REUSEADDR 139
|
||||
#define BIO_R_UNABLE_TO_TFO 109
|
||||
#define BIO_R_UNAVAILABLE_IP_FAMILY 145
|
||||
#define BIO_R_UNINITIALIZED 120
|
||||
#define BIO_R_UNKNOWN_INFO_TYPE 140
|
||||
#define BIO_R_UNSUPPORTED_IP_FAMILY 146
|
||||
#define BIO_R_UNSUPPORTED_METHOD 121
|
||||
#define BIO_R_UNSUPPORTED_PROTOCOL_FAMILY 131
|
||||
#define BIO_R_WRITE_TO_READ_ONLY_BIO 126
|
||||
#define BIO_R_WSASTARTUP 122
|
||||
#define BIO_R_PORT_MISMATCH 150
|
||||
#define BIO_R_PEER_ADDR_NOT_AVAILABLE 151
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user