Compare commits
262 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1371ccc766 | ||
|
|
2e3643235f | ||
|
|
56a746b1ae | ||
|
|
086d4d1152 | ||
|
|
85c112a978 | ||
|
|
81b3b2c2b4 | ||
|
|
12d325ec2f | ||
|
|
300eef544c | ||
|
|
9f918ad0da | ||
|
|
c7134a48db | ||
|
|
b06b146824 | ||
|
|
4061330467 | ||
|
|
1f79d70b00 | ||
|
|
2427d4cef5 | ||
|
|
f8bfbb5b7c | ||
|
|
9045844d00 | ||
|
|
babba295a9 | ||
|
|
dbe0a54469 | ||
|
|
6a4caeacac | ||
|
|
72f4ee829f | ||
|
|
61176368bb | ||
|
|
f4eca63944 | ||
|
|
13c22ea16f | ||
|
|
11de8f49ff | ||
|
|
0eeaec548e | ||
|
|
a191915b9d | ||
|
|
ce52398dc5 | ||
|
|
dccd8ec7ef | ||
|
|
b55f604294 | ||
|
|
eb458c1ad2 | ||
|
|
aaa1ca7079 | ||
|
|
ab3aac8d05 | ||
|
|
6c47627f85 | ||
|
|
07f9e7e576 | ||
|
|
f16299ebcc | ||
|
|
b2bee37fe2 | ||
|
|
fb2258fa34 | ||
|
|
56d9e75d2b | ||
|
|
7ae0e0dd48 | ||
|
|
578ff79a88 | ||
|
|
ec90adfb42 | ||
|
|
22dd617d87 | ||
|
|
74d97a04c2 | ||
|
|
f91787793e | ||
|
|
661edf2466 | ||
|
|
765e104cb3 | ||
|
|
6b053e4e71 | ||
|
|
29a5663980 | ||
|
|
1bba410f69 | ||
|
|
751c2f8d2e | ||
|
|
f0585f6c06 | ||
|
|
97eb58d8b5 | ||
|
|
471c3d3259 | ||
|
|
584f9475e2 | ||
|
|
ccc1dfb426 | ||
|
|
21876c6b8d | ||
|
|
19ef75e170 | ||
|
|
e20749927b | ||
|
|
f212c6e8ad | ||
|
|
fb31cb6bb5 | ||
|
|
72624335f1 | ||
|
|
09b10d81e8 | ||
|
|
04fbabc0f2 | ||
|
|
7f11ab3d84 | ||
|
|
000dc49ad9 | ||
|
|
5d59723df8 | ||
|
|
abb977970c | ||
|
|
7da5e83864 | ||
|
|
aa9b7652d9 | ||
|
|
6221f62c12 | ||
|
|
31f35b16fa | ||
|
|
569f670f9d | ||
|
|
f17dd82b09 | ||
|
|
0c3b45d7c2 | ||
|
|
f4d9265712 | ||
|
|
e3274893b6 | ||
|
|
747f8b7f55 | ||
|
|
417950d7da | ||
|
|
f5788296ac | ||
|
|
e83c9ccd10 | ||
|
|
232e3c57f3 | ||
|
|
fbc1e83ebe | ||
|
|
be7b87797b | ||
|
|
9255884af4 | ||
|
|
22e0d2f171 | ||
|
|
cf9c112995 | ||
|
|
7acc19bd3e | ||
|
|
643cc6d128 | ||
|
|
8a962927ed | ||
|
|
7174ad265d | ||
|
|
2a34e15858 | ||
|
|
733d27ed9e | ||
|
|
227e1d7c62 | ||
|
|
66b435d9f9 | ||
|
|
37cdf16834 | ||
|
|
d9a09fe450 | ||
|
|
d76f932e85 | ||
|
|
75d141d8a8 | ||
|
|
ae6e6f6400 | ||
|
|
f1e789abe5 | ||
|
|
97df7bf58c | ||
|
|
12e5158b46 | ||
|
|
138f0ef40b | ||
|
|
e05a0ef1eb | ||
|
|
884ed26152 | ||
|
|
06ab7b8673 | ||
|
|
3c3f207963 | ||
|
|
80d65e7b50 | ||
|
|
31f7ee835f | ||
|
|
dc1c515958 | ||
|
|
e56db8e6fe | ||
|
|
80eec4928c | ||
|
|
ce70b18bdb | ||
|
|
7e65e6963a | ||
|
|
7471853652 | ||
|
|
9c2bfeb4e0 | ||
|
|
d072e0d142 | ||
|
|
b2418acf7c | ||
|
|
11d7b2125e | ||
|
|
a3a2b4bdaa | ||
|
|
87f6f14af6 | ||
|
|
b48cb3d069 | ||
|
|
9738b1bbc2 | ||
|
|
3764f7dae4 | ||
|
|
7d9229359a | ||
|
|
ab2865b71e | ||
|
|
c3453ce2b8 | ||
|
|
6729bb64f8 | ||
|
|
b993edae58 | ||
|
|
ee803c6247 | ||
|
|
6a6022cda7 | ||
|
|
f9438bec26 | ||
|
|
02edd06b63 | ||
|
|
db49a33a0f | ||
|
|
d19bc0ca7d | ||
|
|
0ddf07f4de | ||
|
|
ecad4aa276 | ||
|
|
065445d721 | ||
|
|
bb452520fc | ||
|
|
6d60e02341 | ||
|
|
7f9c71805e | ||
|
|
e6f4247ae8 | ||
|
|
9536c3f8c8 | ||
|
|
918b528648 | ||
|
|
4613d4977c | ||
|
|
cb80160605 | ||
|
|
fbd9319605 | ||
|
|
a76c1ab6a1 | ||
|
|
2f72f7e555 | ||
|
|
1d7b94ccaf | ||
|
|
3ce617a304 | ||
|
|
a8f55452f0 | ||
|
|
754173543a | ||
|
|
1194556b9c | ||
|
|
7dc7df792a | ||
|
|
ccfcfff9a4 | ||
|
|
e1dad1d65b | ||
|
|
75d43124ab | ||
|
|
47cfbf3d9f | ||
|
|
744ff01e64 | ||
|
|
5a30f4c983 | ||
|
|
50d21da453 | ||
|
|
34b6004ad3 | ||
|
|
9457304ad3 | ||
|
|
7c48586394 | ||
|
|
84e1cb80e1 | ||
|
|
0dfc4e6a61 | ||
|
|
617bd0b4ef | ||
|
|
092a9b0ef6 | ||
|
|
b15d2bb668 | ||
|
|
6074fd4b86 | ||
|
|
c48a1d8adc | ||
|
|
7815f3fa5f | ||
|
|
3234ffd4ea | ||
|
|
c15ddb8597 | ||
|
|
d062346db2 | ||
|
|
29a105d016 | ||
|
|
8f5f383ead | ||
|
|
447ab4a74c | ||
|
|
492ee0dc61 | ||
|
|
248a4da331 | ||
|
|
78c32035f8 | ||
|
|
fe06f6d8ff | ||
|
|
28a76fa965 | ||
|
|
49bdfcc33d | ||
|
|
28f0200c7f | ||
|
|
1e5bd25291 | ||
|
|
7a54ad9fb1 | ||
|
|
80d9dc7c77 | ||
|
|
a069451888 | ||
|
|
35720d0e8e | ||
|
|
b186c42bf0 | ||
|
|
ddd7310e38 | ||
|
|
6c457fe56d | ||
|
|
4284394607 | ||
|
|
8bbb522ced | ||
|
|
5f6120012e | ||
|
|
2288714bce | ||
|
|
fdcd3d4747 | ||
|
|
17f006db03 | ||
|
|
053d2944d1 | ||
|
|
490a95af0f | ||
|
|
8dcd65786e | ||
|
|
0ad380ded0 | ||
|
|
3121b51d22 | ||
|
|
178a5452d4 | ||
|
|
331ec26530 | ||
|
|
5328f2a9e9 | ||
|
|
19dc99b425 | ||
|
|
9527750205 | ||
|
|
7a6ed6da57 | ||
|
|
7e1dd5d30a | ||
|
|
e0c4c01e44 | ||
|
|
3f244ff8e1 | ||
|
|
63731def4a | ||
|
|
9b4e7b661b | ||
|
|
f32a35607b | ||
|
|
f45a2c22d5 | ||
|
|
00e1511daf | ||
|
|
7c29774fbb | ||
|
|
3f7e3aa10b | ||
|
|
3157fb6923 | ||
|
|
fb5988ffec | ||
|
|
584d504273 | ||
|
|
498bff4b0b | ||
|
|
94df20bbee | ||
|
|
f485c8ce49 | ||
|
|
b4ba33f72a | ||
|
|
bdfc115a0a | ||
|
|
079126360d | ||
|
|
d5db081e7d | ||
|
|
e1616df7b4 | ||
|
|
7517e379c5 | ||
|
|
a34a0c492a | ||
|
|
66da3a7c87 | ||
|
|
12f0be4149 | ||
|
|
6257594085 | ||
|
|
cfaa0efde4 | ||
|
|
1c0a575ccc | ||
|
|
4108d696e4 | ||
|
|
2dfdf703fd | ||
|
|
d19ca54fda | ||
|
|
37387e151f | ||
|
|
2fc6b10cc9 | ||
|
|
59e3a104ba | ||
|
|
2456ec603c | ||
|
|
cae6b4a566 | ||
|
|
326b7d6aed | ||
|
|
d2a2542e5b | ||
|
|
59e7adb32f | ||
|
|
8e601a9577 | ||
|
|
8689032369 | ||
|
|
9cd90d5a8d | ||
|
|
850862c1d1 | ||
|
|
053cd9a830 | ||
|
|
38a7a058ab | ||
|
|
7d978ca131 | ||
|
|
c3d72f8c71 | ||
|
|
fb85ea15da | ||
|
|
3f0d2b9909 | ||
|
|
e4bec4133d | ||
|
|
c0d9ae87f2 |
7
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# Contributing
|
||||||
|
Thanks for contributing to the Moonlight Project! Whether you're opening an issue or proposing a pull request, you are welcome to follow these instructions.
|
||||||
|
|
||||||
|
- Use proper English: it doesn't have to be complicated, just make it simple to understand for everyone
|
||||||
|
- Cleary expose your feature or problem: My features adds, my problem is...
|
||||||
|
- Include screenshots if possible
|
||||||
|
- When posting an issue, give us the logs (blank your private IP)
|
||||||
24
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Read before posting an issue
|
||||||
|
If you have an issue, please consider the following before:
|
||||||
|
|
||||||
|
- Have you tried __updating__:
|
||||||
|
- Your operating system
|
||||||
|
- Geforce Experience (mention if in beta)
|
||||||
|
- Chrome to the latest version
|
||||||
|
- The Moonlight client
|
||||||
|
- Have you tried __pinging__ your host from the client?
|
||||||
|
- If streaming __over the internet__:
|
||||||
|
- Have you followed the [guide](https://github.com/moonlight-stream/moonlight-docs/wiki/Setup-Guide)?
|
||||||
|
- Have you opened all ports to they correct protocols (udp or tcp)
|
||||||
|
- Have you enabled __hardware acceleration__?
|
||||||
|
- Check under `chrome://settings/system` to enable it
|
||||||
|
- Check under `chrome://flags/#disable-accelerated-video-decode` for video hardware acceleration
|
||||||
|
- Check under `chrome://gpu` for:
|
||||||
|
- Video Decode: "Hardware accelerated"
|
||||||
|
- WebGL: "Hardware accelerated"
|
||||||
|
- WebGL2: "Hardware accelerated"
|
||||||
|
- Have you __enabled NaCL__?
|
||||||
|
- Check under `chrome://flags/#enable-nacl` to enable it
|
||||||
|
- Are you running Linux? if so, install Chrome from official ppa
|
||||||
|
|
||||||
|
If you still have problems, post them in the issues section with info, logs and screenshots if possible
|
||||||
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Name of my pull request
|
||||||
|
|
||||||
|
Fixes #123
|
||||||
|
|
||||||
|
Changes proposed in this pull request:
|
||||||
|
- My change #1
|
||||||
|
- My change #2
|
||||||
|
- My change #3
|
||||||
|
|
||||||
|
@moonlight-stream
|
||||||
4
.github/auto-comment.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
issuesOpened: >
|
||||||
|
If this is a question about Moonlight or you need help troubleshooting a streaming problem, please use the help channels on our [Discord server](https://moonlight-stream.org/discord) instead of GitHub issues. There are many more people available on Discord to help you and answer your questions.<br /><br />
|
||||||
|
This issue tracker should only be used for specific bugs or feature requests.<br /><br />
|
||||||
|
Thank you, and happy streaming!
|
||||||
8
.github/no-response.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# ProBot No Response (https://probot.github.io/apps/no-response/)
|
||||||
|
|
||||||
|
daysUntilClose: 7
|
||||||
|
responseRequiredLabel: 'need more info'
|
||||||
|
closeComment: >
|
||||||
|
This issue has been automatically closed because there was no response to a
|
||||||
|
request for more information from the issue opener. Please leave a comment or
|
||||||
|
open a new issue if you have additional information related to this issue.
|
||||||
14
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# ProBot Stale (https://probot.github.io/apps/stale/)
|
||||||
|
|
||||||
|
daysUntilStale: 90
|
||||||
|
daysUntilClose: 7
|
||||||
|
exemptLabels:
|
||||||
|
- accepted
|
||||||
|
- bug
|
||||||
|
- enhancement
|
||||||
|
- meta
|
||||||
|
staleLabel: stale
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs.
|
||||||
|
closeComment: false
|
||||||
6
.gitignore
vendored
@@ -42,3 +42,9 @@ dir.stamp
|
|||||||
*.pexe
|
*.pexe
|
||||||
*.nmf
|
*.nmf
|
||||||
*.bc
|
*.bc
|
||||||
|
|
||||||
|
# Jetbrains IDEs
|
||||||
|
*.idea/
|
||||||
|
|
||||||
|
# Visual Studio
|
||||||
|
*.vs/
|
||||||
|
|||||||
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@moonlight-stream.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
3
Makefile
@@ -21,7 +21,8 @@ CHROME_ARGS += --allow-nacl-socket-api=localhost
|
|||||||
|
|
||||||
LIBS = ppapi_gles2 ppapi ppapi_cpp pthread curl z ssl crypto nacl_io
|
LIBS = ppapi_gles2 ppapi ppapi_cpp pthread curl z ssl crypto nacl_io
|
||||||
|
|
||||||
CFLAGS = -Wall $(COMMON_C_C_FLAGS) $(OPUS_C_FLAGS)
|
CFLAGS += -Wall $(COMMON_C_C_FLAGS) $(OPUS_C_FLAGS)
|
||||||
|
CXXFLAGS += -Wall
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
$(OPUS_SOURCE) \
|
$(OPUS_SOURCE) \
|
||||||
|
|||||||
47
README.md
@@ -1,32 +1,24 @@
|
|||||||
# Moonlight for Chrome
|
# Moonlight for ChromeOS
|
||||||
|
|
||||||
[Moonlight for Chrome](http://moonlight-stream.com) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built to run in the Chrome browser.
|
[Moonlight for ChromeOS](https://moonlight-stream.org) is an open source client for NVIDIA GameStream and [Sunshine](https://github.com/LizardByte/Sunshine).
|
||||||
|
|
||||||
Moonlight for Chrome allows you to stream your full collection of games from your powerful desktop to another PC or laptop running Windows, Mac OS X, Linux, or Chrome OS.
|
Moonlight for ChromeOS allows you to stream your full collection of games from your powerful desktop to another PC or laptop running ChromeOS.
|
||||||
|
|
||||||
Moonlight also has mobile versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [iOS](https://github.com/moonlight-stream/moonlight-ios).
|
Moonlight also has mobile versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [iOS/tvOS](https://github.com/moonlight-stream/moonlight-ios).
|
||||||
|
|
||||||
## Features
|
Check out [the Moonlight wiki](https://github.com/moonlight-stream/moonlight-docs/wiki) for more detailed project information, setup guide, or troubleshooting steps.
|
||||||
|
|
||||||
* Streams Steam Big Picture and all of your games from your PC to your Chrome browser
|
[](https://ci.appveyor.com/project/cgutman/moonlight-chrome/branch/master)
|
||||||
* Keyboard and mouse support
|
|
||||||
* Hardware-accelerated video decoding
|
|
||||||
* Full support for Xbox controllers and PlayStation controllers, and some other HID gamepads
|
|
||||||
* Use mDNS to scan for compatible GeForce Experience (GFE) machines on the network
|
|
||||||
|
|
||||||
## Features to come
|
[](https://chrome.google.com/webstore/detail/moonlight-game-streaming/gemamigbbenahjlfnmlfdjhdnkpbkfjj)
|
||||||
* Gamepad mapping
|
|
||||||
* Improved UI
|
|
||||||
* Better error handling
|
|
||||||
|
|
||||||
## Installation
|
## Deprecation
|
||||||
* Download [GeForce Experience](http://www.geforce.com/geforce-experience) and install on your GameStream-compatible PC
|
|
||||||
* Install the [latest release](https://github.com/moonlight-stream/moonlight-chrome/releases)
|
|
||||||
|
|
||||||
## Requirements
|
Moonlight for ChromeOS is a legacy client that depends on the [deprecated NaCl runtime](https://blog.chromium.org/2021/10/extending-chrome-app-support-on-chrome.html). It is receiving only basic bugfixes and little/no feature work.
|
||||||
* Chrome browser on Windows, Mac OS X, Linux, or Chrome OS
|
|
||||||
* [GameStream-compatible](http://shield.nvidia.com/play-pc-games/) computer with GTX 600+ series desktop or mobile GPU (for the PC from which you're streaming)
|
For ChromeOS systems, we recommend migrating to the [Android](https://github.com/moonlight-stream/moonlight-android) app for additional features, functionality, and active support. Please reach out in the [GitHub tracker](https://github.com/moonlight-stream/moonlight-android/issues) if there are any functionality or performance regressions when moving to the Android client on ChromeOS systems.
|
||||||
* High-end wireless router (802.11n dual-band recommended) or wired network
|
|
||||||
|
For Windows, Mac, and Linux clients, we recommend running the [native PC port](https://github.com/moonlight-stream/moonlight-qt).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
1. Install the Chrome Native Client SDK and download the current Pepper SDK
|
1. Install the Chrome Native Client SDK and download the current Pepper SDK
|
||||||
@@ -40,16 +32,3 @@ Moonlight also has mobile versions for [Android](https://github.com/moonlight-st
|
|||||||
3. Click 'Load unpacked extension' and point it at your built moonlight-chrome repo
|
3. Click 'Load unpacked extension' and point it at your built moonlight-chrome repo
|
||||||
4. Run Moonlight from the extensions page
|
4. Run Moonlight from the extensions page
|
||||||
5. If making changes, make sure to click the Reload button on the Extensions page
|
5. If making changes, make sure to click the Reload button on the Extensions page
|
||||||
|
|
||||||
## Streaming
|
|
||||||
Simply type the hostname or IP into the textbox, pair, choose an app to run, then begin streaming. Once paired, the host will be remembered in a dropdown menu. To exit a stream, press Ctrl+Alt+Shift+Q. To remove focus from the stream, press Ctrl+Alt+Shift.
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
This project is being actively developed at [XDA Developers](http://forum.xda-developers.com/showthread.php?t=2505510)
|
|
||||||
|
|
||||||
1. Fork us
|
|
||||||
2. Write code
|
|
||||||
3. Send Pull Requests
|
|
||||||
|
|
||||||
Check out our [website](http://moonlight-stream.com) for project links and information.
|
|
||||||
|
|||||||
26
appveyor.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
version: 0.0.0.{build}
|
||||||
|
|
||||||
|
clone_depth: 1
|
||||||
|
|
||||||
|
image: Previous Ubuntu2004
|
||||||
|
|
||||||
|
install:
|
||||||
|
- 'pushd $HOME'
|
||||||
|
- 'wget https://github.com/cgutman/nacl_sdk/archive/refs/heads/master.zip -O nacl_sdk.zip'
|
||||||
|
- 'unzip nacl_sdk.zip'
|
||||||
|
- 'cd nacl_sdk-master'
|
||||||
|
- 'source $HOME/venv2.7/bin/activate'
|
||||||
|
- './naclsdk update'
|
||||||
|
- 'export NACL_SDK_ROOT=$HOME/nacl_sdk-master/pepper_49'
|
||||||
|
- 'popd'
|
||||||
|
|
||||||
|
before_build:
|
||||||
|
- 'git submodule update --init --recursive'
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- './do-release.sh'
|
||||||
|
|
||||||
|
after_build:
|
||||||
|
- 'appveyor PushArtifact moonlight-chrome.zip'
|
||||||
|
|
||||||
|
deploy: off
|
||||||
19
auddec.cpp
@@ -11,8 +11,8 @@
|
|||||||
// at a time.
|
// at a time.
|
||||||
|
|
||||||
static short s_CircularBuffer[CIRCULAR_BUFFER_SIZE][FRAME_SIZE * MAX_CHANNEL_COUNT];
|
static short s_CircularBuffer[CIRCULAR_BUFFER_SIZE][FRAME_SIZE * MAX_CHANNEL_COUNT];
|
||||||
static int s_ReadIndex = 0;
|
static int s_ReadIndex;
|
||||||
static int s_WriteIndex = 0;
|
static int s_WriteIndex;
|
||||||
|
|
||||||
static void AudioPlayerSampleCallback(void* samples, uint32_t buffer_size, void* data) {
|
static void AudioPlayerSampleCallback(void* samples, uint32_t buffer_size, void* data) {
|
||||||
// It should only ask us for complete buffers
|
// It should only ask us for complete buffers
|
||||||
@@ -34,9 +34,12 @@ static void AudioPlayerSampleCallback(void* samples, uint32_t buffer_size, void*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig) {
|
int MoonlightInstance::AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int flags) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
// Reset the ring buffer to empty
|
||||||
|
s_ReadIndex = s_WriteIndex = 0;
|
||||||
|
|
||||||
g_Instance->m_OpusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
g_Instance->m_OpusDecoder = opus_multistream_decoder_create(opusConfig->sampleRate,
|
||||||
opusConfig->channelCount,
|
opusConfig->channelCount,
|
||||||
opusConfig->streams,
|
opusConfig->streams,
|
||||||
@@ -49,6 +52,8 @@ void MoonlightInstance::AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CON
|
|||||||
|
|
||||||
// Start playback now
|
// Start playback now
|
||||||
g_Instance->m_AudioPlayer.StartPlayback();
|
g_Instance->m_AudioPlayer.StartPlayback();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::AudDecCleanup(void) {
|
void MoonlightInstance::AudDecCleanup(void) {
|
||||||
@@ -83,8 +88,8 @@ void MoonlightInstance::AudDecDecodeAndPlaySample(char* sampleData, int sampleLe
|
|||||||
}
|
}
|
||||||
|
|
||||||
AUDIO_RENDERER_CALLBACKS MoonlightInstance::s_ArCallbacks = {
|
AUDIO_RENDERER_CALLBACKS MoonlightInstance::s_ArCallbacks = {
|
||||||
MoonlightInstance::AudDecInit,
|
.init = MoonlightInstance::AudDecInit,
|
||||||
MoonlightInstance::AudDecCleanup,
|
.cleanup = MoonlightInstance::AudDecCleanup,
|
||||||
MoonlightInstance::AudDecDecodeAndPlaySample,
|
.decodeAndPlaySample = MoonlightInstance::AudDecDecodeAndPlaySample,
|
||||||
CAPABILITY_DIRECT_SUBMIT
|
.capabilities = CAPABILITY_DIRECT_SUBMIT
|
||||||
};
|
};
|
||||||
@@ -24,18 +24,21 @@ COMMON_C_SOURCE := \
|
|||||||
$(COMMON_C_DIR)/AudioStream.c \
|
$(COMMON_C_DIR)/AudioStream.c \
|
||||||
$(COMMON_C_DIR)/ByteBuffer.c \
|
$(COMMON_C_DIR)/ByteBuffer.c \
|
||||||
$(COMMON_C_DIR)/Connection.c \
|
$(COMMON_C_DIR)/Connection.c \
|
||||||
|
$(COMMON_C_DIR)/ConnectionTester.c \
|
||||||
$(COMMON_C_DIR)/ControlStream.c \
|
$(COMMON_C_DIR)/ControlStream.c \
|
||||||
$(COMMON_C_DIR)/FakeCallbacks.c \
|
$(COMMON_C_DIR)/FakeCallbacks.c \
|
||||||
$(COMMON_C_DIR)/InputStream.c \
|
$(COMMON_C_DIR)/InputStream.c \
|
||||||
$(COMMON_C_DIR)/LinkedBlockingQueue.c \
|
$(COMMON_C_DIR)/LinkedBlockingQueue.c \
|
||||||
$(COMMON_C_DIR)/Misc.c \
|
$(COMMON_C_DIR)/Misc.c \
|
||||||
$(COMMON_C_DIR)/Platform.c \
|
$(COMMON_C_DIR)/Platform.c \
|
||||||
|
$(COMMON_C_DIR)/PlatformCrypto.c \
|
||||||
$(COMMON_C_DIR)/PlatformSockets.c \
|
$(COMMON_C_DIR)/PlatformSockets.c \
|
||||||
$(COMMON_C_DIR)/RtpFecQueue.c \
|
$(COMMON_C_DIR)/RtpAudioQueue.c \
|
||||||
$(COMMON_C_DIR)/RtpReorderQueue.c \
|
$(COMMON_C_DIR)/RtpVideoQueue.c \
|
||||||
$(COMMON_C_DIR)/RtspConnection.c \
|
$(COMMON_C_DIR)/RtspConnection.c \
|
||||||
$(COMMON_C_DIR)/RtspParser.c \
|
$(COMMON_C_DIR)/RtspParser.c \
|
||||||
$(COMMON_C_DIR)/SdpGenerator.c \
|
$(COMMON_C_DIR)/SdpGenerator.c \
|
||||||
|
$(COMMON_C_DIR)/SimpleStun.c \
|
||||||
$(COMMON_C_DIR)/VideoDepacketizer.c \
|
$(COMMON_C_DIR)/VideoDepacketizer.c \
|
||||||
$(COMMON_C_DIR)/VideoStream.c \
|
$(COMMON_C_DIR)/VideoStream.c \
|
||||||
$(ENET_SOURCE) \
|
$(ENET_SOURCE) \
|
||||||
|
|||||||
@@ -10,8 +10,13 @@ void MoonlightInstance::ClStageStarting(int stage) {
|
|||||||
g_Instance->PostMessage(response);
|
g_Instance->PostMessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::ClStageFailed(int stage, long errorCode) {
|
void MoonlightInstance::ClStageFailed(int stage, int errorCode) {
|
||||||
pp::Var response(std::string("Starting ") + std::string(LiGetStageName(stage)) + std::string("failed"));
|
pp::Var response(
|
||||||
|
std::string("DialogMsg: ") +
|
||||||
|
std::string(LiGetStageName(stage)) +
|
||||||
|
std::string(" failed (error ") +
|
||||||
|
std::to_string(errorCode) +
|
||||||
|
std::string(")"));
|
||||||
g_Instance->PostMessage(response);
|
g_Instance->PostMessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,7 +25,7 @@ void MoonlightInstance::ClConnectionStarted(void) {
|
|||||||
g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::OnConnectionStarted));
|
g_Instance->m_CallbackFactory.NewCallback(&MoonlightInstance::OnConnectionStarted));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::ClConnectionTerminated(long errorCode) {
|
void MoonlightInstance::ClConnectionTerminated(int errorCode) {
|
||||||
// Teardown the connection
|
// Teardown the connection
|
||||||
LiStopConnection();
|
LiStopConnection();
|
||||||
|
|
||||||
@@ -38,12 +43,23 @@ void MoonlightInstance::ClDisplayTransientMessage(const char* message) {
|
|||||||
g_Instance->PostMessage(response);
|
g_Instance->PostMessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::ClLogMessage(const char* format, ...) {
|
||||||
|
va_list va;
|
||||||
|
char message[1024];
|
||||||
|
|
||||||
|
va_start(va, format);
|
||||||
|
vsnprintf(message, sizeof(message), format, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
pp::Var response(std::string("LogMsg: ") + std::string(message));
|
||||||
|
g_Instance->PostMessage(response);
|
||||||
|
}
|
||||||
|
|
||||||
CONNECTION_LISTENER_CALLBACKS MoonlightInstance::s_ClCallbacks = {
|
CONNECTION_LISTENER_CALLBACKS MoonlightInstance::s_ClCallbacks = {
|
||||||
MoonlightInstance::ClStageStarting,
|
.stageStarting = MoonlightInstance::ClStageStarting,
|
||||||
NULL,
|
.stageFailed = MoonlightInstance::ClStageFailed,
|
||||||
MoonlightInstance::ClStageFailed,
|
.connectionStarted = MoonlightInstance::ClConnectionStarted,
|
||||||
MoonlightInstance::ClConnectionStarted,
|
.connectionTerminated = MoonlightInstance::ClConnectionTerminated,
|
||||||
MoonlightInstance::ClConnectionTerminated,
|
.logMessage = MoonlightInstance::ClLogMessage,
|
||||||
MoonlightInstance::ClDisplayMessage,
|
.rumble = MoonlightInstance::ClControllerRumble,
|
||||||
MoonlightInstance::ClDisplayTransientMessage
|
|
||||||
};
|
};
|
||||||
|
|||||||
16
do-release.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$1" 1>&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
git diff-index --quiet HEAD -- || fail "Release builds must not have unstaged changes!"
|
||||||
|
|
||||||
|
rm moonlight-chrome.zip
|
||||||
|
make clean || fail "Clean failed"
|
||||||
|
make -j$(nproc) || fail "Build failed"
|
||||||
|
|
||||||
|
|
||||||
|
zip moonlight-chrome.zip -r . -i pnacl/Release/moonlight-chrome.* -i manifest.json -i index.html -i LICENSE || fail "Zip failed"
|
||||||
|
zip moonlight-chrome.zip -r icons || fail "Zip failed"
|
||||||
|
zip moonlight-chrome.zip -r static || fail "Zip failed"
|
||||||
18
gamepad.cpp
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
static const unsigned short k_StandardGamepadButtonMapping[] = {
|
static const unsigned short k_StandardGamepadButtonMapping[] = {
|
||||||
A_FLAG, B_FLAG, X_FLAG, Y_FLAG,
|
A_FLAG, B_FLAG, X_FLAG, Y_FLAG,
|
||||||
LB_FLAG, RB_FLAG,
|
LB_FLAG, RB_FLAG,
|
||||||
@@ -25,6 +27,9 @@ static short GetActiveGamepadMask(PP_GamepadsSampleData& gamepadData) {
|
|||||||
for (unsigned int p = 0; p < gamepadData.length; p++) {
|
for (unsigned int p = 0; p < gamepadData.length; p++) {
|
||||||
PP_GamepadSampleData& padData = gamepadData.items[p];
|
PP_GamepadSampleData& padData = gamepadData.items[p];
|
||||||
|
|
||||||
|
// See logic in getConnectedGamepadMask() (utils.js)
|
||||||
|
// These must stay in sync!
|
||||||
|
|
||||||
if (!padData.connected) {
|
if (!padData.connected) {
|
||||||
// Not connected
|
// Not connected
|
||||||
continue;
|
continue;
|
||||||
@@ -81,7 +86,7 @@ void MoonlightInstance::PollGamepads() {
|
|||||||
|
|
||||||
m_LastPadTimestamps[p] = padData.timestamp;
|
m_LastPadTimestamps[p] = padData.timestamp;
|
||||||
|
|
||||||
short buttonFlags = 0;
|
int buttonFlags = 0;
|
||||||
unsigned char leftTrigger = 0, rightTrigger = 0;
|
unsigned char leftTrigger = 0, rightTrigger = 0;
|
||||||
short leftStickX = 0, leftStickY = 0;
|
short leftStickX = 0, leftStickY = 0;
|
||||||
short rightStickX = 0, rightStickY = 0;
|
short rightStickX = 0, rightStickY = 0;
|
||||||
@@ -124,3 +129,14 @@ void MoonlightInstance::PollGamepads() {
|
|||||||
controllerIndex++;
|
controllerIndex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor)
|
||||||
|
{
|
||||||
|
const float weakMagnitude = static_cast<float>(highFreqMotor) / static_cast<float>(UINT16_MAX);
|
||||||
|
const float strongMagnitude = static_cast<float>(lowFreqMotor) / static_cast<float>(UINT16_MAX);
|
||||||
|
|
||||||
|
std::ostringstream ss;
|
||||||
|
ss << controllerNumber << "," << weakMagnitude << "," << strongMagnitude;
|
||||||
|
pp::Var response(std::string("controllerRumble: ") + ss.str());
|
||||||
|
g_Instance->PostMessage(response);
|
||||||
|
}
|
||||||
54
http.cpp
@@ -5,15 +5,19 @@
|
|||||||
#include <http.h>
|
#include <http.h>
|
||||||
#include <errors.h>
|
#include <errors.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
|
||||||
#include <mkcert.h>
|
#include <mkcert.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
X509 *g_Cert;
|
X509 *g_Cert;
|
||||||
EVP_PKEY *g_PrivateKey;
|
EVP_PKEY *g_PrivateKey;
|
||||||
char *g_UniqueId;
|
char *g_UniqueId;
|
||||||
char *g_CertHex;
|
char *g_CertHex;
|
||||||
|
pthread_mutex_t *g_OSSLMutexes;
|
||||||
|
|
||||||
void MoonlightInstance::MakeCert(int32_t callbackId, pp::VarArray args)
|
void MoonlightInstance::MakeCert(int32_t callbackId, pp::VarArray args)
|
||||||
{
|
{
|
||||||
@@ -62,7 +66,7 @@ void MoonlightInstance::LoadCert(const char* certStr, const char* keyStr)
|
|||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
|
|
||||||
bio = BIO_new_mem_buf(_keyStr, -1);
|
bio = BIO_new_mem_buf(_keyStr, -1);
|
||||||
if(PEM_read_bio_PrivateKey(bio, &g_PrivateKey, NULL, NULL) == NULL) {
|
if (!(g_PrivateKey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))) {
|
||||||
PostMessage(pp::Var("Error loading private key into memory"));
|
PostMessage(pp::Var("Error loading private key into memory"));
|
||||||
}
|
}
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
@@ -77,25 +81,64 @@ void MoonlightInstance::LoadCert(const char* certStr, const char* keyStr)
|
|||||||
free(_keyStr);
|
free(_keyStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::OSSLThreadLock(int mode, int n, const char *, int)
|
||||||
|
{
|
||||||
|
if (mode & CRYPTO_LOCK) {
|
||||||
|
pthread_mutex_lock(&g_OSSLMutexes[n]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pthread_mutex_unlock(&g_OSSLMutexes[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long MoonlightInstance::OSSLThreadId(void)
|
||||||
|
{
|
||||||
|
return (unsigned long)pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
void MoonlightInstance::NvHTTPInit(int32_t callbackId, pp::VarArray args)
|
void MoonlightInstance::NvHTTPInit(int32_t callbackId, pp::VarArray args)
|
||||||
{
|
{
|
||||||
std::string _cert = args.Get(0).AsString();
|
std::string _cert = args.Get(0).AsString();
|
||||||
std::string _key = args.Get(1).AsString();
|
std::string _key = args.Get(1).AsString();
|
||||||
std::string _uniqueId = args.Get(2).AsString();
|
std::string _uniqueId = args.Get(2).AsString();
|
||||||
|
|
||||||
|
// Mount resource directory where CA bundle resides
|
||||||
|
mount("static/curl", "/curl", "httpfs", 0, "");
|
||||||
|
|
||||||
|
// This will initialize OpenSSL
|
||||||
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
|
|
||||||
LoadCert(_cert.c_str(), _key.c_str());
|
LoadCert(_cert.c_str(), _key.c_str());
|
||||||
g_UniqueId = strdup(_uniqueId.c_str());
|
g_UniqueId = strdup(_uniqueId.c_str());
|
||||||
|
|
||||||
|
g_OSSLMutexes = new pthread_mutex_t[CRYPTO_num_locks()];
|
||||||
|
for (int i = 0; i < CRYPTO_num_locks(); i++) {
|
||||||
|
pthread_mutex_init(&g_OSSLMutexes[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CRYPTO_set_id_callback(OSSLThreadId);
|
||||||
|
CRYPTO_set_locking_callback(OSSLThreadLock);
|
||||||
|
|
||||||
pp::VarDictionary ret;
|
pp::VarDictionary ret;
|
||||||
ret.Set("callbackId", pp::Var(callbackId));
|
ret.Set("callbackId", pp::Var(callbackId));
|
||||||
ret.Set("type", pp::Var("resolve"));
|
ret.Set("type", pp::Var("resolve"));
|
||||||
ret.Set("ret", pp::Var(""));
|
ret.Set("ret", pp::Var());
|
||||||
PostMessage(ret);
|
PostMessage(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, std::string url, bool binaryResponse)
|
void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, pp::VarArray args)
|
||||||
{
|
{
|
||||||
char* _url = strdup(url.c_str());
|
std::string url = args.Get(0).AsString();
|
||||||
|
std::string ppkstr = args.Get(1).AsString();
|
||||||
|
bool binaryResponse = args.Get(2).AsBool();
|
||||||
|
|
||||||
|
// For launch/resume requests, append the additional query parameters
|
||||||
|
if (url.find("/launch?") != std::string::npos || url.find("/resume?") != std::string::npos) {
|
||||||
|
url += LiGetLaunchUrlQueryParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMessage(pp::Var(url.c_str()));
|
||||||
|
|
||||||
PHTTP_DATA data = http_create_data();
|
PHTTP_DATA data = http_create_data();
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@@ -108,7 +151,7 @@ void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, st
|
|||||||
goto clean_data;
|
goto clean_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = http_request(_url , data);
|
err = http_request(url.c_str(), ppkstr.empty() ? NULL : ppkstr.c_str(), data);
|
||||||
if (err) {
|
if (err) {
|
||||||
pp::VarDictionary ret;
|
pp::VarDictionary ret;
|
||||||
ret.Set("callbackId", pp::Var(callbackId));
|
ret.Set("callbackId", pp::Var(callbackId));
|
||||||
@@ -144,5 +187,4 @@ void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, st
|
|||||||
|
|
||||||
clean_data:
|
clean_data:
|
||||||
http_free_data(data);
|
http_free_data(data);
|
||||||
free(_url);
|
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 13 KiB |
BIN
icons/icon16.png
|
Before Width: | Height: | Size: 809 B After Width: | Height: | Size: 859 B |
BIN
icons/icon32.png
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
icons/icon48.png
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.5 KiB |
270
index.html
@@ -1,174 +1,190 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Pragma" content="no-cache">
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<meta http-equiv="Expires" content="-1">
|
<meta http-equiv="Expires" content="-1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Moonlight</title>
|
<title>Moonlight</title>
|
||||||
<link rel="stylesheet" href="static/css/roboto.css">
|
<link rel="stylesheet" href="static/css/roboto.css">
|
||||||
<link rel="stylesheet" href="static/css/material.min.css">
|
<link rel="stylesheet" href="static/css/material.min.css">
|
||||||
<link rel="stylesheet" href="static/css/style.css">
|
<link rel="stylesheet" href="static/css/style.css">
|
||||||
<link rel="stylesheet" href="static/css/material-icons.css">
|
<link rel="stylesheet" href="static/css/material-icons.css">
|
||||||
</head>
|
</head>
|
||||||
<body data-name="moonlight-chrome" data-tools="pnacl" data-configs="Debug Release" data-path="{tc}/{config}">
|
<body data-name="moonlight-chrome" data-tools="pnacl" data-configs="Debug Release" data-path="{tc}/{config}">
|
||||||
<div class="mdl-layout mdl-js-layout">
|
<div class="mdl-layout mdl-js-layout">
|
||||||
<header id="main-navigation" class="mdl-layout__header mdl-layout__header--transparent">
|
<header id="main-navigation" class="mdl-layout__header mdl-layout__header--transparent">
|
||||||
<div class="mdl-layout__header-row">
|
<div class="mdl-layout__header-row">
|
||||||
<span id='backIcon'><i class="material-icons">keyboard_arrow_left</i></span>
|
<button id="backIcon" class="mdl-button mdl-js-button mdl-button--icon" role="link" aria-label="Host selection"><i class="material-icons">keyboard_arrow_left</i></button>
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<span class="mdl-layout-title">MOON<span>LIGHT</span></span>
|
<span class="mdl-layout-title">MOON<span>LIGHT</span></span>
|
||||||
<!-- Add spacer, to align navigation to the right -->
|
<!-- Add spacer, to align navigation to the right -->
|
||||||
<div class="mdl-layout-spacer"></div>
|
<div class="mdl-layout-spacer"></div>
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="mdl-navigation">
|
<nav class="mdl-navigation">
|
||||||
|
<div class="nav-menu-parent">
|
||||||
<div class="nav-menu-parent">
|
<div id="resolutionMenu">
|
||||||
<div id="resolutionMenu">
|
<button id="selectResolution" data-value="1280:720" class="mdl-button mdl-js-button">
|
||||||
<button id="selectResolution" data-value="1920:1080" class="mdl-button mdl-js-button">
|
720p
|
||||||
1080p
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="resolutionMenu mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
|
<ul class="resolutionMenu mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="selectResolution">
|
||||||
for="selectResolution">
|
<li class="mdl-menu__item" data-value="1280:720">720p</li>
|
||||||
<li class="mdl-menu__item" data-value="1280:720">720p</li>
|
<li class="mdl-menu__item" data-value="1920:1080">1080p</li>
|
||||||
<li class="mdl-menu__item" data-value="1920:1080">1080p</li>
|
<li class="mdl-menu__item" data-value="3840:2160">4K</li>
|
||||||
<li class="mdl-menu__item" data-value="3840:2160">4K</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div id="resolutionTooltip" class="mdl-tooltip" for="resolutionMenu">
|
<div id="resolutionTooltip" class="mdl-tooltip" for="resolutionMenu">
|
||||||
Resolution
|
Resolution
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="nav-menu-parent">
|
||||||
<div class="nav-menu-parent">
|
<div id="framerateMenu">
|
||||||
<div id="framerateMenu">
|
<button id="selectFramerate" data-value="60" class="mdl-button mdl-js-button">
|
||||||
<button id="selectFramerate" data-value="60" class="mdl-button mdl-js-button">
|
|
||||||
60 FPS
|
60 FPS
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="framerateMenu mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect"
|
<ul class="framerateMenu mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="selectFramerate">
|
||||||
for="selectFramerate">
|
<li class="mdl-menu__item" data-value="30">30 FPS</li>
|
||||||
<li class="mdl-menu__item" data-value="30">30 FPS</li>
|
<li class="mdl-menu__item" data-value="60">60 FPS</li>
|
||||||
<li class="mdl-menu__item" data-value="60">60 FPS</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div id="framerateTooltip" class="mdl-tooltip" for="framerateMenu">
|
<div id="framerateTooltip" class="mdl-tooltip" for="framerateMenu">
|
||||||
Framerate
|
Framerate
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-menu-parent">
|
<div class="nav-menu-parent">
|
||||||
<div id="bandwidthMenu">
|
<div id="bandwidthMenu">
|
||||||
<button id='bitrateField' class="mdl-button">10 Mbps</button>
|
<button id="bitrateField" class="mdl-button">10 Mbps</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bitrateMenu mdl-menu mdl-js-menu mdl-js-ripple-effect" for="bandwidthMenu">
|
<div class="bitrateMenu mdl-menu mdl-js-menu mdl-js-ripple-effect" for="bandwidthMenu">
|
||||||
<input id="bitrateSlider" class="mdl-slider mdl-js-slider" type="range" min="0" max="100" step="0.5" value="10">
|
<input id="bitrateSlider" class="mdl-slider mdl-js-slider" type="range" min="0" max="100" step="0.5" value="10">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="bandwidthTooltip" class="mdl-tooltip" for="bandwidthMenu">
|
<div id="bandwidthTooltip" class="mdl-tooltip" for="bandwidthMenu">
|
||||||
Bandwidth
|
Bandwidth
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label id="externalAudioBtn" class="mdl-icon-toggle mdl-js-icon-toggle mdl-js-ripple-effect" for="remoteAudioEnabledSwitch">
|
<div class="nav-menu-parent">
|
||||||
<input type="checkbox" id="remoteAudioEnabledSwitch" class="mdl-icon-toggle__input" checked>
|
<label id="externalAudioBtn" class="mdl-icon-toggle mdl-js-icon-toggle mdl-js-ripple-effect" for="remoteAudioEnabledSwitch">
|
||||||
<i class="mdl-icon-toggle__label material-icons">volume_up</i>
|
<input type="checkbox" id="remoteAudioEnabledSwitch" class="mdl-icon-toggle__input">
|
||||||
</label>
|
<i class="mdl-icon-toggle__label material-icons">volume_up</i>
|
||||||
<div id="externalAudioTooltip" class="mdl-tooltip" for="externalAudioBtn">
|
</label>
|
||||||
Remote audio is ON
|
<div id="externalAudioTooltip" class="mdl-tooltip" for="externalAudioBtn">
|
||||||
</div>
|
Play audio on the host
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="quitCurrentApp">
|
<div class="nav-menu-parent">
|
||||||
|
<label id="mouseLockBtn" class="mdl-icon-toggle mdl-js-icon-toggle mdl-js-ripple-effect" for="mouseLockEnabledSwitch">
|
||||||
|
<input type="checkbox" id="mouseLockEnabledSwitch" class="mdl-icon-toggle__input">
|
||||||
|
<i class="mdl-icon-toggle__label material-icons">mouse</i>
|
||||||
|
</label>
|
||||||
|
<div id="mouseLockTooltip" class="mdl-tooltip" for="mouseLockBtn">
|
||||||
|
Enable mouse locking (must disable to use tap-to-click on touchpads)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="nav-menu-parent">
|
||||||
|
<label id="optimizeGamesBtn" class="mdl-icon-toggle mdl-js-icon-toggle mdl-js-ripple-effect" for="optimizeGamesSwitch">
|
||||||
|
<input type="checkbox" id="optimizeGamesSwitch" class="mdl-icon-toggle__input">
|
||||||
|
<i class="mdl-icon-toggle__label material-icons">timeline</i>
|
||||||
|
</label>
|
||||||
|
<div id="optimizeGamesTooltip" class="mdl-tooltip" for="optimizeGamesBtn">
|
||||||
|
Allow game optimisations
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="quitCurrentApp" aria-label="Quit current app">
|
||||||
<i class="material-icons">remove_circle_outline</i>
|
<i class="material-icons">remove_circle_outline</i>
|
||||||
Quit Current App
|
Quit Current App
|
||||||
</button>
|
</button>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main id="main-content" class="mdl-layout__content">
|
<main id="main-content" class="mdl-layout__content">
|
||||||
<div id="host-grid">
|
<div id="host-grid">
|
||||||
<div class="page-title">Your PCs</div>
|
<div class="add-host-card mdl-card mdl-shadow--4dp" id="addHostCell">
|
||||||
<div class="add-host-card mdl-card mdl-shadow--4dp" id='addHostCell'>
|
<div class="mdl-card__title mdl-card--expand" id="addHostIcon" role="link" tabindex="0" aria-label="Add Host">
|
||||||
<div class="mdl-card__title mdl-card--expand" id="addHostIcon">
|
<h2 class="mdl-card__title-text">Add Host</h2>
|
||||||
<h2 class="mdl-card__title-text" >Add Host</h2>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div id="game-grid"></div>
|
||||||
<div id="game-grid">
|
<div id="listener"></div>
|
||||||
<div class="page-title">Your Games</div>
|
<!-- NaCl module placeholder. NaCl gets thrown into here -->
|
||||||
</div>
|
<div id="loadingSpinner" class="mdl-progress mdl-js-progress mdl-progress__indeterminate">
|
||||||
<div id="listener"></div>
|
<h5 id="loadingMessage"></h5>
|
||||||
<!-- NaCl module placeholder. NaCl gets thrown into here -->
|
</div>
|
||||||
<div id="loadingSpinner" class="mdl-progress mdl-js-progress mdl-progress__indeterminate">
|
<div id="naclSpinner" class="mdl-progress mdl-js-progress mdl-progress__indeterminate">
|
||||||
<h5 id="loadingMessage"></h5>
|
<h5 id="naclSpinnerMessage"></h5>
|
||||||
</div>
|
</div>
|
||||||
<div id="naclSpinner" class="mdl-progress mdl-js-progress mdl-progress__indeterminate">
|
|
||||||
<h5 id="naclSpinnerMessage"></h5>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
<script defer src="static/js/jquery-2.2.0.min.js"></script>
|
<script defer src="static/js/jquery-2.2.0.min.js"></script>
|
||||||
<script defer src="static/js/material.min.js"></script>
|
<script defer src="static/js/material.min.js"></script>
|
||||||
<script type="text/javascript" src="static/js/messages.js"></script>
|
<script type="text/javascript" src="static/js/messages.js"></script>
|
||||||
<script type="text/javascript" src="static/js/common.js"></script>
|
<script type="text/javascript" src="static/js/common.js"></script>
|
||||||
<script type="text/javascript" src="static/js/index.js"></script>
|
<script type="text/javascript" src="static/js/index.js"></script>
|
||||||
<script type="text/javascript" src="static/js/utils.js"></script>
|
<script type="text/javascript" src="static/js/utils.js"></script>
|
||||||
<script type="text/javascript" src="static/js/mdns-browser/dns.js"></script>
|
<script type="text/javascript" src="static/js/mdns-browser/dns.js"></script>
|
||||||
<script type="text/javascript" src="static/js/mdns-browser/main.js"></script>
|
<script type="text/javascript" src="static/js/mdns-browser/main.js"></script>
|
||||||
<dialog id="pairingDialog" class="mdl-dialog">
|
<dialog id="pairingDialog" class="mdl-dialog">
|
||||||
<h3 class="mdl-dialog__title">Pairing</h3>
|
<h3 class="mdl-dialog__title">Pairing</h3>
|
||||||
<div class="mdl-dialog__content">
|
<div class="mdl-dialog__content">
|
||||||
<p id="pairingDialogText">
|
<p id="pairingDialogText">
|
||||||
Please enter the number XXXX on the GFE dialog on the computer. This dialog will be dismissed once complete
|
Please enter the number XXXX on the GFE dialog on the computer. This dialog will be dismissed once complete
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="mdl-dialog__actions">
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelPairingDialog">Cancel</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelPairingDialog">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
<dialog id="quitAppDialog" class="mdl-dialog">
|
<dialog id="quitAppDialog" class="mdl-dialog">
|
||||||
<h3 class="mdl-dialog__title">Quit Running App?</h3>
|
<h3 class="mdl-dialog__title">Quit Running App?</h3>
|
||||||
<div class="mdl-dialog__content">
|
<div class="mdl-dialog__content">
|
||||||
<p id="quitAppDialogText">
|
<p id="quitAppDialogText">
|
||||||
Y is already running. Would you like to quit Y?
|
Y is already running. Would you like to quit Y?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="mdl-dialog__actions">
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelQuitApp">No</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelQuitApp">No</button>
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueQuitApp">Yes</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueQuitApp">Yes</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
<dialog id="deleteHostDialog" class="mdl-dialog">
|
<dialog id="deleteHostDialog" class="mdl-dialog">
|
||||||
<h3 class="mdl-dialog__title">Delete PC</h3>
|
<h3 class="mdl-dialog__title">Delete PC</h3>
|
||||||
<div class="mdl-dialog__content">
|
<div class="mdl-dialog__content">
|
||||||
<p id="deleteHostDialogText">
|
<p id="deleteHostDialogText">
|
||||||
Are you sure you want to delete this host?
|
Are you sure you want to delete this host?
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="mdl-dialog__actions">
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelDeleteHost">No</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelDeleteHost">No</button>
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueDeleteHost">Yes</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueDeleteHost">Yes</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
<dialog id="addHostDialog" class="mdl-dialog">
|
<dialog id="addHostDialog" class="mdl-dialog">
|
||||||
<h3 class="mdl-dialog__title">Add Host Manually</h3>
|
<h3 class="mdl-dialog__title">Add Host Manually</h3>
|
||||||
<div class="mdl-dialog__content">
|
<div class="mdl-dialog__content">
|
||||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
|
||||||
<input class="mdl-textfield__input" type="text" id="dialogInputHost"/>
|
<input class="mdl-textfield__input" type="text" id="dialogInputHost" />
|
||||||
<label class="mdl-textfield__label" for="dialogInputHost">IP Address or Hostname of Geforce PC</label>
|
<label class="mdl-textfield__label" for="dialogInputHost">IP Address or Hostname of GeForce PC</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mdl-dialog__actions">
|
<div class="mdl-dialog__actions">
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelAddHost">Cancel</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="cancelAddHost">Cancel</button>
|
||||||
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueAddHost">Continue</button>
|
<button type="button" class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" id="continueAddHost">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</dialog>
|
||||||
<div id="snackbar" class="mdl-snackbar mdl-js-snackbar">
|
<div id="snackbar" class="mdl-snackbar mdl-js-snackbar">
|
||||||
<div class="mdl-snackbar__text"></div>
|
<div class="mdl-snackbar__text"></div>
|
||||||
<button id='snackButton' class="mdl-snackbar__action" type="button"></button> <!-- this button exists to suppress the snackbar warning. we're really using a toast. -->
|
<button id="snackButton" class="mdl-snackbar__action" type="button"></button>
|
||||||
</div>
|
<!-- this button exists to suppress the snackbar warning. we're really using a toast. -->
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
246
input.cpp
@@ -1,13 +1,22 @@
|
|||||||
#include "moonlight.hpp"
|
#include "moonlight.hpp"
|
||||||
|
|
||||||
#include "ppapi/c/ppb_input_event.h"
|
#include "ppapi/c/ppb_input_event.h"
|
||||||
|
#include "ppapi/cpp/mouse_cursor.h"
|
||||||
|
|
||||||
#include "ppapi/cpp/input_event.h"
|
#include "ppapi/cpp/input_event.h"
|
||||||
|
|
||||||
#include <Limelight.h>
|
#include <Limelight.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define KEY_PREFIX 0x80
|
#define KEY_PREFIX 0x80
|
||||||
|
|
||||||
|
#define TOUCH_DEAD_ZONE_DELAY 0.250
|
||||||
|
#define TOUCH_DEAD_ZONE_RADIUS 50
|
||||||
|
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
|
static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
|
||||||
switch (ppButton) {
|
switch (ppButton) {
|
||||||
case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
|
case PP_INPUTEVENT_MOUSEBUTTON_LEFT:
|
||||||
@@ -21,12 +30,35 @@ static int ConvertPPButtonToLiButton(PP_InputEvent_MouseButton ppButton) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::LockMouseOrJustCaptureInput() {
|
||||||
|
if (m_MouseLockingFeatureEnabled) {
|
||||||
|
LockMouse(m_CallbackFactory.NewCallback(&MoonlightInstance::DidLockMouse));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume it worked until we get a callback telling us otherwise;
|
||||||
|
// if not locking mouse this just serves to tell us whether to capture input
|
||||||
|
m_MouseLocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::UnlockMouseOrJustReleaseInput() {
|
||||||
|
if (m_MouseLockingFeatureEnabled) {
|
||||||
|
UnlockMouse();
|
||||||
|
} else {
|
||||||
|
pp::MouseCursor::SetCursor(this, PP_MOUSECURSOR_TYPE_POINTER);
|
||||||
|
}
|
||||||
|
m_MouseLocked = false;
|
||||||
|
m_WaitingForAllModifiersUp = false;
|
||||||
|
}
|
||||||
|
|
||||||
void MoonlightInstance::DidLockMouse(int32_t result) {
|
void MoonlightInstance::DidLockMouse(int32_t result) {
|
||||||
m_MouseLocked = (result == PP_OK);
|
m_MouseLocked = (result == PP_OK);
|
||||||
if (m_MouseLocked) {
|
if (m_MouseLocked) {
|
||||||
// Request an IDR frame to dump the frame queue that may have
|
// Request an IDR frame to dump the frame queue that may have
|
||||||
// built up from the GL pipeline being stalled.
|
// built up from the GL pipeline being stalled.
|
||||||
g_Instance->m_RequestIdrFrame = true;
|
LiRequestIdrFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,15 +83,138 @@ static char GetModifierFlags(const pp::InputEvent& event) {
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t GetTranslatedKeyCode(const pp::KeyboardInputEvent& event) {
|
||||||
|
|
||||||
|
// For some reason, NaCl won't give us the real left and right
|
||||||
|
// VK codes for modifiers and instead gives us modifier flags
|
||||||
|
// to indicate whether the key is left or right. We have to
|
||||||
|
// convert these back to the original VK codes to before
|
||||||
|
// sending them to the PC.
|
||||||
|
switch (event.GetKeyCode()) {
|
||||||
|
// VK_SHIFT
|
||||||
|
case 0x10:
|
||||||
|
if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISLEFT) {
|
||||||
|
// VK_LSHIFT
|
||||||
|
return 0xA0;
|
||||||
|
}
|
||||||
|
else if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISRIGHT) {
|
||||||
|
// VK_RSHIFT
|
||||||
|
return 0xA1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// VK_CONTROL
|
||||||
|
case 0x11:
|
||||||
|
if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISLEFT) {
|
||||||
|
// VK_LCONTROL
|
||||||
|
return 0xA2;
|
||||||
|
}
|
||||||
|
else if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISRIGHT) {
|
||||||
|
// VK_RCONTROL
|
||||||
|
return 0xA3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// VK_MENU (Alt)
|
||||||
|
case 0x12:
|
||||||
|
if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISLEFT) {
|
||||||
|
// VK_LMENU
|
||||||
|
return 0xA4;
|
||||||
|
}
|
||||||
|
else if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISRIGHT) {
|
||||||
|
// VK_RMENU
|
||||||
|
return 0xA5;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have to handle the ISKEYPAD modifier on macOS, and convert them
|
||||||
|
// to the correct numpad keycodes for Windows.
|
||||||
|
int32_t num = event.GetKeyCode() - 0x30;
|
||||||
|
if ((event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISKEYPAD) &&
|
||||||
|
num >= 0 && num <= 9) {
|
||||||
|
// Offset with numpad 0's virtual keycode
|
||||||
|
return num + 0x60;
|
||||||
|
}
|
||||||
|
|
||||||
|
return event.GetKeyCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::ReportMouseMovement() {
|
||||||
|
if (m_MouseDeltaX != 0 || m_MouseDeltaY != 0) {
|
||||||
|
LiSendMouseMoveEvent(m_MouseDeltaX, m_MouseDeltaY);
|
||||||
|
m_MouseDeltaX = m_MouseDeltaY = 0;
|
||||||
|
} else if (m_MousePositionX != 0 || m_MousePositionY != 0) {
|
||||||
|
// Clamp the input coordinates to the plugin area
|
||||||
|
short x = MIN(MAX(m_MousePositionX, 0), m_PluginRect.width());
|
||||||
|
short y = MIN(MAX(m_MousePositionY, 0), m_PluginRect.height());
|
||||||
|
LiSendMousePositionEvent(x, y, m_PluginRect.width(), m_PluginRect.height());
|
||||||
|
m_MousePositionX = 0;
|
||||||
|
m_MousePositionY = 0;
|
||||||
|
}
|
||||||
|
if (m_AccumulatedTicks != 0) {
|
||||||
|
// We can have fractional ticks here, so multiply by WHEEL_DELTA
|
||||||
|
// to get actual scroll distance and use the high-res variant.
|
||||||
|
LiSendHighResScrollEvent(m_AccumulatedTicks * 120);
|
||||||
|
m_AccumulatedTicks = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MoonlightInstance::TryHandleNativeTouchEvent(const pp::InputEvent& event) {
|
||||||
|
// Check if the host supports native pen/touch events
|
||||||
|
if (!(LiGetHostFeatureFlags() & LI_FF_PEN_TOUCH_EVENTS)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t eventType;
|
||||||
|
switch (event.GetType()) {
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHSTART:
|
||||||
|
eventType = LI_TOUCH_EVENT_DOWN;
|
||||||
|
break;
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHMOVE:
|
||||||
|
eventType = LI_TOUCH_EVENT_MOVE;
|
||||||
|
break;
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHEND:
|
||||||
|
eventType = LI_TOUCH_EVENT_UP;
|
||||||
|
break;
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
|
||||||
|
eventType = LI_TOUCH_EVENT_CANCEL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Not a touch event
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::TouchInputEvent touchEvent(event);
|
||||||
|
uint32_t count = touchEvent.GetTouchCount(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES);
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
pp::TouchPoint touchPoint = touchEvent.GetTouchByIndex(PP_TOUCHLIST_TYPE_CHANGEDTOUCHES, i);
|
||||||
|
pp::FloatPoint touchPos = touchPoint.position();
|
||||||
|
LiSendTouchEvent(eventType, touchPoint.id(),
|
||||||
|
MIN(MAX(touchPos.x(), 0), m_PluginRect.width()) / m_PluginRect.width(),
|
||||||
|
MIN(MAX(touchPos.y(), 0), m_PluginRect.height()) / m_PluginRect.height(),
|
||||||
|
touchPoint.pressure(),
|
||||||
|
0.0f, 0.0f,
|
||||||
|
touchPoint.rotation_angle());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
||||||
|
// If the host can handle native touch events, send them natively
|
||||||
|
if (TryHandleNativeTouchEvent(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event.GetType()) {
|
switch (event.GetType()) {
|
||||||
case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
|
case PP_INPUTEVENT_TYPE_MOUSEDOWN: {
|
||||||
// Lock the mouse cursor when the user clicks on the stream
|
// Lock the mouse cursor when the user clicks on the stream
|
||||||
if (!m_MouseLocked) {
|
if (!m_MouseLocked) {
|
||||||
LockMouse(m_CallbackFactory.NewCallback(&MoonlightInstance::DidLockMouse));
|
LockMouseOrJustCaptureInput();
|
||||||
|
|
||||||
// Assume it worked until we get a callback telling us otherwise
|
|
||||||
m_MouseLocked = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +231,20 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
|||||||
|
|
||||||
pp::MouseInputEvent mouseEvent(event);
|
pp::MouseInputEvent mouseEvent(event);
|
||||||
pp::Point posDelta = mouseEvent.GetMovement();
|
pp::Point posDelta = mouseEvent.GetMovement();
|
||||||
|
pp::Point position = mouseEvent.GetPosition();
|
||||||
|
|
||||||
|
// Wait to report mouse movement until the next input polling window
|
||||||
|
// to allow batching to occur which reduces overall input lag.
|
||||||
|
if (m_MouseLocked) {
|
||||||
|
if (m_MouseLockingFeatureEnabled) {
|
||||||
|
m_MouseDeltaX += posDelta.x();
|
||||||
|
m_MouseDeltaY += posDelta.y();
|
||||||
|
} else {
|
||||||
|
m_MousePositionX = position.x();
|
||||||
|
m_MousePositionY = position.y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LiSendMouseMoveEvent(posDelta.x(), posDelta.y());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,8 +260,6 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PP_INPUTEVENT_TYPE_WHEEL: {
|
case PP_INPUTEVENT_TYPE_WHEEL: {
|
||||||
signed char fullTicks;
|
|
||||||
|
|
||||||
if (!m_MouseLocked) {
|
if (!m_MouseLocked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -103,15 +268,6 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
|||||||
|
|
||||||
// Accumulate the current tick value
|
// Accumulate the current tick value
|
||||||
m_AccumulatedTicks += wheelEvent.GetTicks().y();
|
m_AccumulatedTicks += wheelEvent.GetTicks().y();
|
||||||
|
|
||||||
// Compute the number of full ticks
|
|
||||||
fullTicks = (signed char) m_AccumulatedTicks;
|
|
||||||
|
|
||||||
// Send a scroll event if we've completed a full tick
|
|
||||||
if (fullTicks != 0) {
|
|
||||||
LiSendScrollEvent(fullTicks);
|
|
||||||
m_AccumulatedTicks -= fullTicks;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,9 +278,10 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
|||||||
|
|
||||||
pp::KeyboardInputEvent keyboardEvent(event);
|
pp::KeyboardInputEvent keyboardEvent(event);
|
||||||
char modifiers = GetModifierFlags(event);
|
char modifiers = GetModifierFlags(event);
|
||||||
|
uint32_t keyCode = GetTranslatedKeyCode(keyboardEvent);
|
||||||
|
|
||||||
if (modifiers == (MODIFIER_ALT | MODIFIER_CTRL | MODIFIER_SHIFT)) {
|
if (modifiers == (MODIFIER_ALT | MODIFIER_CTRL | MODIFIER_SHIFT)) {
|
||||||
if (keyboardEvent.GetKeyCode() == 0x51) { // Q key
|
if (keyCode == 0x51) { // Q key
|
||||||
// Terminate the connection
|
// Terminate the connection
|
||||||
StopConnection();
|
StopConnection();
|
||||||
return true;
|
return true;
|
||||||
@@ -135,31 +292,72 @@ bool MoonlightInstance::HandleInputEvent(const pp::InputEvent& event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LiSendKeyboardEvent(KEY_PREFIX << 8 | keyboardEvent.GetKeyCode(),
|
if (event.GetModifiers() & PP_INPUTEVENT_MODIFIER_ISAUTOREPEAT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LiSendKeyboardEvent(KEY_PREFIX << 8 | keyCode,
|
||||||
KEY_ACTION_DOWN, modifiers);
|
KEY_ACTION_DOWN, modifiers);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PP_INPUTEVENT_TYPE_KEYUP: {
|
case PP_INPUTEVENT_TYPE_KEYUP: {
|
||||||
if (!m_MouseLocked) {
|
if (!m_MouseLocked) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pp::KeyboardInputEvent keyboardEvent(event);
|
pp::KeyboardInputEvent keyboardEvent(event);
|
||||||
char modifiers = GetModifierFlags(event);
|
char modifiers = GetModifierFlags(event);
|
||||||
|
uint32_t keyCode = GetTranslatedKeyCode(keyboardEvent);
|
||||||
|
|
||||||
// Check if all modifiers are up now
|
// Check if all modifiers are up now
|
||||||
if (m_WaitingForAllModifiersUp && modifiers == 0) {
|
if (m_WaitingForAllModifiersUp && modifiers == 0) {
|
||||||
UnlockMouse();
|
UnlockMouseOrJustReleaseInput();
|
||||||
m_MouseLocked = false;
|
|
||||||
m_WaitingForAllModifiersUp = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LiSendKeyboardEvent(KEY_PREFIX << 8 | keyboardEvent.GetKeyCode(),
|
LiSendKeyboardEvent(KEY_PREFIX << 8 | keyCode,
|
||||||
KEY_ACTION_UP, modifiers);
|
KEY_ACTION_UP, modifiers);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHMOVE:
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHSTART: {
|
||||||
|
pp::TouchInputEvent touchEvent(event);
|
||||||
|
|
||||||
|
pp::FloatPoint touchPoint = touchEvent.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, 0).position();
|
||||||
|
|
||||||
|
// Create a small deadzone for touch downs to allow more precise double-clicks
|
||||||
|
if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHMOVE ||
|
||||||
|
event.GetTimeStamp() - m_LastTouchUpTime > TOUCH_DEAD_ZONE_DELAY ||
|
||||||
|
sqrt(pow(m_LastTouchUpPoint.x() - touchPoint.x(), 2) +
|
||||||
|
pow(m_LastTouchUpPoint.y() - touchPoint.y(), 2)) > TOUCH_DEAD_ZONE_RADIUS) {
|
||||||
|
// Scale the touch coordinates to the video rect
|
||||||
|
short x = MIN(MAX(touchPoint.x(), 0), m_PluginRect.width());
|
||||||
|
short y = MIN(MAX(touchPoint.y(), 0), m_PluginRect.height());
|
||||||
|
|
||||||
|
// Update the mouse position prior to sending the button down
|
||||||
|
LiSendMousePositionEvent(x, y, m_PluginRect.width(), m_PluginRect.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.GetType() == PP_INPUTEVENT_TYPE_TOUCHSTART &&
|
||||||
|
touchEvent.GetTouchCount(PP_TOUCHLIST_TYPE_TARGETTOUCHES) == 1) {
|
||||||
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHCANCEL:
|
||||||
|
case PP_INPUTEVENT_TYPE_TOUCHEND: {
|
||||||
|
pp::TouchInputEvent touchEvent(event);
|
||||||
|
|
||||||
|
if (touchEvent.GetTouchCount(PP_TOUCHLIST_TYPE_TARGETTOUCHES) == 1) {
|
||||||
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
|
m_LastTouchUpTime = event.GetTimeStamp();
|
||||||
|
m_LastTouchUpPoint = touchEvent.GetTouchByIndex(PP_TOUCHLIST_TYPE_TARGETTOUCHES, 0).position();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <sys/timeb.h>
|
#include <sys/timeb.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
// This function is defined but not implemented by newlib
|
// This function is defined but not implemented by newlib
|
||||||
int ftime(struct timeb *tp) {
|
int ftime(struct timeb *tp) {
|
||||||
@@ -16,3 +17,10 @@ int ftime(struct timeb *tp) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is required for libcurl to link but never
|
||||||
|
// called using by any of the APIs we use
|
||||||
|
unsigned alarm(unsigned seconds) {
|
||||||
|
abort();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,3 +27,4 @@
|
|||||||
#define GS_IO_ERROR -5
|
#define GS_IO_ERROR -5
|
||||||
#define GS_NOT_SUPPORTED_4K -6
|
#define GS_NOT_SUPPORTED_4K -6
|
||||||
|
|
||||||
|
#define GS_CERT_MISMATCH -100
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ static CURLcode sslctx_function(CURL * curl, void * sslctx, void * parm)
|
|||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_request(char* url, PHTTP_DATA data) {
|
int http_request(const char* url, const char* ppkstr, PHTTP_DATA data) {
|
||||||
int ret;
|
int ret;
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
|
|
||||||
@@ -67,12 +67,7 @@ int http_request(char* url, PHTTP_DATA data) {
|
|||||||
if (!curl)
|
if (!curl)
|
||||||
return GS_FAILED;
|
return GS_FAILED;
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
curl_easy_setopt(curl, CURLOPT_CAINFO, "/curl/ca-bundle.crt");
|
||||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE,"PEM");
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
|
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl);
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl);
|
||||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
|
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
|
||||||
@@ -80,11 +75,19 @@ int http_request(char* url, PHTTP_DATA data) {
|
|||||||
curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 0L);
|
curl_easy_setopt(curl, CURLOPT_MAXCONNECTS, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
|
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
|
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
|
||||||
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5L);
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 3L);
|
||||||
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
|
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_ENABLE_ALPN, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
|
|
||||||
|
// Use the pinned certificate for HTTPS
|
||||||
|
if (ppkstr != NULL) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, ppkstr);
|
||||||
|
}
|
||||||
|
|
||||||
if (data->size > 0) {
|
if (data->size > 0) {
|
||||||
free(data->memory);
|
free(data->memory);
|
||||||
data->memory = malloc(1);
|
data->memory = malloc(1);
|
||||||
@@ -98,7 +101,11 @@ int http_request(char* url, PHTTP_DATA data) {
|
|||||||
|
|
||||||
CURLcode res = curl_easy_perform(curl);
|
CURLcode res = curl_easy_perform(curl);
|
||||||
|
|
||||||
if(res != CURLE_OK) {
|
printf("CURL: %s (PPK: '%s') -> %s\n", url, ppkstr ? ppkstr : "<NULL>", curl_easy_strerror(res));
|
||||||
|
|
||||||
|
if (res == CURLE_SSL_PINNEDPUBKEYNOTMATCH) {
|
||||||
|
ret = GS_CERT_MISMATCH;
|
||||||
|
} else if (res != CURLE_OK) {
|
||||||
ret = GS_FAILED;
|
ret = GS_FAILED;
|
||||||
} else if (data->memory == NULL) {
|
} else if (data->memory == NULL) {
|
||||||
ret = GS_OUT_OF_MEMORY;
|
ret = GS_OUT_OF_MEMORY;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ typedef struct _HTTP_DATA {
|
|||||||
} HTTP_DATA, *PHTTP_DATA;
|
} HTTP_DATA, *PHTTP_DATA;
|
||||||
|
|
||||||
PHTTP_DATA http_create_data();
|
PHTTP_DATA http_create_data();
|
||||||
int http_request(char* url, PHTTP_DATA data);
|
int http_request(const char* url, const char* ppkstr, PHTTP_DATA data);
|
||||||
void http_free_data(PHTTP_DATA data);
|
void http_free_data(PHTTP_DATA data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -128,13 +128,7 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
|||||||
*/
|
*/
|
||||||
X509_set_issuer_name(x, name);
|
X509_set_issuer_name(x, name);
|
||||||
|
|
||||||
/* Add various extensions: standard extensions */
|
if (!X509_sign(x, pk, EVP_sha256())) {
|
||||||
add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
|
|
||||||
add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");
|
|
||||||
|
|
||||||
add_ext(x, NID_subject_key_identifier, "hash");
|
|
||||||
|
|
||||||
if (!X509_sign(x, pk, EVP_sha1())) {
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,29 +139,3 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
|||||||
err:
|
err:
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add extension using V3 code: we can set the config file as NULL
|
|
||||||
* because we wont reference any other sections.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int add_ext(X509 *cert, int nid, char *value)
|
|
||||||
{
|
|
||||||
X509_EXTENSION *ex;
|
|
||||||
X509V3_CTX ctx;
|
|
||||||
/* This sets the 'context' of the extensions. */
|
|
||||||
/* No configuration database */
|
|
||||||
X509V3_set_ctx_nodb(&ctx);
|
|
||||||
/* Issuer and subject certs: both the target since it is self signed,
|
|
||||||
* no request and no CRL
|
|
||||||
*/
|
|
||||||
X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
|
|
||||||
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
|
|
||||||
if (!ex) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
X509_add_ext(cert, ex, -1);
|
|
||||||
X509_EXTENSION_free(ex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ static int xml_search(char* data, size_t len, char* node, char** result) {
|
|||||||
|
|
||||||
startOffset = strstr(data, startTag);
|
startOffset = strstr(data, startTag);
|
||||||
if (startOffset == NULL) {
|
if (startOffset == NULL) {
|
||||||
|
free(data);
|
||||||
return GS_FAILED;
|
return GS_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
endOffset = strstr(data, endTag);
|
endOffset = strstr(data, endTag);
|
||||||
if (endOffset == NULL) {
|
if (endOffset == NULL) {
|
||||||
|
free(data);
|
||||||
return GS_FAILED;
|
return GS_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,6 +69,7 @@ static int xml_search(char* data, size_t len, char* node, char** result) {
|
|||||||
*result = malloc(strlen(startOffset + strlen(startTag)) + 1);
|
*result = malloc(strlen(startOffset + strlen(startTag)) + 1);
|
||||||
strcpy(*result, startOffset + strlen(startTag));
|
strcpy(*result, startOffset + strlen(startTag));
|
||||||
|
|
||||||
|
free(data);
|
||||||
return GS_OK;
|
return GS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,115 +129,283 @@ cleanup:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
static bool verifySignature(const unsigned char *data, int dataLength, unsigned char *signature, int signatureLength, X509 *cert) {
|
||||||
int ret = GS_OK;
|
EVP_PKEY* pubKey = X509_get_pubkey(cert);
|
||||||
char url[4096];
|
EVP_MD_CTX *mdctx = NULL;
|
||||||
|
mdctx = EVP_MD_CTX_create();
|
||||||
|
EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pubKey);
|
||||||
|
EVP_DigestVerifyUpdate(mdctx, data, dataLength);
|
||||||
|
int result = EVP_DigestVerifyFinal(mdctx, signature, signatureLength);
|
||||||
|
|
||||||
unsigned char salt_data[16];
|
EVP_PKEY_free(pubKey);
|
||||||
char salt_hex[33];
|
EVP_MD_CTX_destroy(mdctx);
|
||||||
RAND_bytes(salt_data, 16);
|
|
||||||
bytes_to_hex(salt_data, salt_hex, 16);
|
|
||||||
|
|
||||||
sprintf(url, "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", address, g_UniqueId, salt_hex, g_CertHex);
|
return result > 0;
|
||||||
PHTTP_DATA data = http_create_data();
|
}
|
||||||
if (data == NULL)
|
|
||||||
return GS_OUT_OF_MEMORY;
|
|
||||||
else if ((ret = http_request(url, data)) != GS_OK)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
unsigned char salt_pin[20];
|
X509* get_cert(PHTTP_DATA data) {
|
||||||
unsigned char aes_key_hash[32];
|
char *pemcerthex;
|
||||||
AES_KEY enc_key, dec_key;
|
|
||||||
memcpy(salt_pin, salt_data, 16);
|
|
||||||
memcpy(salt_pin+16, pin, 4);
|
|
||||||
|
|
||||||
int hash_length = serverMajorVersion >= 7 ? 32 : 20;
|
if (xml_search(data->memory, data->size, "plaincert", &pemcerthex) != GS_OK)
|
||||||
if (serverMajorVersion >= 7)
|
return NULL;
|
||||||
SHA256(salt_pin, 20, aes_key_hash);
|
|
||||||
else
|
|
||||||
SHA1(salt_pin, 20, aes_key_hash);
|
|
||||||
|
|
||||||
AES_set_encrypt_key((unsigned char *)aes_key_hash, 128, &enc_key);
|
// Convert cert from hex string to the PEM string and null terminate
|
||||||
AES_set_decrypt_key((unsigned char *)aes_key_hash, 128, &dec_key);
|
int hexstrlen = strlen(pemcerthex);
|
||||||
|
char *pemcert = malloc(hexstrlen / 2 + 1);
|
||||||
unsigned char challenge_data[16];
|
for (int count = 0; count < hexstrlen; count += 2) {
|
||||||
unsigned char challenge_enc[16];
|
sscanf(&pemcerthex[count], "%2hhx", &pemcert[count / 2]);
|
||||||
char challenge_hex[33];
|
|
||||||
RAND_bytes(challenge_data, 16);
|
|
||||||
AES_encrypt(challenge_data, challenge_enc, &enc_key);
|
|
||||||
bytes_to_hex(challenge_enc, challenge_hex, 16);
|
|
||||||
|
|
||||||
sprintf(url, "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", address, g_UniqueId, challenge_hex);
|
|
||||||
if ((ret = http_request(url, data)) != GS_OK)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
char *result;
|
|
||||||
if (xml_search(data->memory, data->size, "challengeresponse", &result) != GS_OK) {
|
|
||||||
ret = GS_INVALID;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
pemcert[hexstrlen / 2] = 0;
|
||||||
|
free(pemcerthex);
|
||||||
|
|
||||||
unsigned char challenge_response_data_enc[48];
|
// pemcert is referenced, but NOT copied!
|
||||||
unsigned char challenge_response_data[48];
|
BIO* bio = BIO_new_mem_buf(pemcert, -1);
|
||||||
for (int count = 0; count < strlen(result); count += 2) {
|
|
||||||
sscanf(&result[count], "%2hhx", &challenge_response_data_enc[count / 2]);
|
if (bio) {
|
||||||
|
X509* cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
BIO_free_all(bio);
|
||||||
|
free(pemcert);
|
||||||
|
return cert;
|
||||||
}
|
}
|
||||||
free(result);
|
else {
|
||||||
|
free(pemcert);
|
||||||
for (int i = 0; i < 48; i += 16) {
|
return NULL;
|
||||||
AES_decrypt(&challenge_response_data_enc[i], &challenge_response_data[i], &dec_key);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char client_secret_data[16];
|
static char* x509_to_curl_ppk_string(X509* x509) {
|
||||||
RAND_bytes(client_secret_data, 16);
|
BIO* bio = BIO_new(BIO_s_mem());
|
||||||
|
|
||||||
unsigned char challenge_response[16 + 256 + 16];
|
// Get x509 public key alone in DER format
|
||||||
unsigned char challenge_response_hash[32];
|
EVP_PKEY* pubkey = X509_get_pubkey(x509);
|
||||||
unsigned char challenge_response_hash_enc[32];
|
i2d_PUBKEY_bio(bio, pubkey);
|
||||||
char challenge_response_hex[65];
|
EVP_PKEY_free(pubkey);
|
||||||
memcpy(challenge_response, challenge_response_data + hash_length, 16);
|
|
||||||
memcpy(challenge_response + 16, g_Cert->signature->data, 256);
|
|
||||||
memcpy(challenge_response + 16 + 256, client_secret_data, 16);
|
|
||||||
|
|
||||||
if (serverMajorVersion >= 7)
|
BUF_MEM* mem;
|
||||||
SHA256(challenge_response, 16 + 256 + 16, challenge_response_hash);
|
BIO_get_mem_ptr(bio, &mem);
|
||||||
else
|
|
||||||
SHA1(challenge_response, 16 + 256 + 16, challenge_response_hash);
|
|
||||||
|
|
||||||
for (int i = 0; i < 32; i += 16) {
|
// SHA256 hash the resulting DER string
|
||||||
AES_encrypt(&challenge_response_hash[i], &challenge_response_hash_enc[i], &enc_key);
|
unsigned char pubkeyhash[32];
|
||||||
}
|
SHA256((unsigned char*)mem->data, mem->length, pubkeyhash);
|
||||||
bytes_to_hex(challenge_response_hash_enc, challenge_response_hex, 32);
|
BIO_free(bio);
|
||||||
|
|
||||||
sprintf(url, "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", address, g_UniqueId, challenge_response_hex);
|
// Base64-encode the resulting SHA256 hash
|
||||||
if ((ret = http_request(url, data)) != GS_OK)
|
bio = BIO_new(BIO_s_mem());
|
||||||
goto cleanup;
|
BIO* b64 = BIO_new(BIO_f_base64());
|
||||||
|
bio = BIO_push(b64, bio);
|
||||||
|
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
BIO_write(bio, pubkeyhash, sizeof(pubkeyhash));
|
||||||
|
BIO_flush(bio);
|
||||||
|
|
||||||
if (xml_search(data->memory, data->size, "pairingsecret", &result) != GS_OK) {
|
BIO_get_mem_ptr(bio, &mem);
|
||||||
ret = GS_INVALID;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *signature = NULL;
|
// Assemble the final curl PPK string
|
||||||
size_t s_len;
|
const char* prefix = "sha256//";
|
||||||
if (sign_it(client_secret_data, 16, &signature, &s_len, g_PrivateKey) != GS_OK) {
|
char* ret = malloc(strlen(prefix) + mem->length + 1);
|
||||||
gs_error = "Failed to sign data";
|
memcpy(ret, prefix, strlen(prefix));
|
||||||
ret = GS_FAILED;
|
memcpy(&ret[strlen(prefix)], mem->data, mem->length);
|
||||||
goto cleanup;
|
ret[strlen(prefix) + mem->length] = 0;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char client_pairing_secret[16 + 256];
|
BIO_free_all(bio);
|
||||||
char client_pairing_secret_hex[(16 + 256) * 2 + 1];
|
|
||||||
memcpy(client_pairing_secret, client_secret_data, 16);
|
|
||||||
memcpy(client_pairing_secret + 16, signature, 256);
|
|
||||||
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, 16 + 256);
|
|
||||||
|
|
||||||
sprintf(url, "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, g_UniqueId, client_pairing_secret_hex);
|
|
||||||
if ((ret = http_request(url, data)) != GS_OK)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
http_free_data(data);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int gs_unpair(const char* address) {
|
||||||
|
int ret = GS_OK;
|
||||||
|
char url[4096];
|
||||||
|
PHTTP_DATA data = http_create_data();
|
||||||
|
if (data == NULL)
|
||||||
|
return GS_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
snprintf(url, sizeof(url), "http://%s:47989/unpair?uniqueid=%s", address, g_UniqueId);
|
||||||
|
ret = http_request(url, NULL, data);
|
||||||
|
|
||||||
|
http_free_data(data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gs_pair(int serverMajorVersion, const char* address, const char* pin, char** curl_ppk_string) {
|
||||||
|
int ret = GS_OK;
|
||||||
|
char* result = NULL;
|
||||||
|
X509* server_cert = NULL;
|
||||||
|
char url[4096];
|
||||||
|
|
||||||
|
unsigned char salt_data[16];
|
||||||
|
char salt_hex[33];
|
||||||
|
RAND_bytes(salt_data, 16);
|
||||||
|
bytes_to_hex(salt_data, salt_hex, 16);
|
||||||
|
|
||||||
|
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", address, g_UniqueId, salt_hex, g_CertHex);
|
||||||
|
PHTTP_DATA data = http_create_data();
|
||||||
|
if (data == NULL)
|
||||||
|
return GS_OUT_OF_MEMORY;
|
||||||
|
else if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (strcmp(result, "1") != 0) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
server_cert = get_cert(data);
|
||||||
|
if (server_cert == NULL) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char salt_pin[20];
|
||||||
|
unsigned char aes_key_hash[32];
|
||||||
|
AES_KEY enc_key, dec_key;
|
||||||
|
memcpy(salt_pin, salt_data, 16);
|
||||||
|
memcpy(salt_pin+16, pin, 4);
|
||||||
|
|
||||||
|
int hash_length = serverMajorVersion >= 7 ? 32 : 20;
|
||||||
|
if (serverMajorVersion >= 7)
|
||||||
|
SHA256(salt_pin, 20, aes_key_hash);
|
||||||
|
else
|
||||||
|
SHA1(salt_pin, 20, aes_key_hash);
|
||||||
|
|
||||||
|
AES_set_encrypt_key((unsigned char *)aes_key_hash, 128, &enc_key);
|
||||||
|
AES_set_decrypt_key((unsigned char *)aes_key_hash, 128, &dec_key);
|
||||||
|
|
||||||
|
unsigned char challenge_data[16];
|
||||||
|
unsigned char challenge_enc[16];
|
||||||
|
char challenge_hex[33];
|
||||||
|
RAND_bytes(challenge_data, 16);
|
||||||
|
AES_encrypt(challenge_data, challenge_enc, &enc_key);
|
||||||
|
bytes_to_hex(challenge_enc, challenge_hex, 16);
|
||||||
|
|
||||||
|
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", address, g_UniqueId, challenge_hex);
|
||||||
|
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (strcmp(result, "1") != 0) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
if (xml_search(data->memory, data->size, "challengeresponse", &result) != GS_OK) {
|
||||||
|
ret = GS_INVALID;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char challenge_response_data_enc[48];
|
||||||
|
unsigned char challenge_response_data[48];
|
||||||
|
for (int count = 0; count < strlen(result); count += 2) {
|
||||||
|
sscanf(&result[count], "%2hhx", &challenge_response_data_enc[count / 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 48; i += 16) {
|
||||||
|
AES_decrypt(&challenge_response_data_enc[i], &challenge_response_data[i], &dec_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char client_secret_data[16];
|
||||||
|
RAND_bytes(client_secret_data, 16);
|
||||||
|
|
||||||
|
ASN1_BIT_STRING *asnSignature;
|
||||||
|
X509_get0_signature(&asnSignature, NULL, g_Cert);
|
||||||
|
|
||||||
|
unsigned char challenge_response[16 + 256 + 16];
|
||||||
|
unsigned char challenge_response_hash[32];
|
||||||
|
unsigned char challenge_response_hash_enc[32];
|
||||||
|
char challenge_response_hex[65];
|
||||||
|
memcpy(challenge_response, challenge_response_data + hash_length, 16);
|
||||||
|
memcpy(challenge_response + 16, asnSignature->data, 256);
|
||||||
|
memcpy(challenge_response + 16 + 256, client_secret_data, 16);
|
||||||
|
if (serverMajorVersion >= 7)
|
||||||
|
SHA256(challenge_response, 16 + 256 + 16, challenge_response_hash);
|
||||||
|
else
|
||||||
|
SHA1(challenge_response, 16 + 256 + 16, challenge_response_hash);
|
||||||
|
|
||||||
|
for (int i = 0; i < 32; i += 16) {
|
||||||
|
AES_encrypt(&challenge_response_hash[i], &challenge_response_hash_enc[i], &enc_key);
|
||||||
|
}
|
||||||
|
bytes_to_hex(challenge_response_hash_enc, challenge_response_hex, 32);
|
||||||
|
|
||||||
|
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", address, g_UniqueId, challenge_response_hex);
|
||||||
|
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (strcmp(result, "1") != 0) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
if (xml_search(data->memory, data->size, "pairingsecret", &result) != GS_OK) {
|
||||||
|
ret = GS_INVALID;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char pairing_secret[16 + 256];
|
||||||
|
for (int count = 0; count < strlen(result); count += 2) {
|
||||||
|
sscanf(&result[count], "%2hhx", &pairing_secret[count / 2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!verifySignature(pairing_secret, 16, pairing_secret+16, 256, server_cert)) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *signature = NULL;
|
||||||
|
size_t s_len;
|
||||||
|
if (sign_it(client_secret_data, 16, &signature, &s_len, g_PrivateKey) != GS_OK) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char client_pairing_secret[16 + 256];
|
||||||
|
char client_pairing_secret_hex[(16 + 256) * 2 + 1];
|
||||||
|
memcpy(client_pairing_secret, client_secret_data, 16);
|
||||||
|
memcpy(client_pairing_secret + 16, signature, 256);
|
||||||
|
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, 16 + 256);
|
||||||
|
|
||||||
|
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, g_UniqueId, client_pairing_secret_hex);
|
||||||
|
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
free(result);
|
||||||
|
result = NULL;
|
||||||
|
if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (strcmp(result, "1") != 0) {
|
||||||
|
ret = GS_FAILED;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
*curl_ppk_string = x509_to_curl_ppk_string(server_cert);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (ret != GS_OK)
|
||||||
|
gs_unpair(address);
|
||||||
|
|
||||||
|
if (result != NULL)
|
||||||
|
free(result);
|
||||||
|
|
||||||
|
if (server_cert != NULL)
|
||||||
|
X509_free(server_cert);
|
||||||
|
|
||||||
|
http_free_data(data);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin);
|
int gs_pair(int serverMajorVersion, const char* address, const char* pin, char** server_cert_der_string);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
119
main.cpp
@@ -10,20 +10,20 @@
|
|||||||
#include "ppapi/cpp/input_event.h"
|
#include "ppapi/cpp/input_event.h"
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
// Requests the NaCl module to connection to the server specified after the :
|
// Requests the NaCl module to connection to the server specified after the :
|
||||||
#define MSG_START_REQUEST "startRequest"
|
#define MSG_START_REQUEST "startRequest"
|
||||||
// Requests the NaCl module stop streaming
|
// Requests the NaCl module stop streaming
|
||||||
#define MSG_STOP_REQUEST "stopRequest"
|
#define MSG_STOP_REQUEST "stopRequest"
|
||||||
// Sent by the NaCl module when the stream has stopped whether user-requested or not
|
// Sent by the NaCl module when the stream has stopped whether user-requested or not
|
||||||
#define MSG_STREAM_TERMINATED "streamTerminated"
|
#define MSG_STREAM_TERMINATED "streamTerminated: "
|
||||||
|
|
||||||
#define MSG_OPENURL "openUrl"
|
#define MSG_OPENURL "openUrl"
|
||||||
|
|
||||||
MoonlightInstance* g_Instance;
|
MoonlightInstance* g_Instance;
|
||||||
|
|
||||||
MoonlightInstance::~MoonlightInstance() {}
|
|
||||||
|
|
||||||
class MoonlightModule : public pp::Module {
|
class MoonlightModule : public pp::Module {
|
||||||
public:
|
public:
|
||||||
MoonlightModule() : pp::Module() {}
|
MoonlightModule() : pp::Module() {}
|
||||||
@@ -40,7 +40,7 @@ void MoonlightInstance::OnConnectionStarted(uint32_t unused) {
|
|||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
|
|
||||||
// Start receiving input events
|
// Start receiving input events
|
||||||
RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL);
|
RequestInputEvents(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_TOUCH);
|
||||||
|
|
||||||
// Filtering is suboptimal but it ensures that we can pass keyboard events
|
// Filtering is suboptimal but it ensures that we can pass keyboard events
|
||||||
// to the browser when mouse lock is disabled. This is neccessary for Esc
|
// to the browser when mouse lock is disabled. This is neccessary for Esc
|
||||||
@@ -53,13 +53,16 @@ void MoonlightInstance::OnConnectionStopped(uint32_t error) {
|
|||||||
m_Running = false;
|
m_Running = false;
|
||||||
|
|
||||||
// Stop receiving input events
|
// Stop receiving input events
|
||||||
ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE | PP_INPUTEVENT_CLASS_WHEEL | PP_INPUTEVENT_CLASS_KEYBOARD);
|
ClearInputEventRequest(PP_INPUTEVENT_CLASS_MOUSE |
|
||||||
|
PP_INPUTEVENT_CLASS_WHEEL |
|
||||||
|
PP_INPUTEVENT_CLASS_KEYBOARD |
|
||||||
|
PP_INPUTEVENT_CLASS_TOUCH);
|
||||||
|
|
||||||
// Unlock the mouse
|
// Unlock the mouse
|
||||||
UnlockMouse();
|
UnlockMouseOrJustReleaseInput();
|
||||||
|
|
||||||
// Notify the JS code that the stream has ended
|
// Notify the JS code that the stream has ended
|
||||||
pp::Var response(MSG_STREAM_TERMINATED);
|
pp::Var response(std::string(MSG_STREAM_TERMINATED) + std::to_string((int)error));
|
||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,26 +83,35 @@ void* MoonlightInstance::StopThreadFunc(void* context) {
|
|||||||
// not be invoked during LiStartConnection.
|
// not be invoked during LiStartConnection.
|
||||||
pthread_join(g_Instance->m_ConnectionThread, NULL);
|
pthread_join(g_Instance->m_ConnectionThread, NULL);
|
||||||
|
|
||||||
|
// Force raise all modifier keys to avoid leaving them down after disconnecting
|
||||||
|
LiSendKeyboardEvent(0xA0, KEY_ACTION_UP, 0);
|
||||||
|
LiSendKeyboardEvent(0xA1, KEY_ACTION_UP, 0);
|
||||||
|
LiSendKeyboardEvent(0xA2, KEY_ACTION_UP, 0);
|
||||||
|
LiSendKeyboardEvent(0xA3, KEY_ACTION_UP, 0);
|
||||||
|
LiSendKeyboardEvent(0xA4, KEY_ACTION_UP, 0);
|
||||||
|
LiSendKeyboardEvent(0xA5, KEY_ACTION_UP, 0);
|
||||||
|
|
||||||
// Not running anymore
|
// Not running anymore
|
||||||
g_Instance->m_Running = false;
|
g_Instance->m_Running = false;
|
||||||
|
|
||||||
// We also need to stop this thread after the connection thread, because it depends
|
// We also need to stop this thread after the connection thread, because it depends
|
||||||
// on being initialized there.
|
// on being initialized there.
|
||||||
pthread_join(g_Instance->m_GamepadThread, NULL);
|
pthread_join(g_Instance->m_InputThread, NULL);
|
||||||
|
|
||||||
// Stop the connection
|
// Stop the connection
|
||||||
LiStopConnection();
|
LiStopConnection();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* MoonlightInstance::GamepadThreadFunc(void* context) {
|
void* MoonlightInstance::InputThreadFunc(void* context) {
|
||||||
MoonlightInstance* me = (MoonlightInstance*)context;
|
MoonlightInstance* me = (MoonlightInstance*)context;
|
||||||
|
|
||||||
while (me->m_Running) {
|
while (me->m_Running) {
|
||||||
me->PollGamepads();
|
me->PollGamepads();
|
||||||
|
me->ReportMouseMovement();
|
||||||
|
|
||||||
// Poll every 10 ms
|
// Poll every 5 ms
|
||||||
usleep(10 * 1000);
|
usleep(5 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -117,16 +129,22 @@ void* MoonlightInstance::ConnectionThreadFunc(void* context) {
|
|||||||
LiInitializeServerInformation(&serverInfo);
|
LiInitializeServerInformation(&serverInfo);
|
||||||
serverInfo.address = me->m_Host.c_str();
|
serverInfo.address = me->m_Host.c_str();
|
||||||
serverInfo.serverInfoAppVersion = me->m_AppVersion.c_str();
|
serverInfo.serverInfoAppVersion = me->m_AppVersion.c_str();
|
||||||
|
serverInfo.serverInfoGfeVersion = me->m_GfeVersion.c_str();
|
||||||
|
serverInfo.rtspSessionUrl = me->m_RtspUrl.c_str();
|
||||||
|
serverInfo.serverCodecModeSupport = SCM_H264;
|
||||||
|
|
||||||
err = LiStartConnection(&serverInfo,
|
err = LiStartConnection(&serverInfo,
|
||||||
&me->m_StreamConfig,
|
&me->m_StreamConfig,
|
||||||
&MoonlightInstance::s_ClCallbacks,
|
&MoonlightInstance::s_ClCallbacks,
|
||||||
&MoonlightInstance::s_DrCallbacks,
|
&MoonlightInstance::s_DrCallbacks,
|
||||||
&MoonlightInstance::s_ArCallbacks,
|
&MoonlightInstance::s_ArCallbacks,
|
||||||
|
NULL, 0,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
// Notify the JS code that the stream has ended
|
// Notify the JS code that the stream has ended
|
||||||
pp::Var response(MSG_STREAM_TERMINATED);
|
// NB: We pass error code 0 here to avoid triggering a "Connection terminated"
|
||||||
|
// warning message.
|
||||||
|
pp::Var response(MSG_STREAM_TERMINATED + std::to_string(0));
|
||||||
me->PostMessage(response);
|
me->PostMessage(response);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -134,7 +152,7 @@ void* MoonlightInstance::ConnectionThreadFunc(void* context) {
|
|||||||
// Set running state before starting connection-specific threads
|
// Set running state before starting connection-specific threads
|
||||||
me->m_Running = true;
|
me->m_Running = true;
|
||||||
|
|
||||||
pthread_create(&me->m_GamepadThread, NULL, MoonlightInstance::GamepadThreadFunc, me);
|
pthread_create(&me->m_InputThread, NULL, MoonlightInstance::InputThreadFunc, me);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -162,6 +180,8 @@ void MoonlightInstance::HandleMessage(const pp::Var& var_message) {
|
|||||||
MakeCert(callbackId, params);
|
MakeCert(callbackId, params);
|
||||||
} else if (strcmp(method.c_str(), "pair") == 0) {
|
} else if (strcmp(method.c_str(), "pair") == 0) {
|
||||||
HandlePair(callbackId, params);
|
HandlePair(callbackId, params);
|
||||||
|
} else if (strcmp(method.c_str(), "STUN") == 0) {
|
||||||
|
HandleSTUN(callbackId, params);
|
||||||
} else {
|
} else {
|
||||||
pp::Var response("Unhandled message received: " + method);
|
pp::Var response("Unhandled message received: " + method);
|
||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
@@ -182,7 +202,10 @@ void MoonlightInstance::HandleStartStream(int32_t callbackId, pp::VarArray args)
|
|||||||
std::string bitrate = args.Get(4).AsString();
|
std::string bitrate = args.Get(4).AsString();
|
||||||
std::string rikey = args.Get(5).AsString();
|
std::string rikey = args.Get(5).AsString();
|
||||||
std::string rikeyid = args.Get(6).AsString();
|
std::string rikeyid = args.Get(6).AsString();
|
||||||
std::string appversion = args.Get(7).AsString();
|
std::string mouse_lock = args.Get(7).AsString();
|
||||||
|
std::string appversion = args.Get(8).AsString();
|
||||||
|
std::string gfeversion = args.Get(9).AsString();
|
||||||
|
std::string rtspurl = args.Get(10).AsString();
|
||||||
|
|
||||||
pp::Var response("Setting stream width to: " + width);
|
pp::Var response("Setting stream width to: " + width);
|
||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
@@ -200,6 +223,12 @@ void MoonlightInstance::HandleStartStream(int32_t callbackId, pp::VarArray args)
|
|||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
response = ("Setting appversion to: " + appversion);
|
response = ("Setting appversion to: " + appversion);
|
||||||
PostMessage(response);
|
PostMessage(response);
|
||||||
|
response = ("Setting gfeversion to: " + gfeversion);
|
||||||
|
PostMessage(response);
|
||||||
|
response = ("Setting mouse lock to: " + mouse_lock);
|
||||||
|
PostMessage(response);
|
||||||
|
response = ("Setting RTSP URL to: " + rtspurl);
|
||||||
|
PostMessage(response);
|
||||||
|
|
||||||
// Populate the stream configuration
|
// Populate the stream configuration
|
||||||
LiInitializeStreamConfiguration(&m_StreamConfig);
|
LiInitializeStreamConfiguration(&m_StreamConfig);
|
||||||
@@ -207,14 +236,14 @@ void MoonlightInstance::HandleStartStream(int32_t callbackId, pp::VarArray args)
|
|||||||
m_StreamConfig.height = stoi(height);
|
m_StreamConfig.height = stoi(height);
|
||||||
m_StreamConfig.fps = stoi(fps);
|
m_StreamConfig.fps = stoi(fps);
|
||||||
m_StreamConfig.bitrate = stoi(bitrate); // kilobits per second
|
m_StreamConfig.bitrate = stoi(bitrate); // kilobits per second
|
||||||
m_StreamConfig.streamingRemotely = 0;
|
|
||||||
m_StreamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
|
m_StreamConfig.audioConfiguration = AUDIO_CONFIGURATION_STEREO;
|
||||||
|
m_StreamConfig.streamingRemotely = STREAM_CFG_AUTO;
|
||||||
// The overhead of receiving a packet is much higher in NaCl because we must
|
|
||||||
// pass through various layers of abstraction on each recv() call. We're using a
|
|
||||||
// higher than normal default video packet size here to reduce CPU cycles wasted
|
|
||||||
// receiving packets. The possible cost is greater network losses.
|
|
||||||
m_StreamConfig.packetSize = 1392;
|
m_StreamConfig.packetSize = 1392;
|
||||||
|
m_StreamConfig.supportedVideoFormats = VIDEO_FORMAT_H264;
|
||||||
|
|
||||||
|
// TODO: If/when video encryption is added, we'll probably want to
|
||||||
|
// limit that to devices that support AES instructions.
|
||||||
|
m_StreamConfig.encryptionFlags = ENCFLG_AUDIO;
|
||||||
|
|
||||||
// Load the rikey and rikeyid into the stream configuration
|
// Load the rikey and rikeyid into the stream configuration
|
||||||
hexStringToBytes(rikey.c_str(), m_StreamConfig.remoteInputAesKey);
|
hexStringToBytes(rikey.c_str(), m_StreamConfig.remoteInputAesKey);
|
||||||
@@ -224,6 +253,9 @@ void MoonlightInstance::HandleStartStream(int32_t callbackId, pp::VarArray args)
|
|||||||
// Store the parameters from the start message
|
// Store the parameters from the start message
|
||||||
m_Host = host;
|
m_Host = host;
|
||||||
m_AppVersion = appversion;
|
m_AppVersion = appversion;
|
||||||
|
m_GfeVersion = gfeversion;
|
||||||
|
m_RtspUrl = rtspurl;
|
||||||
|
m_MouseLockingFeatureEnabled = stoi(mouse_lock);
|
||||||
|
|
||||||
// Initialize the rendering surface before starting the connection
|
// Initialize the rendering surface before starting the connection
|
||||||
if (InitializeRenderingSurface(m_StreamConfig.width, m_StreamConfig.height)) {
|
if (InitializeRenderingSurface(m_StreamConfig.width, m_StreamConfig.height)) {
|
||||||
@@ -253,25 +285,54 @@ void MoonlightInstance::HandleStopStream(int32_t callbackId, pp::VarArray args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::HandleOpenURL(int32_t callbackId, pp::VarArray args) {
|
void MoonlightInstance::HandleOpenURL(int32_t callbackId, pp::VarArray args) {
|
||||||
std::string url = args.Get(0).AsString();
|
m_HttpThreadPool[m_HttpThreadPoolSequence++ % HTTP_HANDLER_THREADS]->message_loop().PostWork(
|
||||||
bool binaryResponse = args.Get(1).AsBool();
|
m_CallbackFactory.NewCallback(&MoonlightInstance::NvHTTPRequest, callbackId, args));
|
||||||
|
|
||||||
openHttpThread.message_loop().PostWork(m_CallbackFactory.NewCallback(&MoonlightInstance::NvHTTPRequest, callbackId, url, binaryResponse));
|
|
||||||
|
|
||||||
PostMessage(pp::Var (url.c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::HandlePair(int32_t callbackId, pp::VarArray args) {
|
void MoonlightInstance::HandlePair(int32_t callbackId, pp::VarArray args) {
|
||||||
openHttpThread.message_loop().PostWork(m_CallbackFactory.NewCallback(&MoonlightInstance::PairCallback, callbackId, args));
|
m_HttpThreadPool[m_HttpThreadPoolSequence++ % HTTP_HANDLER_THREADS]->message_loop().PostWork(
|
||||||
|
m_CallbackFactory.NewCallback(&MoonlightInstance::PairCallback, callbackId, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MoonlightInstance::PairCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args) {
|
void MoonlightInstance::PairCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args) {
|
||||||
int err = gs_pair(atoi(args.Get(0).AsString().c_str()), args.Get(1).AsString().c_str(), args.Get(2).AsString().c_str());
|
char* ppkstr;
|
||||||
|
int err = gs_pair(atoi(args.Get(0).AsString().c_str()), args.Get(1).AsString().c_str(), args.Get(2).AsString().c_str(), &ppkstr);
|
||||||
|
|
||||||
|
pp::VarDictionary ret;
|
||||||
|
ret.Set("callbackId", pp::Var(callbackId));
|
||||||
|
if (err == 0) {
|
||||||
|
ret.Set("type", pp::Var("resolve"));
|
||||||
|
ret.Set("ret", pp::Var(ppkstr));
|
||||||
|
free(ppkstr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret.Set("type", pp::Var("reject"));
|
||||||
|
ret.Set("ret", pp::Var(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
PostMessage(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::HandleSTUN(int32_t callbackId, pp::VarArray args) {
|
||||||
|
m_HttpThreadPool[m_HttpThreadPoolSequence++ % HTTP_HANDLER_THREADS]->message_loop().PostWork(
|
||||||
|
m_CallbackFactory.NewCallback(&MoonlightInstance::STUNCallback, callbackId, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoonlightInstance::STUNCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args) {
|
||||||
|
unsigned int wanAddr;
|
||||||
|
char addrStr[128] = {};
|
||||||
|
|
||||||
pp::VarDictionary ret;
|
pp::VarDictionary ret;
|
||||||
ret.Set("callbackId", pp::Var(callbackId));
|
ret.Set("callbackId", pp::Var(callbackId));
|
||||||
ret.Set("type", pp::Var("resolve"));
|
ret.Set("type", pp::Var("resolve"));
|
||||||
ret.Set("ret", pp::Var(err));
|
|
||||||
|
if (LiFindExternalAddressIP4("stun.moonlight-stream.org", 3478, &wanAddr) == 0) {
|
||||||
|
inet_ntop(AF_INET, &wanAddr, addrStr, sizeof(addrStr));
|
||||||
|
ret.Set("ret", pp::Var(addrStr));
|
||||||
|
} else {
|
||||||
|
ret.Set("ret", pp::Var());
|
||||||
|
}
|
||||||
|
|
||||||
PostMessage(ret);
|
PostMessage(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Moonlight Game Streaming",
|
"name": "Moonlight Game Streaming",
|
||||||
"short_name": "Moonlight",
|
"short_name": "Moonlight",
|
||||||
"version": "0.7.0",
|
"version": "0.10.27",
|
||||||
"description": "Open-source client for NVIDIA GameStream",
|
"description": "Open-source client for NVIDIA GameStream",
|
||||||
"icons": {
|
"icons": {
|
||||||
"128": "icons/icon128.png",
|
"128": "icons/icon128.png",
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
"pointerLock",
|
"pointerLock",
|
||||||
"system.network",
|
"system.network",
|
||||||
"fullscreen",
|
"fullscreen",
|
||||||
|
"power",
|
||||||
"overrideEscFullscreen", {
|
"overrideEscFullscreen", {
|
||||||
"socket": [
|
"socket": [
|
||||||
"tcp-connect",
|
"tcp-connect",
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
|
|
||||||
#define DR_FLAG_FORCE_SW_DECODE 0x01
|
#define DR_FLAG_FORCE_SW_DECODE 0x01
|
||||||
|
|
||||||
|
// These will mostly be I/O bound so we'll create
|
||||||
|
// a bunch to allow more concurrent server requests
|
||||||
|
// since our HTTP request libary is synchronous.
|
||||||
|
#define HTTP_HANDLER_THREADS 8
|
||||||
|
|
||||||
struct Shader {
|
struct Shader {
|
||||||
Shader() : program(0), texcoord_scale_location(0) {}
|
Shader() : program(0), texcoord_scale_location(0) {}
|
||||||
~Shader() {}
|
~Shader() {}
|
||||||
@@ -53,13 +58,17 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
pp::MouseLock(this),
|
pp::MouseLock(this),
|
||||||
m_HasNextPicture(false),
|
m_HasNextPicture(false),
|
||||||
m_IsPainting(false),
|
m_IsPainting(false),
|
||||||
m_RequestIdrFrame(false),
|
|
||||||
m_OpusDecoder(NULL),
|
m_OpusDecoder(NULL),
|
||||||
m_CallbackFactory(this),
|
m_CallbackFactory(this),
|
||||||
m_MouseLocked(false),
|
m_MouseLocked(false),
|
||||||
m_WaitingForAllModifiersUp(false),
|
m_WaitingForAllModifiersUp(false),
|
||||||
m_AccumulatedTicks(0),
|
m_AccumulatedTicks(0),
|
||||||
openHttpThread(this) {
|
m_MouseDeltaX(0),
|
||||||
|
m_MouseDeltaY(0),
|
||||||
|
m_MousePositionX(0),
|
||||||
|
m_MousePositionY(0),
|
||||||
|
m_LastTouchUpTime(0),
|
||||||
|
m_HttpThreadPoolSequence(0) {
|
||||||
// This function MUST be used otherwise sockets don't work (nacl_io_init() doesn't work!)
|
// This function MUST be used otherwise sockets don't work (nacl_io_init() doesn't work!)
|
||||||
nacl_io_init_ppapi(pp_instance(), pp::Module::Get()->get_browser_interface());
|
nacl_io_init_ppapi(pp_instance(), pp::Module::Get()->get_browser_interface());
|
||||||
|
|
||||||
@@ -69,10 +78,18 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
|
|
||||||
m_GamepadApi = static_cast<const PPB_Gamepad*>(pp::Module::Get()->GetBrowserInterface(PPB_GAMEPAD_INTERFACE));
|
m_GamepadApi = static_cast<const PPB_Gamepad*>(pp::Module::Get()->GetBrowserInterface(PPB_GAMEPAD_INTERFACE));
|
||||||
|
|
||||||
openHttpThread.Start();
|
for (int i = 0; i < HTTP_HANDLER_THREADS; i++) {
|
||||||
|
m_HttpThreadPool[i] = new pp::SimpleThread(this);
|
||||||
|
m_HttpThreadPool[i]->Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MoonlightInstance();
|
virtual ~MoonlightInstance() {
|
||||||
|
for (int i = 0; i < HTTP_HANDLER_THREADS; i++) {
|
||||||
|
m_HttpThreadPool[i]->Join();
|
||||||
|
delete m_HttpThreadPool[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Init(uint32_t argc, const char* argn[], const char* argv[]);
|
bool Init(uint32_t argc, const char* argn[], const char* argv[]);
|
||||||
|
|
||||||
@@ -82,14 +99,20 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
void HandleStartStream(int32_t callbackId, pp::VarArray args);
|
void HandleStartStream(int32_t callbackId, pp::VarArray args);
|
||||||
void HandleStopStream(int32_t callbackId, pp::VarArray args);
|
void HandleStopStream(int32_t callbackId, pp::VarArray args);
|
||||||
void HandleOpenURL(int32_t callbackId, pp::VarArray args);
|
void HandleOpenURL(int32_t callbackId, pp::VarArray args);
|
||||||
|
void HandleSTUN(int32_t callbackId, pp::VarArray args);
|
||||||
void PairCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args);
|
void PairCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args);
|
||||||
|
void STUNCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args);
|
||||||
|
|
||||||
|
bool TryHandleNativeTouchEvent(const pp::InputEvent& event);
|
||||||
bool HandleInputEvent(const pp::InputEvent& event);
|
bool HandleInputEvent(const pp::InputEvent& event);
|
||||||
|
void ReportMouseMovement();
|
||||||
|
|
||||||
void PollGamepads();
|
void PollGamepads();
|
||||||
|
|
||||||
void MouseLockLost();
|
void MouseLockLost();
|
||||||
void DidLockMouse(int32_t result);
|
void DidLockMouse(int32_t result);
|
||||||
|
void LockMouseOrJustCaptureInput();
|
||||||
|
void UnlockMouseOrJustReleaseInput();
|
||||||
|
|
||||||
void OnConnectionStopped(uint32_t unused);
|
void OnConnectionStopped(uint32_t unused);
|
||||||
void OnConnectionStarted(uint32_t error);
|
void OnConnectionStarted(uint32_t error);
|
||||||
@@ -105,15 +128,17 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
static void ProfilerPrintWarning(const char* message);
|
static void ProfilerPrintWarning(const char* message);
|
||||||
|
|
||||||
static void* ConnectionThreadFunc(void* context);
|
static void* ConnectionThreadFunc(void* context);
|
||||||
static void* GamepadThreadFunc(void* context);
|
static void* InputThreadFunc(void* context);
|
||||||
static void* StopThreadFunc(void* context);
|
static void* StopThreadFunc(void* context);
|
||||||
|
|
||||||
static void ClStageStarting(int stage);
|
static void ClStageStarting(int stage);
|
||||||
static void ClStageFailed(int stage, long errorCode);
|
static void ClStageFailed(int stage, int errorCode);
|
||||||
static void ClConnectionStarted(void);
|
static void ClConnectionStarted(void);
|
||||||
static void ClConnectionTerminated(long errorCode);
|
static void ClConnectionTerminated(int errorCode);
|
||||||
static void ClDisplayMessage(const char* message);
|
static void ClDisplayMessage(const char* message);
|
||||||
static void ClDisplayTransientMessage(const char* message);
|
static void ClDisplayTransientMessage(const char* message);
|
||||||
|
static void ClLogMessage(const char* format, ...);
|
||||||
|
static void ClControllerRumble(unsigned short controllerNumber, unsigned short lowFreqMotor, unsigned short highFreqMotor);
|
||||||
|
|
||||||
static Shader CreateProgram(const char* vertexShader, const char* fragmentShader);
|
static Shader CreateProgram(const char* vertexShader, const char* fragmentShader);
|
||||||
static void CreateShader(GLuint program, GLenum type, const char* source, int size);
|
static void CreateShader(GLuint program, GLenum type, const char* source, int size);
|
||||||
@@ -124,20 +149,26 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
void PaintPicture(void);
|
void PaintPicture(void);
|
||||||
bool InitializeRenderingSurface(int width, int height);
|
bool InitializeRenderingSurface(int width, int height);
|
||||||
void DidChangeFocus(bool got_focus);
|
void DidChangeFocus(bool got_focus);
|
||||||
|
void DidChangeView(const pp::View& view);
|
||||||
|
|
||||||
static void VidDecSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags);
|
static int VidDecSetup(int videoFormat, int width, int height, int redrawRate, void* context, int drFlags);
|
||||||
static void VidDecCleanup(void);
|
static void VidDecCleanup(void);
|
||||||
static int VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
static int VidDecSubmitDecodeUnit(PDECODE_UNIT decodeUnit);
|
||||||
|
|
||||||
static void AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig);
|
static int AudDecInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int flags);
|
||||||
static void AudDecCleanup(void);
|
static void AudDecCleanup(void);
|
||||||
static void AudDecDecodeAndPlaySample(char* sampleData, int sampleLength);
|
static void AudDecDecodeAndPlaySample(char* sampleData, int sampleLength);
|
||||||
|
|
||||||
void MakeCert(int32_t callbackId, pp::VarArray args);
|
void MakeCert(int32_t callbackId, pp::VarArray args);
|
||||||
void LoadCert(const char* certStr, const char* keyStr);
|
void LoadCert(const char* certStr, const char* keyStr);
|
||||||
|
|
||||||
|
static void OSSLThreadLock(int mode, int n, const char *, int);
|
||||||
|
static unsigned long OSSLThreadId(void);
|
||||||
void NvHTTPInit(int32_t callbackId, pp::VarArray args);
|
void NvHTTPInit(int32_t callbackId, pp::VarArray args);
|
||||||
void NvHTTPRequest(int32_t, int32_t callbackId, std::string url, bool binaryResponse);
|
void NvHTTPRequest(int32_t, int32_t callbackId, pp::VarArray args);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const PPB_Gamepad* m_GamepadApi;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks;
|
static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks;
|
||||||
@@ -146,11 +177,14 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
|
|
||||||
std::string m_Host;
|
std::string m_Host;
|
||||||
std::string m_AppVersion;
|
std::string m_AppVersion;
|
||||||
|
std::string m_GfeVersion;
|
||||||
|
std::string m_RtspUrl;
|
||||||
|
bool m_MouseLockingFeatureEnabled;
|
||||||
STREAM_CONFIGURATION m_StreamConfig;
|
STREAM_CONFIGURATION m_StreamConfig;
|
||||||
bool m_Running;
|
bool m_Running;
|
||||||
|
|
||||||
pthread_t m_ConnectionThread;
|
pthread_t m_ConnectionThread;
|
||||||
pthread_t m_GamepadThread;
|
pthread_t m_InputThread;
|
||||||
|
|
||||||
pp::Graphics3D m_Graphics3D;
|
pp::Graphics3D m_Graphics3D;
|
||||||
pp::VideoDecoder* m_VideoDecoder;
|
pp::VideoDecoder* m_VideoDecoder;
|
||||||
@@ -161,19 +195,24 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
|||||||
bool m_HasNextPicture;
|
bool m_HasNextPicture;
|
||||||
PP_VideoPicture m_CurrentPicture;
|
PP_VideoPicture m_CurrentPicture;
|
||||||
bool m_IsPainting;
|
bool m_IsPainting;
|
||||||
bool m_RequestIdrFrame;
|
|
||||||
|
pp::Rect m_PluginRect;
|
||||||
|
|
||||||
OpusMSDecoder* m_OpusDecoder;
|
OpusMSDecoder* m_OpusDecoder;
|
||||||
pp::Audio m_AudioPlayer;
|
pp::Audio m_AudioPlayer;
|
||||||
|
|
||||||
double m_LastPadTimestamps[4];
|
double m_LastPadTimestamps[4];
|
||||||
const PPB_Gamepad* m_GamepadApi;
|
|
||||||
pp::CompletionCallbackFactory<MoonlightInstance> m_CallbackFactory;
|
pp::CompletionCallbackFactory<MoonlightInstance> m_CallbackFactory;
|
||||||
bool m_MouseLocked;
|
bool m_MouseLocked;
|
||||||
bool m_WaitingForAllModifiersUp;
|
bool m_WaitingForAllModifiersUp;
|
||||||
float m_AccumulatedTicks;
|
float m_AccumulatedTicks;
|
||||||
|
int32_t m_MouseDeltaX, m_MouseDeltaY;
|
||||||
|
int32_t m_MousePositionX, m_MousePositionY;
|
||||||
|
PP_TimeTicks m_LastTouchUpTime;
|
||||||
|
pp::FloatPoint m_LastTouchUpPoint;
|
||||||
|
|
||||||
pp::SimpleThread openHttpThread;
|
pp::SimpleThread* m_HttpThreadPool[HTTP_HANDLER_THREADS];
|
||||||
|
uint32_t m_HttpThreadPoolSequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MoonlightInstance* g_Instance;
|
extern MoonlightInstance* g_Instance;
|
||||||
|
|||||||
2
opus
3
opus.mk
@@ -55,6 +55,7 @@ OPUS_SOURCE := \
|
|||||||
$(OPUS_DIR)/silk/lin2log.c \
|
$(OPUS_DIR)/silk/lin2log.c \
|
||||||
$(OPUS_DIR)/silk/log2lin.c \
|
$(OPUS_DIR)/silk/log2lin.c \
|
||||||
$(OPUS_DIR)/silk/LPC_analysis_filter.c \
|
$(OPUS_DIR)/silk/LPC_analysis_filter.c \
|
||||||
|
$(OPUS_DIR)/silk/LPC_fit.c \
|
||||||
$(OPUS_DIR)/silk/LPC_inv_pred_gain.c \
|
$(OPUS_DIR)/silk/LPC_inv_pred_gain.c \
|
||||||
$(OPUS_DIR)/silk/LP_variable_cutoff.c \
|
$(OPUS_DIR)/silk/LP_variable_cutoff.c \
|
||||||
$(OPUS_DIR)/silk/NLSF2A.c \
|
$(OPUS_DIR)/silk/NLSF2A.c \
|
||||||
@@ -114,14 +115,12 @@ OPUS_SOURCE := \
|
|||||||
$(OPUS_DIR)/silk/fixed/LTP_scale_ctrl_FIX.c \
|
$(OPUS_DIR)/silk/fixed/LTP_scale_ctrl_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/noise_shape_analysis_FIX.c \
|
$(OPUS_DIR)/silk/fixed/noise_shape_analysis_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/pitch_analysis_core_FIX.c \
|
$(OPUS_DIR)/silk/fixed/pitch_analysis_core_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/prefilter_FIX.c \
|
|
||||||
$(OPUS_DIR)/silk/fixed/process_gains_FIX.c \
|
$(OPUS_DIR)/silk/fixed/process_gains_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/regularize_correlations_FIX.c \
|
$(OPUS_DIR)/silk/fixed/regularize_correlations_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/residual_energy16_FIX.c \
|
$(OPUS_DIR)/silk/fixed/residual_energy16_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/residual_energy_FIX.c \
|
$(OPUS_DIR)/silk/fixed/residual_energy_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/schur64_FIX.c \
|
$(OPUS_DIR)/silk/fixed/schur64_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/schur_FIX.c \
|
$(OPUS_DIR)/silk/fixed/schur_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/solve_LS_FIX.c \
|
|
||||||
$(OPUS_DIR)/silk/fixed/vector_ops_FIX.c \
|
$(OPUS_DIR)/silk/fixed/vector_ops_FIX.c \
|
||||||
$(OPUS_DIR)/silk/fixed/warped_autocorrelation_FIX.c \
|
$(OPUS_DIR)/silk/fixed/warped_autocorrelation_FIX.c \
|
||||||
$(OPUS_DIR)/src/analysis.c \
|
$(OPUS_DIR)/src/analysis.c \
|
||||||
|
|||||||
134
ports/include/curl/curl.h
Executable file → Normal file
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -423,7 +423,9 @@ typedef enum {
|
|||||||
CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
|
CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
|
||||||
CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
|
CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
|
||||||
CURLE_FTP_CANT_GET_HOST, /* 15 */
|
CURLE_FTP_CANT_GET_HOST, /* 15 */
|
||||||
CURLE_OBSOLETE16, /* 16 - NOT USED */
|
CURLE_HTTP2, /* 16 - A problem in the http2 framing layer.
|
||||||
|
[was obsoleted in August 2007 for 7.17.0,
|
||||||
|
reused in July 2014 for 7.38.0] */
|
||||||
CURLE_FTP_COULDNT_SET_TYPE, /* 17 */
|
CURLE_FTP_COULDNT_SET_TYPE, /* 17 */
|
||||||
CURLE_PARTIAL_FILE, /* 18 */
|
CURLE_PARTIAL_FILE, /* 18 */
|
||||||
CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
|
CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
|
||||||
@@ -519,13 +521,19 @@ typedef enum {
|
|||||||
CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
|
CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
|
||||||
CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
|
CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
|
||||||
session will be queued */
|
session will be queued */
|
||||||
|
CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
|
||||||
|
match */
|
||||||
|
CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */
|
||||||
CURL_LAST /* never use! */
|
CURL_LAST /* never use! */
|
||||||
} CURLcode;
|
} CURLcode;
|
||||||
|
|
||||||
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
|
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
|
||||||
the obsolete stuff removed! */
|
the obsolete stuff removed! */
|
||||||
|
|
||||||
/* Previously obsoletes error codes re-used in 7.24.0 */
|
/* Previously obsolete error code re-used in 7.38.0 */
|
||||||
|
#define CURLE_OBSOLETE16 CURLE_HTTP2
|
||||||
|
|
||||||
|
/* Previously obsolete error codes re-used in 7.24.0 */
|
||||||
#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
|
#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
|
||||||
#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
|
#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
|
||||||
|
|
||||||
@@ -579,6 +587,16 @@ typedef enum {
|
|||||||
make programs break */
|
make programs break */
|
||||||
#define CURLE_ALREADY_COMPLETE 99999
|
#define CURLE_ALREADY_COMPLETE 99999
|
||||||
|
|
||||||
|
/* Provide defines for really old option names */
|
||||||
|
#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */
|
||||||
|
#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */
|
||||||
|
#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA
|
||||||
|
|
||||||
|
/* Since long deprecated options with no code in the lib that does anything
|
||||||
|
with them. */
|
||||||
|
#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
|
||||||
|
#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
|
||||||
|
|
||||||
#endif /*!CURL_NO_OLDIES*/
|
#endif /*!CURL_NO_OLDIES*/
|
||||||
|
|
||||||
/* This prototype applies to all conversion callbacks */
|
/* This prototype applies to all conversion callbacks */
|
||||||
@@ -609,7 +627,8 @@ typedef enum {
|
|||||||
* CURLAUTH_NONE - No HTTP authentication
|
* CURLAUTH_NONE - No HTTP authentication
|
||||||
* CURLAUTH_BASIC - HTTP Basic authentication (default)
|
* CURLAUTH_BASIC - HTTP Basic authentication (default)
|
||||||
* CURLAUTH_DIGEST - HTTP Digest authentication
|
* CURLAUTH_DIGEST - HTTP Digest authentication
|
||||||
* CURLAUTH_GSSNEGOTIATE - HTTP GSS-Negotiate authentication
|
* CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication
|
||||||
|
* CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
|
||||||
* CURLAUTH_NTLM - HTTP NTLM authentication
|
* CURLAUTH_NTLM - HTTP NTLM authentication
|
||||||
* CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
|
* CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
|
||||||
* CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
|
* CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
|
||||||
@@ -622,7 +641,9 @@ typedef enum {
|
|||||||
#define CURLAUTH_NONE ((unsigned long)0)
|
#define CURLAUTH_NONE ((unsigned long)0)
|
||||||
#define CURLAUTH_BASIC (((unsigned long)1)<<0)
|
#define CURLAUTH_BASIC (((unsigned long)1)<<0)
|
||||||
#define CURLAUTH_DIGEST (((unsigned long)1)<<1)
|
#define CURLAUTH_DIGEST (((unsigned long)1)<<1)
|
||||||
#define CURLAUTH_GSSNEGOTIATE (((unsigned long)1)<<2)
|
#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2)
|
||||||
|
/* Deprecated since the advent of CURLAUTH_NEGOTIATE */
|
||||||
|
#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
|
||||||
#define CURLAUTH_NTLM (((unsigned long)1)<<3)
|
#define CURLAUTH_NTLM (((unsigned long)1)<<3)
|
||||||
#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
|
#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
|
||||||
#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
|
#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
|
||||||
@@ -704,6 +725,10 @@ typedef enum {
|
|||||||
servers, a user can this way allow the vulnerability back. */
|
servers, a user can this way allow the vulnerability back. */
|
||||||
#define CURLSSLOPT_ALLOW_BEAST (1<<0)
|
#define CURLSSLOPT_ALLOW_BEAST (1<<0)
|
||||||
|
|
||||||
|
/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
|
||||||
|
SSL backends where such behavior is present. */
|
||||||
|
#define CURLSSLOPT_NO_REVOKE (1<<1)
|
||||||
|
|
||||||
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
|
#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
|
||||||
the obsolete stuff removed! */
|
the obsolete stuff removed! */
|
||||||
|
|
||||||
@@ -785,6 +810,8 @@ typedef enum {
|
|||||||
#define CURLPROTO_RTMPS (1<<23)
|
#define CURLPROTO_RTMPS (1<<23)
|
||||||
#define CURLPROTO_RTMPTS (1<<24)
|
#define CURLPROTO_RTMPTS (1<<24)
|
||||||
#define CURLPROTO_GOPHER (1<<25)
|
#define CURLPROTO_GOPHER (1<<25)
|
||||||
|
#define CURLPROTO_SMB (1<<26)
|
||||||
|
#define CURLPROTO_SMBS (1<<27)
|
||||||
#define CURLPROTO_ALL (~0) /* enable everything */
|
#define CURLPROTO_ALL (~0) /* enable everything */
|
||||||
|
|
||||||
/* long may be 32 or 64 bits, but we should never depend on anything else
|
/* long may be 32 or 64 bits, but we should never depend on anything else
|
||||||
@@ -820,10 +847,10 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* This is the FILE * or void * the regular output should be written to. */
|
/* This is the FILE * or void * the regular output should be written to. */
|
||||||
CINIT(FILE, OBJECTPOINT, 1),
|
CINIT(WRITEDATA, OBJECTPOINT, 1),
|
||||||
|
|
||||||
/* The full URL to get/put */
|
/* The full URL to get/put */
|
||||||
CINIT(URL, OBJECTPOINT, 2),
|
CINIT(URL, OBJECTPOINT, 2),
|
||||||
|
|
||||||
/* Port number to connect to, if other than default. */
|
/* Port number to connect to, if other than default. */
|
||||||
CINIT(PORT, LONG, 3),
|
CINIT(PORT, LONG, 3),
|
||||||
@@ -843,7 +870,7 @@ typedef enum {
|
|||||||
/* not used */
|
/* not used */
|
||||||
|
|
||||||
/* Specified file stream to upload from (use as input): */
|
/* Specified file stream to upload from (use as input): */
|
||||||
CINIT(INFILE, OBJECTPOINT, 9),
|
CINIT(READDATA, OBJECTPOINT, 9),
|
||||||
|
|
||||||
/* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
|
/* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
|
||||||
* bytes big. If this is not used, error messages go to stderr instead: */
|
* bytes big. If this is not used, error messages go to stderr instead: */
|
||||||
@@ -928,7 +955,7 @@ typedef enum {
|
|||||||
|
|
||||||
/* send FILE * or void * to store headers to, if you use a callback it
|
/* send FILE * or void * to store headers to, if you use a callback it
|
||||||
is simply passed to the callback unmodified */
|
is simply passed to the callback unmodified */
|
||||||
CINIT(WRITEHEADER, OBJECTPOINT, 29),
|
CINIT(HEADERDATA, OBJECTPOINT, 29),
|
||||||
|
|
||||||
/* point to a file to read the initial cookies from, also enables
|
/* point to a file to read the initial cookies from, also enables
|
||||||
"cookie awareness" */
|
"cookie awareness" */
|
||||||
@@ -961,13 +988,13 @@ typedef enum {
|
|||||||
/* send linked-list of post-transfer QUOTE commands */
|
/* send linked-list of post-transfer QUOTE commands */
|
||||||
CINIT(POSTQUOTE, OBJECTPOINT, 39),
|
CINIT(POSTQUOTE, OBJECTPOINT, 39),
|
||||||
|
|
||||||
CINIT(WRITEINFO, OBJECTPOINT, 40), /* DEPRECATED, do not use! */
|
CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */
|
||||||
|
|
||||||
CINIT(VERBOSE, LONG, 41), /* talk a lot */
|
CINIT(VERBOSE, LONG, 41), /* talk a lot */
|
||||||
CINIT(HEADER, LONG, 42), /* throw the header out too */
|
CINIT(HEADER, LONG, 42), /* throw the header out too */
|
||||||
CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
|
CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
|
||||||
CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
|
CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
|
||||||
CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */
|
CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */
|
||||||
CINIT(UPLOAD, LONG, 46), /* this is an upload */
|
CINIT(UPLOAD, LONG, 46), /* this is an upload */
|
||||||
CINIT(POST, LONG, 47), /* HTTP POST method */
|
CINIT(POST, LONG, 47), /* HTTP POST method */
|
||||||
CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */
|
CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */
|
||||||
@@ -1040,7 +1067,7 @@ typedef enum {
|
|||||||
/* Max amount of cached alive connections */
|
/* Max amount of cached alive connections */
|
||||||
CINIT(MAXCONNECTS, LONG, 71),
|
CINIT(MAXCONNECTS, LONG, 71),
|
||||||
|
|
||||||
CINIT(CLOSEPOLICY, LONG, 72), /* DEPRECATED, do not use! */
|
CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */
|
||||||
|
|
||||||
/* 73 = OBSOLETE */
|
/* 73 = OBSOLETE */
|
||||||
|
|
||||||
@@ -1593,6 +1620,31 @@ typedef enum {
|
|||||||
/* Pass in a bitmask of "header options" */
|
/* Pass in a bitmask of "header options" */
|
||||||
CINIT(HEADEROPT, LONG, 229),
|
CINIT(HEADEROPT, LONG, 229),
|
||||||
|
|
||||||
|
/* The public key in DER form used to validate the peer public key
|
||||||
|
this option is used only if SSL_VERIFYPEER is true */
|
||||||
|
CINIT(PINNEDPUBLICKEY, OBJECTPOINT, 230),
|
||||||
|
|
||||||
|
/* Path to Unix domain socket */
|
||||||
|
CINIT(UNIX_SOCKET_PATH, OBJECTPOINT, 231),
|
||||||
|
|
||||||
|
/* Set if we should verify the certificate status. */
|
||||||
|
CINIT(SSL_VERIFYSTATUS, LONG, 232),
|
||||||
|
|
||||||
|
/* Set if we should enable TLS false start. */
|
||||||
|
CINIT(SSL_FALSESTART, LONG, 233),
|
||||||
|
|
||||||
|
/* Do not squash dot-dot sequences */
|
||||||
|
CINIT(PATH_AS_IS, LONG, 234),
|
||||||
|
|
||||||
|
/* Proxy Service Name */
|
||||||
|
CINIT(PROXY_SERVICE_NAME, OBJECTPOINT, 235),
|
||||||
|
|
||||||
|
/* Service Name */
|
||||||
|
CINIT(SERVICE_NAME, OBJECTPOINT, 236),
|
||||||
|
|
||||||
|
/* Wait/don't wait for pipe/mutex to clarify */
|
||||||
|
CINIT(PIPEWAIT, LONG, 237),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
@@ -1629,13 +1681,10 @@ typedef enum {
|
|||||||
option might be handy to force libcurl to use a specific IP version. */
|
option might be handy to force libcurl to use a specific IP version. */
|
||||||
#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
|
#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
|
||||||
versions that your system allows */
|
versions that your system allows */
|
||||||
#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */
|
#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */
|
||||||
#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */
|
#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */
|
||||||
|
|
||||||
/* three convenient "aliases" that follow the name scheme better */
|
/* three convenient "aliases" that follow the name scheme better */
|
||||||
#define CURLOPT_WRITEDATA CURLOPT_FILE
|
|
||||||
#define CURLOPT_READDATA CURLOPT_INFILE
|
|
||||||
#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
|
|
||||||
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
|
||||||
|
|
||||||
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
|
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
|
||||||
@@ -1650,6 +1699,11 @@ enum {
|
|||||||
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
|
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Convenience definition simple because the name of the version is HTTP/2 and
|
||||||
|
not 2.0. The 2_0 version of the enum name was set while the version was
|
||||||
|
still planned to be 2.0 and we stick to it for compatibility. */
|
||||||
|
#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public API enums for RTSP requests
|
* Public API enums for RTSP requests
|
||||||
*/
|
*/
|
||||||
@@ -2013,12 +2067,13 @@ typedef enum {
|
|||||||
CURLSSLBACKEND_OPENSSL = 1,
|
CURLSSLBACKEND_OPENSSL = 1,
|
||||||
CURLSSLBACKEND_GNUTLS = 2,
|
CURLSSLBACKEND_GNUTLS = 2,
|
||||||
CURLSSLBACKEND_NSS = 3,
|
CURLSSLBACKEND_NSS = 3,
|
||||||
CURLSSLBACKEND_QSOSSL = 4,
|
CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */
|
||||||
CURLSSLBACKEND_GSKIT = 5,
|
CURLSSLBACKEND_GSKIT = 5,
|
||||||
CURLSSLBACKEND_POLARSSL = 6,
|
CURLSSLBACKEND_POLARSSL = 6,
|
||||||
CURLSSLBACKEND_CYASSL = 7,
|
CURLSSLBACKEND_CYASSL = 7,
|
||||||
CURLSSLBACKEND_SCHANNEL = 8,
|
CURLSSLBACKEND_SCHANNEL = 8,
|
||||||
CURLSSLBACKEND_DARWINSSL = 9
|
CURLSSLBACKEND_DARWINSSL = 9,
|
||||||
|
CURLSSLBACKEND_AXTLS = 10
|
||||||
} curl_sslbackend;
|
} curl_sslbackend;
|
||||||
|
|
||||||
/* Information about the SSL library used and the respective internal SSL
|
/* Information about the SSL library used and the respective internal SSL
|
||||||
@@ -2219,23 +2274,30 @@ typedef struct {
|
|||||||
|
|
||||||
} curl_version_info_data;
|
} curl_version_info_data;
|
||||||
|
|
||||||
#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
|
#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
|
||||||
#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */
|
#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported
|
||||||
#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
|
(deprecated) */
|
||||||
#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
|
#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
|
||||||
#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
|
#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
|
||||||
#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
|
#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
|
||||||
#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */
|
#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported
|
||||||
#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */
|
(deprecated) */
|
||||||
#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */
|
#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */
|
||||||
#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */
|
#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */
|
||||||
#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */
|
#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */
|
||||||
#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */
|
#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */
|
||||||
#define CURL_VERSION_CONV (1<<12) /* character conversions supported */
|
#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are
|
||||||
#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
|
supported */
|
||||||
#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
|
#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */
|
||||||
#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegating to winbind helper */
|
#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */
|
||||||
#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
|
#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */
|
||||||
|
#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
|
||||||
|
#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper
|
||||||
|
is suported */
|
||||||
|
#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
|
||||||
|
#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */
|
||||||
|
#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */
|
||||||
|
#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NAME curl_version_info()
|
* NAME curl_version_info()
|
||||||
|
|||||||
0
ports/include/curl/curlbuild.h
Executable file → Normal file
0
ports/include/curl/curlrules.h
Executable file → Normal file
20
ports/include/curl/curlver.h
Executable file → Normal file
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -26,16 +26,16 @@
|
|||||||
a script at release-time. This was made its own header file in 7.11.2 */
|
a script at release-time. This was made its own header file in 7.11.2 */
|
||||||
|
|
||||||
/* This is the global package copyright */
|
/* This is the global package copyright */
|
||||||
#define LIBCURL_COPYRIGHT "1996 - 2014 Daniel Stenberg, <daniel@haxx.se>."
|
#define LIBCURL_COPYRIGHT "1996 - 2015 Daniel Stenberg, <daniel@haxx.se>."
|
||||||
|
|
||||||
/* This is the version number of the libcurl package from which this header
|
/* This is the version number of the libcurl package from which this header
|
||||||
file origins: */
|
file origins: */
|
||||||
#define LIBCURL_VERSION "7.37.0"
|
#define LIBCURL_VERSION "7.44.0"
|
||||||
|
|
||||||
/* The numeric version number is also available "in parts" by using these
|
/* The numeric version number is also available "in parts" by using these
|
||||||
defines: */
|
defines: */
|
||||||
#define LIBCURL_VERSION_MAJOR 7
|
#define LIBCURL_VERSION_MAJOR 7
|
||||||
#define LIBCURL_VERSION_MINOR 37
|
#define LIBCURL_VERSION_MINOR 44
|
||||||
#define LIBCURL_VERSION_PATCH 0
|
#define LIBCURL_VERSION_PATCH 0
|
||||||
|
|
||||||
/* This is the numeric version of the libcurl version number, meant for easier
|
/* This is the numeric version of the libcurl version number, meant for easier
|
||||||
@@ -52,8 +52,12 @@
|
|||||||
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
|
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
|
||||||
and it is always a greater number in a more recent release. It makes
|
and it is always a greater number in a more recent release. It makes
|
||||||
comparisons with greater than and less than work.
|
comparisons with greater than and less than work.
|
||||||
|
|
||||||
|
Note: This define is the full hex number and _does not_ use the
|
||||||
|
CURL_VERSION_BITS() macro since curl's own configure script greps for it
|
||||||
|
and needs it to contain the full number.
|
||||||
*/
|
*/
|
||||||
#define LIBCURL_VERSION_NUM 0x072500
|
#define LIBCURL_VERSION_NUM 0x072c00
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the date and time when the full source package was created. The
|
* This is the date and time when the full source package was created. The
|
||||||
@@ -64,6 +68,10 @@
|
|||||||
*
|
*
|
||||||
* "Mon Feb 12 11:35:33 UTC 2007"
|
* "Mon Feb 12 11:35:33 UTC 2007"
|
||||||
*/
|
*/
|
||||||
#define LIBCURL_TIMESTAMP "Wed May 21 05:58:26 UTC 2014"
|
#define LIBCURL_TIMESTAMP "Wed Aug 12 06:10:30 UTC 2015"
|
||||||
|
|
||||||
|
#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z)
|
||||||
|
#define CURL_AT_LEAST_VERSION(x,y,z) \
|
||||||
|
(LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
|
||||||
|
|
||||||
#endif /* __CURL_CURLVER_H */
|
#endif /* __CURL_CURLVER_H */
|
||||||
|
|||||||
0
ports/include/curl/easy.h
Executable file → Normal file
9
ports/include/curl/mprintf.h
Executable file → Normal file
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -57,15 +57,8 @@ CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
|
|||||||
# undef vaprintf
|
# undef vaprintf
|
||||||
# define printf curl_mprintf
|
# define printf curl_mprintf
|
||||||
# define fprintf curl_mfprintf
|
# define fprintf curl_mfprintf
|
||||||
#ifdef CURLDEBUG
|
|
||||||
/* When built with CURLDEBUG we define away the sprintf functions since we
|
|
||||||
don't want internal code to be using them */
|
|
||||||
# define sprintf sprintf_was_used
|
|
||||||
# define vsprintf vsprintf_was_used
|
|
||||||
#else
|
|
||||||
# define sprintf curl_msprintf
|
# define sprintf curl_msprintf
|
||||||
# define vsprintf curl_mvsprintf
|
# define vsprintf curl_mvsprintf
|
||||||
#endif
|
|
||||||
# define snprintf curl_msnprintf
|
# define snprintf curl_msnprintf
|
||||||
# define vprintf curl_mvprintf
|
# define vprintf curl_mvprintf
|
||||||
# define vfprintf curl_mvfprintf
|
# define vfprintf curl_mvfprintf
|
||||||
|
|||||||
38
ports/include/curl/multi.h
Executable file → Normal file
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -74,6 +74,11 @@ typedef enum {
|
|||||||
curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
|
curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
|
||||||
#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
|
#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
|
||||||
|
|
||||||
|
/* bitmask bits for CURLMOPT_PIPELINING */
|
||||||
|
#define CURLPIPE_NOTHING 0L
|
||||||
|
#define CURLPIPE_HTTP1 1L
|
||||||
|
#define CURLPIPE_MULTIPLEX 2L
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CURLMSG_NONE, /* first, not used */
|
CURLMSG_NONE, /* first, not used */
|
||||||
CURLMSG_DONE, /* This easy handle has completed. 'result' contains
|
CURLMSG_DONE, /* This easy handle has completed. 'result' contains
|
||||||
@@ -365,6 +370,12 @@ typedef enum {
|
|||||||
/* maximum number of open connections in total */
|
/* maximum number of open connections in total */
|
||||||
CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
|
CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
|
||||||
|
|
||||||
|
/* This is the server push callback function pointer */
|
||||||
|
CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14),
|
||||||
|
|
||||||
|
/* This is the argument passed to the server push callback */
|
||||||
|
CINIT(PUSHDATA, OBJECTPOINT, 15),
|
||||||
|
|
||||||
CURLMOPT_LASTENTRY /* the last unused */
|
CURLMOPT_LASTENTRY /* the last unused */
|
||||||
} CURLMoption;
|
} CURLMoption;
|
||||||
|
|
||||||
@@ -392,6 +403,31 @@ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
|||||||
CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
|
CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
|
||||||
curl_socket_t sockfd, void *sockp);
|
curl_socket_t sockfd, void *sockp);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Name: curl_push_callback
|
||||||
|
*
|
||||||
|
* Desc: This callback gets called when a new stream is being pushed by the
|
||||||
|
* server. It approves or denies the new stream.
|
||||||
|
*
|
||||||
|
* Returns: CURL_PUSH_OK or CURL_PUSH_DENY.
|
||||||
|
*/
|
||||||
|
#define CURL_PUSH_OK 0
|
||||||
|
#define CURL_PUSH_DENY 1
|
||||||
|
|
||||||
|
struct curl_pushheaders; /* forward declaration only */
|
||||||
|
|
||||||
|
CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
|
||||||
|
size_t num);
|
||||||
|
CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
|
||||||
|
const char *name);
|
||||||
|
|
||||||
|
typedef int (*curl_push_callback)(CURL *parent,
|
||||||
|
CURL *easy,
|
||||||
|
size_t num_headers,
|
||||||
|
struct curl_pushheaders *headers,
|
||||||
|
void *userp);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* end of extern "C" */
|
} /* end of extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
0
ports/include/curl/stdcheaders.h
Executable file → Normal file
6
ports/include/curl/typecheck-gcc.h
Executable file → Normal file
@@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@@ -270,6 +270,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
|
|||||||
(option) == CURLOPT_DNS_LOCAL_IP4 || \
|
(option) == CURLOPT_DNS_LOCAL_IP4 || \
|
||||||
(option) == CURLOPT_DNS_LOCAL_IP6 || \
|
(option) == CURLOPT_DNS_LOCAL_IP6 || \
|
||||||
(option) == CURLOPT_LOGIN_OPTIONS || \
|
(option) == CURLOPT_LOGIN_OPTIONS || \
|
||||||
|
(option) == CURLOPT_PROXY_SERVICE_NAME || \
|
||||||
|
(option) == CURLOPT_SERVICE_NAME || \
|
||||||
0)
|
0)
|
||||||
|
|
||||||
/* evaluates to true if option takes a curl_write_callback argument */
|
/* evaluates to true if option takes a curl_write_callback argument */
|
||||||
@@ -291,7 +293,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
|
|||||||
(option) == CURLOPT_SOCKOPTDATA || \
|
(option) == CURLOPT_SOCKOPTDATA || \
|
||||||
(option) == CURLOPT_OPENSOCKETDATA || \
|
(option) == CURLOPT_OPENSOCKETDATA || \
|
||||||
(option) == CURLOPT_PROGRESSDATA || \
|
(option) == CURLOPT_PROGRESSDATA || \
|
||||||
(option) == CURLOPT_WRITEHEADER || \
|
(option) == CURLOPT_HEADERDATA || \
|
||||||
(option) == CURLOPT_DEBUGDATA || \
|
(option) == CURLOPT_DEBUGDATA || \
|
||||||
(option) == CURLOPT_SSL_CTX_DATA || \
|
(option) == CURLOPT_SSL_CTX_DATA || \
|
||||||
(option) == CURLOPT_SEEKDATA || \
|
(option) == CURLOPT_SEEKDATA || \
|
||||||
|
|||||||