mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-08-10 00:52:16 +00:00
Compare commits
647 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6000b85b1a | ||
|
|
d661568536 | ||
|
|
c4e3687c01 | ||
|
|
a6b8371178 | ||
|
|
f546ee8551 | ||
|
|
db28239939 | ||
|
|
9f87401173 | ||
|
|
4100f790ee | ||
|
|
a4acaf15b0 | ||
|
|
0de52efdb1 | ||
|
|
1d242aed7c | ||
|
|
4d3c9b0be8 | ||
|
|
8164c09ea0 | ||
|
|
b464902f25 | ||
|
|
844f041a58 | ||
|
|
de628e843e | ||
|
|
de6779ed83 | ||
|
|
2afa3a4390 | ||
|
|
094ab4eb1a | ||
|
|
c184f16e28 | ||
|
|
15aca474eb | ||
|
|
d963bd1daa | ||
|
|
d38392aea0 | ||
|
|
b7ef109d95 | ||
|
|
dc8bda0e1b | ||
|
|
7cc5e1345c | ||
|
|
49147694de | ||
|
|
58a71bf3e7 | ||
|
|
5ac84fd03f | ||
|
|
1439c8d951 | ||
|
|
ce9934ca52 | ||
|
|
7451c1bd17 | ||
|
|
7340f7660b | ||
|
|
a9af8472df | ||
|
|
b5fa9bb1be | ||
|
|
f850b037bc | ||
|
|
da3c39e9e3 | ||
|
|
7d4df19cdc | ||
|
|
d19c883067 | ||
|
|
42eda48ce4 | ||
|
|
fd0dc9ab8e | ||
|
|
1415c8b200 | ||
|
|
8ba3c073e7 | ||
|
|
92f1313993 | ||
|
|
2b3c514aad | ||
|
|
819501c4e7 | ||
|
|
3b2226c4ea | ||
|
|
00405892cb | ||
|
|
3cd3d261e9 | ||
|
|
4f07672cfa | ||
|
|
25e21ee807 | ||
|
|
270d4ddffe | ||
|
|
46dede3381 | ||
|
|
7019756fa1 | ||
|
|
a1d8cc2296 | ||
|
|
c61b31e8a6 | ||
|
|
802e5c79fa | ||
|
|
6b64149591 | ||
|
|
8fc8884dbc | ||
|
|
2b76111e51 | ||
|
|
54221ae938 | ||
|
|
f07171315f | ||
|
|
f4074341a5 | ||
|
|
9c4763af75 | ||
|
|
6dc10a4d60 | ||
|
|
4b332d6fa0 | ||
|
|
12a361a3d9 | ||
|
|
840013ec78 | ||
|
|
e45452b9bc | ||
|
|
8509260194 | ||
|
|
2a13697fef | ||
|
|
bd51a7d5fa | ||
|
|
1cf0360520 | ||
|
|
4a0d632c6e | ||
|
|
d336de68a2 | ||
|
|
1175a3184e | ||
|
|
dde56c2bb7 | ||
|
|
7da652e299 | ||
|
|
3663e35ecf | ||
|
|
e78ec5c2ce | ||
|
|
70ae7a2fa9 | ||
|
|
651d75fce7 | ||
|
|
c3dfcc1f11 | ||
|
|
a02d314dde | ||
|
|
b5fd69a9ed | ||
|
|
2d969c2ccc | ||
|
|
211b25848f | ||
|
|
d051b58190 | ||
|
|
ab0a6b5fa6 | ||
|
|
0c827690ec | ||
|
|
f5d7cf7692 | ||
|
|
dd73f45175 | ||
|
|
e86207606a | ||
|
|
ca21e6a8ac | ||
|
|
9990b9b04b | ||
|
|
341bc98730 | ||
|
|
1a1cf20152 | ||
|
|
7a5890469c | ||
|
|
65c4f01998 | ||
|
|
676b5559ec | ||
|
|
e9b46201fd | ||
|
|
9b4fc8a270 | ||
|
|
7cb0286414 | ||
|
|
3b41888c66 | ||
|
|
4a65d2cafc | ||
|
|
34f1e89366 | ||
|
|
91cf3bcdcc | ||
|
|
e7ec6050d9 | ||
|
|
0f3eaf0f84 | ||
|
|
c75efd3999 | ||
|
|
f2934c620b | ||
|
|
4f6b001483 | ||
|
|
de3c37969f | ||
|
|
c719ddfc31 | ||
|
|
a5e56cf47d | ||
|
|
84fd2c5766 | ||
|
|
68ba1db24a | ||
|
|
ca00949851 | ||
|
|
88925c705f | ||
|
|
c2752262e5 | ||
|
|
496e51d93a | ||
|
|
6c04065ba7 | ||
|
|
fff419a7ff | ||
|
|
a3e3da3136 | ||
|
|
49bfd2ba1f | ||
|
|
93aebf461a | ||
|
|
c409022df5 | ||
|
|
c4441db606 | ||
|
|
0d0496adf3 | ||
|
|
ca6f02c953 | ||
|
|
8b86abfceb | ||
|
|
5135c16bda | ||
|
|
e6d6d47be1 | ||
|
|
639af4f08a | ||
|
|
12bf5cffc5 | ||
|
|
6741997e59 | ||
|
|
369a941c48 | ||
|
|
2a69385aed | ||
|
|
31f7faa6a5 | ||
|
|
dc4393a583 | ||
|
|
5eb3e7c75f | ||
|
|
6858f9c8d4 | ||
|
|
af342c8cc9 | ||
|
|
4e4a5c8df8 | ||
|
|
cc2d982ceb | ||
|
|
e2bef750b4 | ||
|
|
ffdcf0fea8 | ||
|
|
2ea414d1d4 | ||
|
|
c4977b5393 | ||
|
|
13c2dce3f1 | ||
|
|
b0a02a5985 | ||
|
|
b0df4eabd1 | ||
|
|
ceb7f5f41a | ||
|
|
aa46b8e293 | ||
|
|
63a83cdf7a | ||
|
|
bd033f9e15 | ||
|
|
62ca9c31a0 | ||
|
|
e8ef708034 | ||
|
|
ec450be8b5 | ||
|
|
d4df041210 | ||
|
|
ced0029abc | ||
|
|
a9cf0ebf18 | ||
|
|
3d6611fd50 | ||
|
|
74736c6b76 | ||
|
|
0e0b2ce366 | ||
|
|
3b49deac25 | ||
|
|
734400dc77 | ||
|
|
ef9abf2f15 | ||
|
|
b286c06144 | ||
|
|
521335c387 | ||
|
|
780339d91b | ||
|
|
b332633b07 | ||
|
|
4cd1014bac | ||
|
|
7a1e5f43d9 | ||
|
|
c4054c75a7 | ||
|
|
f36d81954b | ||
|
|
eacae3954e | ||
|
|
56cf3e4ede | ||
|
|
293ee266af | ||
|
|
536df759ae | ||
|
|
4bdf8375cc | ||
|
|
a6921fffad | ||
|
|
1ad0c93ad8 | ||
|
|
97f333c970 | ||
|
|
b854807d40 | ||
|
|
a9b9d1bd09 | ||
|
|
0044ec1d52 | ||
|
|
9c976a23de | ||
|
|
9930880ee6 | ||
|
|
82e1b61a31 | ||
|
|
5bb197ccfc | ||
|
|
20c0426ace | ||
|
|
0a9cc511ed | ||
|
|
2a7af03f9a | ||
|
|
7910ac78a5 | ||
|
|
67762aa445 | ||
|
|
7f22774e08 | ||
|
|
cbafe09396 | ||
|
|
615f7e5875 | ||
|
|
3f309832f7 | ||
|
|
719f4cef59 | ||
|
|
da582198db | ||
|
|
04a2ecaff4 | ||
|
|
3b8b4653e9 | ||
|
|
ea27955b16 | ||
|
|
e223ba53f9 | ||
|
|
907d0bfcd5 | ||
|
|
a014391ae7 | ||
|
|
84584c950b | ||
|
|
f1d82a7d09 | ||
|
|
01155ef4a3 | ||
|
|
88cf616a48 | ||
|
|
b3cdadca86 | ||
|
|
3bd9f6b710 | ||
|
|
e28cc5e645 | ||
|
|
045970bcc5 | ||
|
|
6fca2c593c | ||
|
|
e61bbe87b4 | ||
|
|
80ebc9982e | ||
|
|
9a2689692a | ||
|
|
a31c6c4cd0 | ||
|
|
1f79f4ed12 | ||
|
|
6da0483951 | ||
|
|
3abb199697 | ||
|
|
4c7afc05c7 | ||
|
|
222e53781d | ||
|
|
8d4bd87ad2 | ||
|
|
861331be1c | ||
|
|
2fa2afed56 | ||
|
|
5e910b5fab | ||
|
|
1520cb7bf9 | ||
|
|
4b658cd86b | ||
|
|
f6311ceb3f | ||
|
|
9b2321a722 | ||
|
|
1e91356155 | ||
|
|
fb7a3a0758 | ||
|
|
c2d4ffdaed | ||
|
|
c5e6b84e3d | ||
|
|
68f35f6ab1 | ||
|
|
2b450839a1 | ||
|
|
df3e7c5ca1 | ||
|
|
a4fa42fa96 | ||
|
|
d6183430ef | ||
|
|
f54a32feac | ||
|
|
37edcb1b55 | ||
|
|
320b691086 | ||
|
|
5163ec93b4 | ||
|
|
2be7790415 | ||
|
|
27d2735454 | ||
|
|
361e5f7ea7 | ||
|
|
4a483078ad | ||
|
|
4dff0c8384 | ||
|
|
543254691b | ||
|
|
96205dc48d | ||
|
|
ec5ea7cffb | ||
|
|
8bb7a63479 | ||
|
|
95302485a0 | ||
|
|
7a1347c1f5 | ||
|
|
a78ad20142 | ||
|
|
9dd6576b26 | ||
|
|
cf8a843b03 | ||
|
|
8b423315d0 | ||
|
|
7417430659 | ||
|
|
a494bfa1e9 | ||
|
|
e239751f50 | ||
|
|
91465ed257 | ||
|
|
830fa6567b | ||
|
|
f347089312 | ||
|
|
a577f76d71 | ||
|
|
89f05711e0 | ||
|
|
b19803564c | ||
|
|
a9988cb346 | ||
|
|
b288993b86 | ||
|
|
37e608a889 | ||
|
|
067214a9f9 | ||
|
|
b5896c8f26 | ||
|
|
9f4ad530ca | ||
|
|
c6d489da11 | ||
|
|
c3d498e30c | ||
|
|
bd8ba66023 | ||
|
|
cf859b7c13 | ||
|
|
3b2c70422a | ||
|
|
a9ebdf6785 | ||
|
|
8164b514e1 | ||
|
|
398bf9819e | ||
|
|
59959d6397 | ||
|
|
cbbd813c5a | ||
|
|
f4344ade53 | ||
|
|
8e1b718d7f | ||
|
|
ed62a1f93d | ||
|
|
592cb002bd | ||
|
|
ebc581e165 | ||
|
|
c7a3f7f46e | ||
|
|
41df9c658b | ||
|
|
4bada2d9f6 | ||
|
|
83da80f631 | ||
|
|
2bcb713b82 | ||
|
|
e5239583b5 | ||
|
|
4126a1a98e | ||
|
|
abf2a5ea4e | ||
|
|
a9bbadf8ad | ||
|
|
38dcdcba2f | ||
|
|
4a50fcafd8 | ||
|
|
67f35dfc5f | ||
|
|
de9136c61e | ||
|
|
dd7736e806 | ||
|
|
720f44c03b | ||
|
|
3981ca0840 | ||
|
|
9f707f9015 | ||
|
|
1b6bf8fa34 | ||
|
|
41e6344995 | ||
|
|
5993deadb2 | ||
|
|
7306a3468d | ||
|
|
1513880f63 | ||
|
|
41044ab97f | ||
|
|
1b392e3921 | ||
|
|
870b6e2675 | ||
|
|
ac7fcfe056 | ||
|
|
55ac123d03 | ||
|
|
c748980f58 | ||
|
|
d1a41ad8fe | ||
|
|
db6e2a57ad | ||
|
|
f2c53a52c2 | ||
|
|
adfb3619c3 | ||
|
|
8781fbcc20 | ||
|
|
2c0873332c | ||
|
|
a2c45f8de0 | ||
|
|
cefcaed358 | ||
|
|
6ba4b56f32 | ||
|
|
bfda8558ea | ||
|
|
cc5c1a9b90 | ||
|
|
c5d782dac5 | ||
|
|
60d63fcd21 | ||
|
|
8f99d6cf01 | ||
|
|
4c6a0cdc37 | ||
|
|
0cad1bf6a5 | ||
|
|
95a478e55e | ||
|
|
41a30b5826 | ||
|
|
b1030b6601 | ||
|
|
5dfd5d8027 | ||
|
|
51b7dc5b5c | ||
|
|
7bfbdd5bc0 | ||
|
|
aa3137c0a9 | ||
|
|
c2027a5481 | ||
|
|
909e36b80d | ||
|
|
4fa2624495 | ||
|
|
a97c88c45b | ||
|
|
c579f638fc | ||
|
|
65fdf8f6d1 | ||
|
|
f6fd1f7e84 | ||
|
|
732f5bf21d | ||
|
|
6d2d3eca18 | ||
|
|
997738816d | ||
|
|
41906b6fab | ||
|
|
c910de12ff | ||
|
|
2baed357f2 | ||
|
|
ee513939aa | ||
|
|
b843ab7b97 | ||
|
|
8c37fa8d8b | ||
|
|
a46a14c6ac | ||
|
|
2fec2bfc51 | ||
|
|
ea1e6f20a8 | ||
|
|
aeb72cba02 | ||
|
|
279fb8803e | ||
|
|
59394e23f4 | ||
|
|
8f78b599ae | ||
|
|
cc4ec1b526 | ||
|
|
18a977fdf1 | ||
|
|
bc945df0a7 | ||
|
|
32867d1bbf | ||
|
|
c844290c81 | ||
|
|
4a1f5194cc | ||
|
|
0db8e634a8 | ||
|
|
8309ee965a | ||
|
|
0fa4a89223 | ||
|
|
9350afbe6a | ||
|
|
7ce9d27a67 | ||
|
|
83a4440cad | ||
|
|
85cd54fdfe | ||
|
|
c3eabebd91 | ||
|
|
26aff26eb0 | ||
|
|
07b974d638 | ||
|
|
75cdac5dbf | ||
|
|
7c6fecf13d | ||
|
|
7c96ee1e00 | ||
|
|
975c4e6b26 | ||
|
|
c4838424db | ||
|
|
e07279707a | ||
|
|
1e0db7df4e | ||
|
|
b41cbc8ab4 | ||
|
|
906870d36f | ||
|
|
95baeed75e | ||
|
|
a622c1591e | ||
|
|
030269b596 | ||
|
|
5ff5d46ba5 | ||
|
|
d1ab44912b | ||
|
|
23c6e455fe | ||
|
|
7b5ac1c869 | ||
|
|
143ca274f5 | ||
|
|
7d51a4bfbf | ||
|
|
23e64f23a8 | ||
|
|
a5e2df11eb | ||
|
|
4406f7428b | ||
|
|
17770fe130 | ||
|
|
ff47a13bc3 | ||
|
|
ed38b7e86c | ||
|
|
3f2ee64293 | ||
|
|
2512e7f445 | ||
|
|
9fbfca5699 | ||
|
|
1039160d3a | ||
|
|
214478760b | ||
|
|
c49cbd3c3c | ||
|
|
de8cff072d | ||
|
|
2b0e1fb9dc | ||
|
|
f6d9061441 | ||
|
|
71b5495569 | ||
|
|
0fa68397b7 | ||
|
|
2561886189 | ||
|
|
b73ddc232b | ||
|
|
65b9b653d0 | ||
|
|
ca8917dd1b | ||
|
|
bbdf9618ea | ||
|
|
23f9474e9e | ||
|
|
69642d2db3 | ||
|
|
47a7c5e27b | ||
|
|
502bf8ebf8 | ||
|
|
ecba80372d | ||
|
|
f272b865cd | ||
|
|
89cfbc6bd3 | ||
|
|
e2d3fef9db | ||
|
|
c5b8deff41 | ||
|
|
8478ccca5d | ||
|
|
a268cb552d | ||
|
|
1b0978f252 | ||
|
|
8730980ab8 | ||
|
|
caf70d703e | ||
|
|
95ced89d5e | ||
|
|
e4c9c292e5 | ||
|
|
fe7a7f4d77 | ||
|
|
cb0b32f90a | ||
|
|
9e93bb2dd8 | ||
|
|
0e6c41f823 | ||
|
|
725212b8a4 | ||
|
|
a275ee6b65 | ||
|
|
997095ce39 | ||
|
|
8b9cd51134 | ||
|
|
e7cbfb3ee9 | ||
|
|
1f7bdb1b2a | ||
|
|
9f14b2278d | ||
|
|
4177b02064 | ||
|
|
847d7b6980 | ||
|
|
ef1114512f | ||
|
|
38c36c00c9 | ||
|
|
846820f4ec | ||
|
|
c39e90b9b0 | ||
|
|
096d7587c3 | ||
|
|
27f5bb60e5 | ||
|
|
70ed5ce829 | ||
|
|
e58dc8e446 | ||
|
|
60e3538adc | ||
|
|
e2fb02323c | ||
|
|
57c7945847 | ||
|
|
68c723e135 | ||
|
|
0241414dfb | ||
|
|
c5a356f3e7 | ||
|
|
deecd19af2 | ||
|
|
f4cb13aa0e | ||
|
|
4385014049 | ||
|
|
fcb84132f4 | ||
|
|
50bd3094b4 | ||
|
|
d7cb71f877 | ||
|
|
e287404992 | ||
|
|
d332f11101 | ||
|
|
f78a9e2ccf | ||
|
|
bd7294e672 | ||
|
|
b3304a059d | ||
|
|
d0529fb234 | ||
|
|
bb912786bd | ||
|
|
8f47190ffc | ||
|
|
196f1f7471 | ||
|
|
e3cc25f23f | ||
|
|
a963b31c1d | ||
|
|
4d1689d6e9 | ||
|
|
fed329568c | ||
|
|
e3f642ac25 | ||
|
|
c94d922282 | ||
|
|
7563a0fa1f | ||
|
|
f5db0e438b | ||
|
|
9982ae4675 | ||
|
|
69eba9c493 | ||
|
|
2c67d73f08 | ||
|
|
7f4b9cf36c | ||
|
|
9c0ea17ada | ||
|
|
91a6e55f74 | ||
|
|
fea650fbe4 | ||
|
|
35e0497f86 | ||
|
|
fbc3735f44 | ||
|
|
9be80c103e | ||
|
|
640f2b1c55 | ||
|
|
d8df57130a | ||
|
|
3ba0533773 | ||
|
|
b1224032a1 | ||
|
|
1a7ed53559 | ||
|
|
9e9487617a | ||
|
|
d68b8138a5 | ||
|
|
10ca72f934 | ||
|
|
9dbf0df67d | ||
|
|
b072af3082 | ||
|
|
35c8b74bb4 | ||
|
|
7fbe9ba34f | ||
|
|
81c6ca5915 | ||
|
|
d73a4a38e5 | ||
|
|
6309f478a2 | ||
|
|
4ca2c0e740 | ||
|
|
ea9ada8d20 | ||
|
|
302b61090b | ||
|
|
75d224cd67 | ||
|
|
2ff9a129c0 | ||
|
|
a1a4ce1af8 | ||
|
|
44ac873100 | ||
|
|
3d179a869a | ||
|
|
530f2de79e | ||
|
|
512e581d56 | ||
|
|
e5c2ad2069 | ||
|
|
6af961199e | ||
|
|
276aa23a61 | ||
|
|
e33a7ff53b | ||
|
|
d9d50d8943 | ||
|
|
7c753e2289 | ||
|
|
ff81a286bb | ||
|
|
c7c3ac7c9c | ||
|
|
74f673e23c | ||
|
|
7c51fbfd18 | ||
|
|
7839ff8057 | ||
|
|
8b91e168e5 | ||
|
|
08f056bb3f | ||
|
|
808af7fce1 | ||
|
|
090d353f3d | ||
|
|
c4b371ccc9 | ||
|
|
06a1119512 | ||
|
|
b80c4253f0 | ||
|
|
3f306de5e1 | ||
|
|
39f9506446 | ||
|
|
00de30d336 | ||
|
|
b59df48dde | ||
|
|
3840b3c561 | ||
|
|
b5424ec671 | ||
|
|
ec184fb2ab | ||
|
|
4a750c7b16 | ||
|
|
f38bbf90bb | ||
|
|
05dcff4f87 | ||
|
|
b458118e34 | ||
|
|
7a920da06d | ||
|
|
ec84f43b80 | ||
|
|
03d572fe10 | ||
|
|
c41df22c88 | ||
|
|
3b3b9e2bd9 | ||
|
|
ebf9dbe931 | ||
|
|
0b3b78891b | ||
|
|
12af30b75b | ||
|
|
a9775a0686 | ||
|
|
ca9809ca7e | ||
|
|
97e14de63e | ||
|
|
0f4cdc2d21 | ||
|
|
869b6ed89d | ||
|
|
1876de0a68 | ||
|
|
019d064d8e | ||
|
|
d6b45eb825 | ||
|
|
556a6aaf33 | ||
|
|
fc7ec9e538 | ||
|
|
1f239214a1 | ||
|
|
9e224987f7 | ||
|
|
81317ce672 | ||
|
|
fce23c482c | ||
|
|
1d2e042240 | ||
|
|
d852bb82a3 | ||
|
|
fdb7754043 | ||
|
|
62c3faaacb | ||
|
|
b58279beea | ||
|
|
898d62bad9 | ||
|
|
446c8ace82 | ||
|
|
e007ee9976 | ||
|
|
6721155155 | ||
|
|
b80619fb0f | ||
|
|
e75e26467f | ||
|
|
2187f0b198 | ||
|
|
3382a5d03c | ||
|
|
fff9145680 | ||
|
|
13e57bb183 | ||
|
|
948500ae41 | ||
|
|
17bcdd7902 | ||
|
|
03837a9308 | ||
|
|
b8bfc13cf9 | ||
|
|
24403cdd25 | ||
|
|
13d0106feb | ||
|
|
dce64fc487 | ||
|
|
0629fe7846 | ||
|
|
315ec47523 | ||
|
|
9ed2141fc8 | ||
|
|
5b40c5008f | ||
|
|
62db9ae01a | ||
|
|
8c2cd2f60d | ||
|
|
0812f6f3c3 | ||
|
|
065e9e718a | ||
|
|
27f1dc318b | ||
|
|
ac5f439839 | ||
|
|
b4255e22aa | ||
|
|
d15c1af152 | ||
|
|
0140989f3a | ||
|
|
793e329fa5 | ||
|
|
6702802829 | ||
|
|
dae9a67fe2 | ||
|
|
b8e11b1272 | ||
|
|
f08b6abc96 | ||
|
|
965812bc19 | ||
|
|
7f643345ce | ||
|
|
28fecbc50c | ||
|
|
6c11e9f27d | ||
|
|
2af179630a | ||
|
|
c243e82047 | ||
|
|
3de77b1849 | ||
|
|
37d09b0bdb | ||
|
|
9a5d23ebde | ||
|
|
da3ed5ff79 | ||
|
|
2e8b462fe5 | ||
|
|
87b2b708f8 | ||
|
|
7ddf8bbe94 | ||
|
|
a87782b025 | ||
|
|
c39f2b0c1f | ||
|
|
a07ad3e479 | ||
|
|
c58f95b79e | ||
|
|
d9f7952710 | ||
|
|
ab70a056fc | ||
|
|
844ba53f54 | ||
|
|
63b920cd7b | ||
|
|
2a5fd78789 | ||
|
|
bc52fe9b82 | ||
|
|
667c113d5b | ||
|
|
38915859ba | ||
|
|
70d0be4b9a | ||
|
|
dad446ea41 | ||
|
|
d283900e43 | ||
|
|
4b043e31fe | ||
|
|
f65882e42a | ||
|
|
1fda8f6219 | ||
|
|
620c629bb4 | ||
|
|
a1f63da057 |
@@ -1,3 +1,7 @@
|
||||
# This file is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
# Generated from CLion C/C++ Code Style settings
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -2
|
||||
@@ -23,6 +27,7 @@ BraceWrapping:
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
|
||||
6
.flake8
Normal file
6
.flake8
Normal file
@@ -0,0 +1,6 @@
|
||||
[flake8]
|
||||
filename =
|
||||
*.py
|
||||
max-line-length = 120
|
||||
extend-exclude =
|
||||
venv/
|
||||
102
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
102
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
name: Bug Report
|
||||
description: Create a bug report to help us improve.
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
**THIS IS NOT THE PLACE TO ASK FOR SUPPORT!**
|
||||
Please use [Discord](https://docs.lizardbyte.dev/en/latest/about/support.html#discord) for support issues.
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
description: A clear and concise description of the bug.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expected
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any other context about the bug here.
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: Host Operating System
|
||||
description: What version operating system are you running the software on?
|
||||
options:
|
||||
- Linux
|
||||
- macOS
|
||||
- Windows
|
||||
- other
|
||||
- type: input
|
||||
id: os-version
|
||||
attributes:
|
||||
label: Operating System Version
|
||||
description: Provide the version of the operating system. Additionally a build number would be helpful.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: os-architecture
|
||||
attributes:
|
||||
label: Architecture
|
||||
placeholder: e.g. 32 bit, 64 bit, arm
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Sunshine Version
|
||||
placeholder: eg. 0.14.0
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: graphics_type
|
||||
attributes:
|
||||
label: GPU Type
|
||||
description: The type of the installed graphics card.
|
||||
placeholder: e.g. Intel, AMD, Nvidia
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: graphics_model
|
||||
attributes:
|
||||
label: GPU Model
|
||||
description: The model of the installed graphics card.
|
||||
placeholder: e.g. GeForce RTX 2080 SUPER
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: graphics_driver
|
||||
attributes:
|
||||
label: GPU Driver/Mesa Version
|
||||
description: The driver/mesa version of the installed graphics card.
|
||||
placeholder: e.g. 497.29
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: capture_method
|
||||
attributes:
|
||||
label: Capture Method (Linux Only)
|
||||
description: The driver/mesa version of the installed graphics card.
|
||||
placeholder: e.g. PipeWire/KVM/X11
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: |
|
||||
Please copy and paste any relevant log output. This will be automatically formatted into code,
|
||||
so no need for backticks.
|
||||
render: Shell
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Make sure to close your issue when it's solved! If you found the solution yourself please comment
|
||||
so that others benefit from it.
|
||||
19
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
19
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord support
|
||||
url: https://docs.lizardbyte.dev/about/support.html#discord
|
||||
about: Ask questions in Discord
|
||||
- name: Reddit support
|
||||
url: https://www.reddit.com/r/LizardByte
|
||||
about: Get community support on Reddit
|
||||
- name: Facebook support
|
||||
url: https://www.facebook.com/groups/lizardbyte
|
||||
about: Get community support on Facebook
|
||||
- name: Feature request
|
||||
url: https://feedback.lizardbyte.dev
|
||||
about: Share your suggestions or ideas to help us improve
|
||||
30
.github/dependabot.yml
vendored
Normal file
30
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "00:00"
|
||||
target-branch: "nightly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "00:00"
|
||||
target-branch: "nightly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
time: "00:00"
|
||||
target-branch: "nightly"
|
||||
open-pull-requests-limit: 10
|
||||
49
.github/label-actions.yml
vendored
Normal file
49
.github/label-actions.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
# Configuration for Label Actions - https://github.com/dessant/label-actions
|
||||
|
||||
added:
|
||||
comment: >
|
||||
This feature has been added and will be available in the next release.
|
||||
fixed:
|
||||
comment: >
|
||||
This issue has been fixed and will be available in the next release.
|
||||
invalid:duplicate:
|
||||
comment: >
|
||||
:wave: @{issue-author}, this appears to be a duplicate of a pre-existing issue.
|
||||
close: true
|
||||
lock: true
|
||||
unlabel: 'status:awaiting-triage'
|
||||
|
||||
-invalid:duplicate:
|
||||
reopen: true
|
||||
unlock: true
|
||||
|
||||
invalid:support:
|
||||
comment: >
|
||||
:wave: @{issue-author}, we use the issue tracker exclusively for bug reports.
|
||||
However, this issue appears to be a support request. Please use
|
||||
[Discord](https://docs.lizardbyte.dev/about/support.html#discord) for support issues. Thanks.
|
||||
close: true
|
||||
lock: true
|
||||
lock-reason: 'off-topic'
|
||||
unlabel: 'status:awaiting-triage'
|
||||
|
||||
-invalid:support:
|
||||
reopen: true
|
||||
unlock: true
|
||||
|
||||
invalid:template-incomplete:
|
||||
issues:
|
||||
comment: >
|
||||
:wave: @{issue-author}, please edit your issue to complete the template with
|
||||
all the required info. Your issue will be automatically closed in 5 days if
|
||||
the template is not completed. Thanks.
|
||||
prs:
|
||||
comment: >
|
||||
:wave: @{issue-author}, please edit your PR to complete the template with
|
||||
all the required info. Your PR will be automatically closed in 5 days if
|
||||
the template is not completed. Thanks.
|
||||
24
.github/pr_release_template.md
vendored
Normal file
24
.github/pr_release_template.md
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
## Description
|
||||
<!--- Please include a summary of the changes. --->
|
||||
This PR was created automatically.
|
||||
|
||||
|
||||
### Screenshot
|
||||
<!--- Include screenshots if the changes are UI-related. --->
|
||||
|
||||
|
||||
### Issues Fixed or Closed
|
||||
<!--- Close issue example: `- Closes #1` --->
|
||||
<!--- Fix bug issue example: `- Fixes #2` --->
|
||||
<!--- Resolve issue example: `- Resolves #3` --->
|
||||
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
- [ ] Documentation update (changes to documentation)
|
||||
- [ ] Repository update (changes to repository files)
|
||||
|
||||
## Changelog Summary
|
||||
<!--- Summarize all the changes in a bulleted list. --->
|
||||
22
.github/pull_request_template.md
vendored
Normal file
22
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
## Description
|
||||
<!--- Please include a summary of the changes. --->
|
||||
|
||||
### Screenshot
|
||||
<!--- Include screenshots if the changes are UI-related. --->
|
||||
|
||||
### Issues Fixed or Closed
|
||||
<!--- Delete if not relevant. --->
|
||||
- Fixes #(issue)
|
||||
|
||||
## Type of Change
|
||||
<!--- Please delete options that are not relevant. --->
|
||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] New feature (non-breaking change which adds functionality)
|
||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
||||
|
||||
## Checklist
|
||||
<!--- DO NOT delete any options here. It is okay to have items unchecked! --->
|
||||
- [ ] My code follows the style guidelines of this project
|
||||
- [ ] I have performed a self-review of my own code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have added or updated the docstring/documentation-blocks for new or existing methods/components
|
||||
805
.github/workflows/CI.yml
vendored
Normal file
805
.github/workflows/CI.yml
vendored
Normal file
@@ -0,0 +1,805 @@
|
||||
---
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, nightly]
|
||||
types: [opened, synchronize, reopened]
|
||||
push:
|
||||
branches: [master]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
github_env:
|
||||
name: GitHub Env Debug
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Dump github context
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
shell: bash
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
|
||||
check_changelog:
|
||||
name: Check Changelog
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Verify Changelog
|
||||
id: verify_changelog
|
||||
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }}
|
||||
# base_ref for pull request check, ref for push
|
||||
uses: LizardByte/.github/actions/verify_changelog@master
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
outputs:
|
||||
next_version: ${{ steps.verify_changelog.outputs.changelog_parser_version }}
|
||||
next_version_bare: ${{ steps.verify_changelog.outputs.changelog_parser_version_bare }}
|
||||
last_version: ${{ steps.verify_changelog.outputs.latest_release_tag_name }}
|
||||
release_body: ${{ steps.verify_changelog.outputs.changelog_parser_description }}
|
||||
|
||||
check_versions:
|
||||
name: Check Versions
|
||||
runs-on: ubuntu-latest
|
||||
needs: check_changelog
|
||||
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' }}
|
||||
# base_ref for pull request check, ref for push
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check CMakeLists.txt Version
|
||||
run: |
|
||||
version=$(grep -o -E '^project\(Sunshine VERSION [0-9]+\.[0-9]+\.[0-9]+' CMakeLists.txt | \
|
||||
grep -o -E '[0-9]+\.[0-9]+\.[0-9]+')
|
||||
echo "cmakelists_version=${version}" >> $GITHUB_ENV
|
||||
|
||||
- name: Compare CMakeList.txt Version
|
||||
if: ${{ env.cmakelists_version != needs.check_changelog.outputs.next_version_bare }}
|
||||
run: |
|
||||
echo CMakeLists version: "$cmakelists_version"
|
||||
echo Changelog version: "${{ needs.check_changelog.outputs.next_version_bare }}"
|
||||
echo Within 'CMakeLists.txt' change "project(Sunshine [VERSION $cmakelists_version]" to \
|
||||
"project(Sunshine [VERSION ${{ needs.check_changelog.outputs.next_version_bare }}]"
|
||||
exit 1
|
||||
|
||||
build_linux_aur:
|
||||
name: Linux AUR
|
||||
runs-on: ubuntu-latest
|
||||
needs: check_changelog
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Dependencies Linux AUR
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y \
|
||||
cmake
|
||||
|
||||
- name: Configure PKGBUILD files
|
||||
run: |
|
||||
# variables for manifest
|
||||
echo "aur_publish=false" >> $GITHUB_ENV
|
||||
aur_pkg=sunshine-dev
|
||||
sub_version=""
|
||||
conflicts="'sunshine'"
|
||||
provides="'sunshine'"
|
||||
|
||||
branch=${GITHUB_HEAD_REF}
|
||||
|
||||
# check the branch variable
|
||||
if [ -z "$branch" ]
|
||||
then
|
||||
echo "This is a PUSH event"
|
||||
commit=${{ github.sha }}
|
||||
clone_url=${{ github.event.repository.clone_url }}
|
||||
|
||||
if [[ ${{ github.ref == 'refs/heads/master' }} ]]; then
|
||||
aur_pkg=sunshine
|
||||
conflicts=""
|
||||
provides=""
|
||||
|
||||
echo "aur_publish=true" >> $GITHUB_ENV
|
||||
elif [[ ${{ github.ref == 'refs/heads/nightly' }} ]]; then
|
||||
aur_pkg=sunshine-git
|
||||
sub_version=".r${commit}"
|
||||
|
||||
echo "aur_publish=true" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
echo "This is a PR event"
|
||||
commit=${{ github.event.pull_request.head.sha }}
|
||||
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
|
||||
|
||||
sub_version=".r${commit}"
|
||||
fi
|
||||
echo "Commit: ${commit}"
|
||||
echo "Clone URL: ${clone_url}"
|
||||
|
||||
echo "aur_pkg=${aur_pkg}" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p artifacts
|
||||
mkdir -p build
|
||||
|
||||
cd build
|
||||
cmake -DSUNSHINE_CONFIGURE_AUR=ON \
|
||||
-DSUNSHINE_AUR_PKG=${aur_pkg} \
|
||||
-DSUNSHINE_SUB_VERSION=${sub_version} \
|
||||
-DSUNSHINE_AUR_CONFLICTS=${conflicts} \
|
||||
-DSUNSHINE_AUR_PROVIDES=${provides} \
|
||||
-DGITHUB_CLONE_URL=${clone_url} \
|
||||
-DGITHUB_COMMIT=${commit} \
|
||||
-DSUNSHINE_CONFIGURE_ONLY=ON \
|
||||
..
|
||||
cd ..
|
||||
|
||||
mv ./build/PKGBUILD ./artifacts/
|
||||
|
||||
- name: Validate package
|
||||
uses: hapakaien/archlinux-package-action@v2.2.0
|
||||
with:
|
||||
path: artifacts
|
||||
flags: '--syncdeps --noconfirm'
|
||||
namcap: true
|
||||
srcinfo: true
|
||||
aur: true # workaround mirror problem
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-linux-aur
|
||||
path: artifacts/
|
||||
|
||||
- name: Publish AUR package
|
||||
if: ${{ env.aur_publish == 'true' }}
|
||||
uses: KSXGitHub/github-actions-deploy-aur@v2.4.1
|
||||
with:
|
||||
pkgname: ${{ env.aur_pkg }}
|
||||
pkgbuild: ./artifacts/PKGBUILD
|
||||
assets: |
|
||||
./artifacts/*
|
||||
commit_username: ${{ secrets.AUR_USERNAME }}
|
||||
commit_email: ${{ secrets.AUR_EMAIL }}
|
||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
commit_message: Automatic update from GitHub ${{ github.repository }} per ${{ github.ref }}
|
||||
allow_empty_commits: false
|
||||
|
||||
build_linux_flatpak:
|
||||
name: Linux Flatpak
|
||||
runs-on: ubuntu-latest
|
||||
needs: check_changelog
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Dependencies Linux Flatpak
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y \
|
||||
cmake \
|
||||
flatpak
|
||||
sudo su $(whoami) -c 'flatpak remote-add --user --if-not-exists flathub \
|
||||
https://flathub.org/repo/flathub.flatpakrepo'
|
||||
sudo su $(whoami) -c 'flatpak install --user flathub \
|
||||
org.flatpak.Builder org.freedesktop.Platform//21.08 org.freedesktop.Sdk//21.08 -y'
|
||||
|
||||
- name: Configure Flatpak Manifest
|
||||
run: |
|
||||
# variables for manifest
|
||||
branch=${GITHUB_HEAD_REF}
|
||||
|
||||
# check the branch variable
|
||||
if [ -z "$branch" ]
|
||||
then
|
||||
echo "This is a PUSH event"
|
||||
branch=${{ github.ref_name }}
|
||||
commit=${{ github.sha }}
|
||||
clone_url=${{ github.event.repository.clone_url }}
|
||||
else
|
||||
echo "This is a PR event"
|
||||
commit=${{ github.event.pull_request.head.sha }}
|
||||
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
|
||||
fi
|
||||
echo "Branch: ${branch}"
|
||||
echo "Commit: ${commit}"
|
||||
echo "Clone URL: ${clone_url}"
|
||||
|
||||
mkdir -p build
|
||||
mkdir -p artifacts
|
||||
|
||||
cd build
|
||||
cmake -DGITHUB_CLONE_URL=${clone_url} \
|
||||
-DGITHUB_BRANCH=${branch} \
|
||||
-DGITHUB_COMMIT=${commit} \
|
||||
-DSUNSHINE_CONFIGURE_FLATPAK=ON \
|
||||
-DSUNSHINE_CONFIGURE_ONLY=ON \
|
||||
..
|
||||
|
||||
- name: Build Linux Flatpak
|
||||
working-directory: build
|
||||
run: |
|
||||
sudo su $(whoami) -c 'flatpak run org.flatpak.Builder --repo=repo --force-clean build-sunshine \
|
||||
dev.lizardbyte.sunshine.yml'
|
||||
sudo su $(whoami) -c 'flatpak build-bundle ./repo ../artifacts/sunshine.flatpak dev.lizardbyte.sunshine'
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-linux-flatpak
|
||||
path: artifacts/
|
||||
|
||||
- name: Create Release
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: LizardByte/.github/actions/create_release@master
|
||||
with:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
next_version: ${{ needs.check_changelog.outputs.next_version }}
|
||||
last_version: ${{ needs.check_changelog.outputs.last_version }}
|
||||
release_body: ${{ needs.check_changelog.outputs.release_body }}
|
||||
|
||||
build_linux:
|
||||
name: Linux
|
||||
runs-on: ubuntu-20.04
|
||||
needs: check_changelog
|
||||
strategy:
|
||||
fail-fast: false # false to test all, true to fail entire job if any fail
|
||||
matrix:
|
||||
include: # package these differently
|
||||
- type: cpack
|
||||
CMAKE_INSTALL_PREFIX: '/usr'
|
||||
SUNSHINE_ASSETS_DIR: 'local/sunshine/assets'
|
||||
SUNSHINE_CONFIG_DIR: 'local/sunshine/config'
|
||||
EXTRA_ARGS: ''
|
||||
- type: appimage
|
||||
CMAKE_INSTALL_PREFIX: '/usr'
|
||||
SUNSHINE_ASSETS_DIR: 'sunshine.AppImage.config'
|
||||
SUNSHINE_CONFIG_DIR: 'sunshine.AppImage.home'
|
||||
EXTRA_ARGS: '-DSUNSHINE_CONFIGURE_APPIMAGE=ON'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Dependencies Linux
|
||||
run: |
|
||||
sudo add-apt-repository ppa:savoury1/ffmpeg4 -y
|
||||
# sudo add-apt-repository ppa:savoury1/boost-defaults-1.71 -y
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
gcc-10 \
|
||||
git \
|
||||
g++-10 \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
wget
|
||||
# # Ubuntu 20.04+ packages
|
||||
# libboost-filesystem-dev
|
||||
# libboost-log-dev
|
||||
# libboost-thread-dev
|
||||
|
||||
# # Ubuntu 18.04 packages
|
||||
# libboost-filesystem1.71-dev \
|
||||
# libboost-log1.71-dev \
|
||||
# libboost-regex1.71-dev \
|
||||
# libboost-thread1.71-dev \
|
||||
|
||||
# clean apt cache
|
||||
sudo apt-get clean
|
||||
sudo rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Update gcc alias
|
||||
sudo update-alternatives --install \
|
||||
/usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10
|
||||
|
||||
# Install CuDA
|
||||
sudo wget \
|
||||
https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run \
|
||||
--progress=bar:force:noscroll -q --show-progress -O /root/cuda.run
|
||||
sudo chmod a+x /root/cuda.run
|
||||
sudo /root/cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm
|
||||
sudo rm /root/cuda.run
|
||||
|
||||
# # Install cmake (necessary for 18.04)
|
||||
# wget https://cmake.org/files/v3.22/cmake-3.22.2-linux-x86_64.sh
|
||||
# chmod +x cmake-3.22.2-linux-x86_64.sh
|
||||
# mkdir /opt/cmake
|
||||
# ./cmake-3.22.2-linux-x86_64.sh --prefix=/opt/cmake --skip-license
|
||||
# ln --force --symbolic /opt/cmake/bin/cmake /usr/local/bin/cmake
|
||||
# cmake --version
|
||||
|
||||
- name: Build Linux
|
||||
run: |
|
||||
mkdir -p build
|
||||
mkdir -p artifacts
|
||||
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=${{ matrix.CMAKE_INSTALL_PREFIX }} \
|
||||
-DSUNSHINE_ASSETS_DIR=${{ matrix.SUNSHINE_ASSETS_DIR }} \
|
||||
-DSUNSHINE_CONFIG_DIR=${{ matrix.SUNSHINE_CONFIG_DIR }} \
|
||||
-DSUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \
|
||||
-DSUNSHINE_ENABLE_WAYLAND=ON \
|
||||
-DSUNSHINE_ENABLE_X11=ON \
|
||||
-DSUNSHINE_ENABLE_DRM=ON \
|
||||
-DSUNSHINE_ENABLE_CUDA=ON \
|
||||
${{ matrix.EXTRA_ARGS }} \
|
||||
..
|
||||
make -j ${nproc}
|
||||
|
||||
- name: Package Linux - CPACK
|
||||
if: ${{ matrix.type == 'cpack' }}
|
||||
working-directory: build
|
||||
run: |
|
||||
# package
|
||||
cpack -G DEB
|
||||
cpack -G RPM
|
||||
|
||||
# move
|
||||
mv ./cpack_artifacts/Sunshine.deb ../artifacts/sunshine.deb
|
||||
mv ./cpack_artifacts/Sunshine.rpm ../artifacts/sunshine.rpm
|
||||
|
||||
- name: Set AppImage Version
|
||||
if: ${{ matrix.type == 'appimage' && ( needs.check_changelog.outputs.next_version_bare != needs.check_changelog.outputs.latest_version ) }} # yamllint disable-line rule:line-length
|
||||
run: |
|
||||
version=${{ needs.check_changelog.outputs.next_version_bare }}
|
||||
echo "VERSION=${version}" >> $GITHUB_ENV
|
||||
|
||||
- name: Package Linux - AppImage
|
||||
if: ${{ matrix.type == 'appimage' }}
|
||||
working-directory: build
|
||||
run: |
|
||||
# install sunshine to the DESTDIR
|
||||
make install DESTDIR=AppDir
|
||||
|
||||
# portable home and config
|
||||
# todo - this is ugly... we should use a custom AppRun script to take care of this
|
||||
mv ./AppDir${{ matrix.CMAKE_INSTALL_PREFIX }}/sunshine.AppImage.* ../artifacts/
|
||||
mkdir -p ../artifacts/${{ matrix.SUNSHINE_CONFIG_DIR }}/.config/sunshine/${{ matrix.SUNSHINE_CONFIG_DIR }}
|
||||
cp ../artifacts/${{ matrix.SUNSHINE_CONFIG_DIR }}/apps.json \
|
||||
../artifacts/${{ matrix.SUNSHINE_CONFIG_DIR }}/.config/sunshine/${{ matrix.SUNSHINE_CONFIG_DIR }}/
|
||||
|
||||
# variables
|
||||
DESKTOP_FILE="${DESKTOP_FILE:-sunshine.desktop}"
|
||||
ICON_FILE="${ICON_FILE:-sunshine.png}"
|
||||
|
||||
# AppImage
|
||||
# https://docs.appimage.org/packaging-guide/index.html
|
||||
wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||
chmod +x linuxdeploy-x86_64.AppImage
|
||||
|
||||
# # https://github.com/linuxdeploy/linuxdeploy-plugin-gtk
|
||||
# sudo apt-get install libgtk-3-dev librsvg2-dev -y
|
||||
# wget https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh
|
||||
# chmod +x linuxdeploy-plugin-gtk.sh
|
||||
# export DEPLOY_GTK_VERSION=3
|
||||
|
||||
./linuxdeploy-x86_64.AppImage \
|
||||
--appdir ./AppDir \
|
||||
--executable ./sunshine \
|
||||
--icon-file "../$ICON_FILE" \
|
||||
--desktop-file "./$DESKTOP_FILE" \
|
||||
--library /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0 \
|
||||
--library /usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0 \
|
||||
--library /usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0 \
|
||||
--output appimage
|
||||
# # add this argument back if using gtk plugin
|
||||
# --plugin gtk \
|
||||
|
||||
# move
|
||||
mv Sunshine*.AppImage ../artifacts/sunshine.AppImage
|
||||
|
||||
# permissions
|
||||
chmod +x ../artifacts/sunshine.AppImage
|
||||
|
||||
- name: Verify AppImage
|
||||
if: ${{ matrix.type == 'appimage' }}
|
||||
run: |
|
||||
wget https://github.com/TheAssassin/appimagelint/releases/download/continuous/appimagelint-x86_64.AppImage
|
||||
chmod +x appimagelint-x86_64.AppImage
|
||||
|
||||
# rm -rf ~/.cache/appimagelint/
|
||||
|
||||
./appimagelint-x86_64.AppImage ./artifacts/sunshine.AppImage
|
||||
|
||||
- name: Archive AppImage
|
||||
if: ${{ matrix.type == 'appimage' }}
|
||||
working-directory: artifacts
|
||||
run: |
|
||||
chmod +x ./sunshine.AppImage
|
||||
|
||||
zip --recurse-paths --move --test ./sunshine-appimage.zip ./*
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-linux-${{ matrix.type }}
|
||||
path: artifacts/
|
||||
|
||||
- name: Create Release
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: LizardByte/.github/actions/create_release@master
|
||||
with:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
next_version: ${{ needs.check_changelog.outputs.next_version }}
|
||||
last_version: ${{ needs.check_changelog.outputs.last_version }}
|
||||
release_body: ${{ needs.check_changelog.outputs.release_body }}
|
||||
|
||||
build_mac:
|
||||
name: MacOS
|
||||
runs-on: macos-11
|
||||
needs: check_changelog
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Dependencies MacOS
|
||||
run: |
|
||||
# install dependencies using homebrew
|
||||
brew install boost cmake ffmpeg opus
|
||||
|
||||
# fix openssl header not found
|
||||
ln -sf /usr/local/opt/openssl/include/openssl /usr/local/include/openssl
|
||||
|
||||
- name: Build MacOS
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DSUNSHINE_ASSETS_DIR=local/sunshine/assets \
|
||||
-DSUNSHINE_CONFIG_DIR=local/sunshine/config \
|
||||
..
|
||||
make -j ${nproc}
|
||||
|
||||
- name: Package MacOS
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cd build
|
||||
|
||||
# package
|
||||
cpack -G DragNDrop
|
||||
mv ./cpack_artifacts/Sunshine.dmg ../artifacts/sunshine-macos-experimental-dragndrop.dmg
|
||||
|
||||
cpack -G Bundle
|
||||
mv ./cpack_artifacts/Sunshine.dmg ../artifacts/sunshine-macos-experimental-bundle.dmg
|
||||
|
||||
cpack -G ZIP
|
||||
mv ./cpack_artifacts/Sunshine.zip ../artifacts/sunshine-macos-experimental-archive.zip
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-macos
|
||||
path: artifacts/
|
||||
|
||||
# this step can be removed after packages are fixed
|
||||
- name: Delete experimental packages
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
working-directory: artifacts
|
||||
run: |
|
||||
rm -f ./sunshine-macos-experimental-dragndrop.dmg
|
||||
rm -f ./sunshine-macos-experimental-bundle.dmg
|
||||
rm -f ./sunshine-macos-experimental-archive.zip
|
||||
|
||||
## no artifacts to release currently
|
||||
# - name: Create Release
|
||||
# if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
# uses: LizardByte/.github/actions/create_release@master
|
||||
# with:
|
||||
# token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
# next_version: ${{ needs.check_changelog.outputs.next_version }}
|
||||
# last_version: ${{ needs.check_changelog.outputs.last_version }}
|
||||
# release_body: ${{ needs.check_changelog.outputs.release_body }}
|
||||
|
||||
build_mac_port:
|
||||
name: Macports
|
||||
needs: check_changelog
|
||||
runs-on: macos-11
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Checkout ports
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: macports/macports-ports
|
||||
fetch-depth: 64
|
||||
path: ports
|
||||
|
||||
- name: Checkout mpbb
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: macports/mpbb
|
||||
path: mpbb
|
||||
|
||||
- name: Setup Dependencies Macports
|
||||
run: |
|
||||
# install dependencies using homebrew
|
||||
brew install cmake
|
||||
|
||||
- name: Configure Portfile
|
||||
run: |
|
||||
# variables for Portfile
|
||||
branch=${GITHUB_HEAD_REF}
|
||||
|
||||
# check the branch variable
|
||||
if [ -z "$branch" ]
|
||||
then
|
||||
echo "This is a PUSH event"
|
||||
commit=${{ github.sha }}
|
||||
clone_url=${{ github.event.repository.clone_url }}
|
||||
else
|
||||
echo "This is a PR event"
|
||||
commit=${{ github.event.pull_request.head.sha }}
|
||||
clone_url=${{ github.event.pull_request.head.repo.clone_url }}
|
||||
fi
|
||||
echo "Commit: ${commit}"
|
||||
echo "Clone URL: ${clone_url}"
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DGITHUB_COMMIT=${commit} \
|
||||
-DGITHUB_CLONE_URL=${clone_url} \
|
||||
-DSUNSHINE_CONFIGURE_PORTFILE=ON \
|
||||
-DSUNSHINE_CONFIGURE_ONLY=ON \
|
||||
..
|
||||
cd ..
|
||||
|
||||
# copy Portfile to artifacts
|
||||
mkdir -p artifacts
|
||||
cp -f ./build/Portfile ./artifacts/
|
||||
|
||||
# copy Portfile to ports
|
||||
mkdir -p ./ports/multimedia/Sunshine
|
||||
cp -f ./build/Portfile ./ports/multimedia/Sunshine/Portfile
|
||||
|
||||
# testing
|
||||
cat ./artifacts/Portfile
|
||||
|
||||
- name: Bootstrap MacPorts
|
||||
run: |
|
||||
. ports/.github/workflows/bootstrap.sh
|
||||
|
||||
# Add getopt, mpbb and the MacPorts paths to $PATH for the subsequent steps.
|
||||
echo "/opt/mports/bin" >> $GITHUB_PATH
|
||||
echo "${PWD}/mpbb" >> $GITHUB_PATH
|
||||
echo "/opt/local/bin" >> $GITHUB_PATH
|
||||
echo "/opt/local/sbin" >> $GITHUB_PATH
|
||||
|
||||
- name: Determine list of subports
|
||||
id: subportlist
|
||||
run: |
|
||||
set -eu
|
||||
port=Sunshine
|
||||
subportlist=""
|
||||
|
||||
echo "Listing subports for Sunshine"
|
||||
new_subports=$(mpbb \
|
||||
--work-dir /tmp/mpbb \
|
||||
list-subports \
|
||||
--archive-site= \
|
||||
--archive-site-private= \
|
||||
--include-deps=no \
|
||||
"$port" \
|
||||
| tr '\n' ' ')
|
||||
for subport in $new_subports; do
|
||||
echo "$subport"
|
||||
subportlist="$subportlist $subport"
|
||||
done
|
||||
echo "::set-output name=subportlist::${subportlist}"
|
||||
|
||||
- name: Run port lint for all subports
|
||||
run: |
|
||||
set -eu
|
||||
fail=0
|
||||
for subport in $subportlist; do
|
||||
echo "::group::${subport}"
|
||||
path=$(port file "$subport")
|
||||
messagetype="warning"
|
||||
if ! messages=$(port -q lint "$subport" 2>&1); then
|
||||
messagetype="error"
|
||||
fail=1
|
||||
fi
|
||||
if [ -n "$messages" ]; then
|
||||
echo "$messages"
|
||||
# See https://github.com/actions/toolkit/issues/193#issuecomment-605394935
|
||||
encoded_messages="port lint ${subport}:%0A"
|
||||
encoded_messages+="$(echo "${messages}" | sed -E 's/$/%0A/g' | tr -d '\n')"
|
||||
echo "::${messagetype} file=${path#${PWD}/ports/},line=1,col=1::${encoded_messages}"
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
exit "$fail"
|
||||
env:
|
||||
subportlist: ${{ steps.subportlist.outputs.subportlist }}
|
||||
|
||||
- name: Build subports
|
||||
run: |
|
||||
set -eu
|
||||
fail=0
|
||||
for subport in $subportlist; do
|
||||
workdir="/tmp/mpbb/$subport"
|
||||
mkdir -p "$workdir/logs"
|
||||
touch "$workdir/logs/dependencies-progress.txt"
|
||||
echo "::group::Cleaning up between ports"
|
||||
sudo mpbb --work-dir "$workdir" cleanup
|
||||
echo "::endgroup::"
|
||||
echo "::group::Installing dependencies for ${subport}"
|
||||
sudo mpbb \
|
||||
--work-dir "$workdir" \
|
||||
install-dependencies \
|
||||
"$subport" >"$workdir/logs/install-dependencies.log" 2>&1 &
|
||||
deps_pid=$!
|
||||
tail -f "$workdir/logs/dependencies-progress.txt" 2>/dev/null &
|
||||
tail_pid=$!
|
||||
set +e
|
||||
wait "$deps_pid"
|
||||
deps_exit=$?
|
||||
set -e
|
||||
kill "$tail_pid" || true
|
||||
if [ "$deps_exit" -ne 0 ]; then
|
||||
echo "::endgroup::"
|
||||
echo "::error::Failed to install dependencies for ${subport}"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
echo "::group::Installing ${subport}"
|
||||
set +e
|
||||
sudo mpbb \
|
||||
--work-dir "$workdir" \
|
||||
install-port \
|
||||
--source \
|
||||
"$subport"
|
||||
install_exit=$?
|
||||
set -e
|
||||
if [ "$install_exit" -ne 0 ]; then
|
||||
echo "::endgroup::"
|
||||
echo "::error::Failed to install ${subport}"
|
||||
fail=1
|
||||
continue
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
done
|
||||
exit "$fail"
|
||||
env:
|
||||
subportlist: ${{ steps.subportlist.outputs.subportlist }}
|
||||
|
||||
- name: Package
|
||||
run: |
|
||||
# create packages
|
||||
sudo port pkg sunshine
|
||||
sudo port dmg sunshine
|
||||
|
||||
work=$(port work sunshine)
|
||||
echo "Sunshine port work directory: ${work}"
|
||||
|
||||
# move components out of port work directory
|
||||
sudo mv ${work}/Sunshine*component.pkg /tmp/
|
||||
|
||||
# copy artifacts
|
||||
sudo mv ${work}/Sunshine*.pkg ./artifacts/sunshine.pkg
|
||||
sudo mv ${work}/Sunshine*.dmg ./artifacts/sunshine.dmg
|
||||
|
||||
# move components back
|
||||
# sudo mv /tmp/Sunshine*component.pkg ${work}/
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-macports
|
||||
path: artifacts/
|
||||
|
||||
- name: Create Release
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: LizardByte/.github/actions/create_release@master
|
||||
with:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
next_version: ${{ needs.check_changelog.outputs.next_version }}
|
||||
last_version: ${{ needs.check_changelog.outputs.last_version }}
|
||||
release_body: ${{ needs.check_changelog.outputs.release_body }}
|
||||
|
||||
build_win:
|
||||
name: Windows
|
||||
runs-on: windows-2019
|
||||
needs: check_changelog
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Dependencies Windows
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
update: true
|
||||
install: >-
|
||||
base-devel
|
||||
diffutils
|
||||
git
|
||||
make
|
||||
mingw-w64-x86_64-binutils
|
||||
mingw-w64-x86_64-boost
|
||||
mingw-w64-x86_64-cmake
|
||||
mingw-w64-x86_64-nsis
|
||||
mingw-w64-x86_64-openssl
|
||||
mingw-w64-x86_64-opus
|
||||
mingw-w64-x86_64-toolchain
|
||||
mingw-w64-x86_64-x265
|
||||
nasm
|
||||
yasm
|
||||
|
||||
- name: Build Windows
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release \
|
||||
-DSUNSHINE_ASSETS_DIR=assets \
|
||||
-DSUNSHINE_CONFIG_DIR=config \
|
||||
-G "MinGW Makefiles" \
|
||||
..
|
||||
mingw32-make -j2
|
||||
|
||||
- name: Package Windows
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
mkdir -p artifacts
|
||||
cd build
|
||||
|
||||
# package
|
||||
cpack -G NSIS
|
||||
cpack -G ZIP
|
||||
|
||||
# move
|
||||
mv ./cpack_artifacts/Sunshine.exe ../artifacts/sunshine-windows.exe
|
||||
mv ./cpack_artifacts/Sunshine.zip ../artifacts/sunshine-windows.zip
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: sunshine-windows
|
||||
path: artifacts/
|
||||
|
||||
- name: Create Release
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: LizardByte/.github/actions/create_release@master
|
||||
with:
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
next_version: ${{ needs.check_changelog.outputs.next_version }}
|
||||
last_version: ${{ needs.check_changelog.outputs.last_version }}
|
||||
release_body: ${{ needs.check_changelog.outputs.release_body }}
|
||||
31
.github/workflows/auto-create-pr.yml
vendored
Normal file
31
.github/workflows/auto-create-pr.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Auto create PR
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'nightly'
|
||||
|
||||
jobs:
|
||||
create_pr:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: repo-sync/pull-request@v2
|
||||
with:
|
||||
source_branch: "" # should be "nightly" as it's the triggering branch
|
||||
destination_branch: "master"
|
||||
pr_title: "Pulling ${{ github.ref_name }} into master"
|
||||
pr_template: ".github/pr_release_template.md"
|
||||
pr_assignee: "${{ secrets.GH_BOT_NAME }}"
|
||||
pr_draft: true
|
||||
pr_allow_empty: false
|
||||
github_token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
59
.github/workflows/automerge.yml
vendored
Normal file
59
.github/workflows/automerge.yml
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Automerge PR
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
autoapprove:
|
||||
if: >
|
||||
contains(fromJson('["LizardByte-bot"]'), github.event.pull_request.user.login) &&
|
||||
contains(fromJson('["LizardByte-bot"]'), github.actor)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Autoapproving
|
||||
uses: hmarr/auto-approve-action@v2
|
||||
with:
|
||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
|
||||
- name: Label autoapproved
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['autoapproved', 'autoupdate']
|
||||
})
|
||||
|
||||
automerge:
|
||||
needs: [autoapprove]
|
||||
runs-on: ubuntu-latest
|
||||
concurrency:
|
||||
group: automerge-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Automerging
|
||||
uses: pascalgn/automerge-action@v0.15.3
|
||||
env:
|
||||
BASE_BRANCHES: nightly
|
||||
GITHUB_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
|
||||
GITHUB_LOGIN: ${{ secrets.GH_BOT_NAME }}
|
||||
MERGE_LABELS: ""
|
||||
MERGE_METHOD: "squash"
|
||||
MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})"
|
||||
MERGE_DELETE_BRANCH: true
|
||||
MERGE_ERROR_FAIL: true
|
||||
MERGE_FILTER_AUTHOR: ${{ secrets.GH_BOT_NAME }}
|
||||
MERGE_RETRIES: "240" # 1 hour
|
||||
MERGE_RETRY_SLEEP: "15000" # 15 seconds
|
||||
32
.github/workflows/autoupdate.yml
vendored
Normal file
32
.github/workflows/autoupdate.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
# This workflow is designed to work with:
|
||||
# - automerge workflows
|
||||
|
||||
# It uses GitHub Action that auto-updates pull requests branches, when changes are pushed to their destination branch.
|
||||
# Auto-updating to the latest destination branch works only in the context of upstream repo and not forks.
|
||||
|
||||
name: autoupdate
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'nightly'
|
||||
|
||||
jobs:
|
||||
autoupdate-for-bot:
|
||||
name: Autoupdate autoapproved PR created in the upstream
|
||||
if: startsWith(github.repository, 'LizardByte/')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update
|
||||
uses: docker://chinthakagodawita/autoupdate-action:v1
|
||||
env:
|
||||
GITHUB_TOKEN: '${{ secrets.GH_BOT_TOKEN }}'
|
||||
PR_FILTER: "labelled"
|
||||
PR_LABELS: "autoupdate"
|
||||
PR_READY_STATE: "ready_for_review"
|
||||
MERGE_CONFLICT_ACTION: "ignore"
|
||||
60
.github/workflows/cpp-clang-format-lint.yml
vendored
Normal file
60
.github/workflows/cpp-clang-format-lint.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Clang Format Lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, nightly]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
check_src:
|
||||
name: Check src
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Check
|
||||
id: check
|
||||
run: |
|
||||
if [ -d "./src" ]
|
||||
then
|
||||
FOUND=true
|
||||
else
|
||||
FOUND=false
|
||||
fi
|
||||
|
||||
echo "::set-output name=src::${FOUND}"
|
||||
|
||||
outputs:
|
||||
src: ${{ steps.check.outputs.src }}
|
||||
|
||||
lint:
|
||||
name: Clang Format Lint
|
||||
needs: [check_src]
|
||||
if: ${{ needs.check_src.outputs.src == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Clang format lint
|
||||
uses: DoozyX/clang-format-lint-action@v0.14
|
||||
with:
|
||||
source: './src'
|
||||
extensions: 'cpp,h,m,mm'
|
||||
clangFormatVersion: 13
|
||||
style: file
|
||||
inplace: false
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: clang-format-fixes
|
||||
path: src/
|
||||
54
.github/workflows/issues-stale.yml
vendored
Normal file
54
.github/workflows/issues-stale.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Stale Issues / PRs
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '00 00 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Check Stale Issues / PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Stale
|
||||
uses: actions/stale@v5
|
||||
with:
|
||||
close-issue-message: >
|
||||
This issue was closed because it has been stalled for 5 days with no activity.
|
||||
close-pr-message: >
|
||||
This PR was closed because it has been stalled for 10 days with no activity.
|
||||
days-before-stale: 90
|
||||
days-before-close: 10
|
||||
exempt-all-assignees: true
|
||||
exempt-issue-labels: 'added,fixed'
|
||||
exempt-pr-labels: 'dependencies,l10n'
|
||||
stale-issue-label: 'stale'
|
||||
stale-issue-message: >
|
||||
This issue is stale because it has been open for 30 days with no activity.
|
||||
Comment or remove the stale label, otherwise this will be closed in 5 days.
|
||||
stale-pr-label: 'stale'
|
||||
stale-pr-message: >
|
||||
This PR is stale because it has been open for 90 days with no activity.
|
||||
Comment or remove the stale label, otherwise this will be closed in 10 days.
|
||||
|
||||
- name: Invalid Template
|
||||
uses: actions/stale@v5
|
||||
with:
|
||||
close-issue-message: >
|
||||
This issue was closed because the the template was not completed after 5 days.
|
||||
close-pr-message: >
|
||||
This PR was closed because the the template was not completed after 5 days.
|
||||
days-before-stale: 0
|
||||
days-before-close: 5
|
||||
exempt-pr-labels: 'dependencies,l10n'
|
||||
only-labels: 'invalid:template-incomplete'
|
||||
stale-issue-label: 'invalid:template-incomplete'
|
||||
stale-issue-message: >
|
||||
Invalid issues template.
|
||||
stale-pr-label: 'invalid:template-incomplete'
|
||||
stale-pr-message: >
|
||||
Invalid PR template.
|
||||
22
.github/workflows/issues.yml
vendored
Normal file
22
.github/workflows/issues.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Issues
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [labeled, unlabeled]
|
||||
discussion:
|
||||
types: [labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
label:
|
||||
name: Label Actions
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label Actions
|
||||
uses: dessant/label-actions@v2
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
95
.github/workflows/localize.yml
vendored
Normal file
95
.github/workflows/localize.yml
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
---
|
||||
name: localize
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [nightly]
|
||||
paths: # prevents workflow from running unless these files change
|
||||
- '.github/workflows/localize.yml'
|
||||
- 'src/**'
|
||||
- 'locale/sunshine.po'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
file: ./locale/sunshine.po
|
||||
|
||||
jobs:
|
||||
localize:
|
||||
name: Update Localization
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Python 3.9
|
||||
uses: actions/setup-python@v4 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.9'
|
||||
|
||||
- name: Set up Python 3.9 Dependencies
|
||||
run: |
|
||||
cd ./scripts
|
||||
python -m pip install --upgrade pip setuptools
|
||||
python -m pip install -r requirements.txt
|
||||
|
||||
- name: Set up xgettext
|
||||
run: |
|
||||
sudo apt-get update -y && \
|
||||
sudo apt-get --reinstall install -y \
|
||||
gettext
|
||||
|
||||
- name: Update Strings
|
||||
run: |
|
||||
# first, try to remove existing file as xgettext does not remove unused translations
|
||||
if [ -f "${{ env.file }}" ];
|
||||
then
|
||||
rm ${{ env.file }}
|
||||
echo "new_file=false" >> $GITHUB_ENV
|
||||
else
|
||||
echo "new_file=true" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
# extract the new strings
|
||||
python ./scripts/_locale.py --extract
|
||||
|
||||
- name: git diff
|
||||
if: ${{ env.new_file == 'false' }}
|
||||
run: |
|
||||
# disable the pager
|
||||
git config --global pager.diff false
|
||||
|
||||
# print the git diff
|
||||
git diff locale/sunshine.po
|
||||
|
||||
# set the variable with minimal output
|
||||
OUTPUT=$(git diff --numstat locale/sunshine.po)
|
||||
echo "git_diff=${OUTPUT}" >> $GITHUB_ENV
|
||||
|
||||
- name: git reset
|
||||
# only run if a single line changed (date/time) and file already existed
|
||||
# \t in next line is a tab character
|
||||
if: ${{ env.git_diff == '1\t1\tlocale/sunshine.po' && env.new_file == 'false' }}
|
||||
run: |
|
||||
git reset --hard
|
||||
|
||||
- name: Create/Update Pull Request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
add-paths: |
|
||||
locale/*.po
|
||||
token: ${{ secrets.GH_BOT_TOKEN }} # must trigger PR tests
|
||||
commit-message: New localization template
|
||||
branch: localize/update
|
||||
delete-branch: true
|
||||
base: nightly
|
||||
title: New Babel Updates
|
||||
body: |
|
||||
Update report
|
||||
- Updated with *today's* date
|
||||
- Auto-generated by [create-pull-request][1]
|
||||
|
||||
[1]: https://github.com/peter-evans/create-pull-request
|
||||
labels: |
|
||||
babel
|
||||
l10n
|
||||
27
.github/workflows/pull-requests.yml
vendored
Normal file
27
.github/workflows/pull-requests.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Pull Requests
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, edited, reopened]
|
||||
|
||||
jobs:
|
||||
check-pull-request:
|
||||
name: Check Pull Request
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Vankka/pr-target-branch-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
target: master
|
||||
exclude: nightly # Don't prevent going from nightly -> master
|
||||
change-to: nightly
|
||||
comment: |
|
||||
Your PR was set to `master`, PRs should be sent to `nightly`.
|
||||
The base branch of this PR has been automatically changed to `nightly`.
|
||||
Please check that there are no merge conflicts
|
||||
31
.github/workflows/python-flake8.yml
vendored
Normal file
31
.github/workflows/python-flake8.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: flake8
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, nightly]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
flake8:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4 # https://github.com/actions/setup-python
|
||||
with:
|
||||
python-version: '3.10'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools flake8
|
||||
|
||||
- name: Test with flake8
|
||||
run: |
|
||||
python -m flake8 --verbose
|
||||
81
.github/workflows/release-notifier.yml
vendored
Normal file
81
.github/workflows/release-notifier.yml
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: Release Notifications
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
# https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#onevent_nametypes
|
||||
|
||||
jobs:
|
||||
discord:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: discord
|
||||
uses: sarisia/actions-status-discord@v1 # https://github.com/sarisia/actions-status-discord
|
||||
with:
|
||||
webhook: ${{ secrets.DISCORD_RELEASE_WEBHOOK }}
|
||||
nodetail: true
|
||||
nofail: false
|
||||
username: ${{ secrets.DISCORD_USERNAME }}
|
||||
avatar_url: ${{ secrets.ORG_LOGO_URL }}
|
||||
title: ${{ github.event.repository.name }} ${{ github.ref_name }} Released
|
||||
description: ${{ github.event.release.body }}
|
||||
color: 0xFF4500
|
||||
|
||||
facebook_group:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: facebook-post-action
|
||||
uses: ReenigneArcher/facebook-post-action@v1 # https://github.com/ReenigneArcher/facebook-post-action
|
||||
with:
|
||||
page_id: ${{ secrets.FACEBOOK_GROUP_ID }}
|
||||
access_token: ${{ secrets.FACEBOOK_ACCESS_TOKEN }}
|
||||
message: |
|
||||
${{ github.event.repository.name }} ${{ github.ref_name }} Released
|
||||
${{ github.event.release.body }}
|
||||
url: ${{ github.event.release.html_url }}
|
||||
|
||||
facebook_page:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: facebook-post-action
|
||||
uses: ReenigneArcher/facebook-post-action@v1 # https://github.com/ReenigneArcher/facebook-post-action
|
||||
with:
|
||||
page_id: ${{ secrets.FACEBOOK_PAGE_ID }}
|
||||
access_token: ${{ secrets.FACEBOOK_ACCESS_TOKEN }}
|
||||
message: |
|
||||
${{ github.event.repository.name }} ${{ github.ref_name }} Released
|
||||
${{ github.event.release.body }}
|
||||
url: ${{ github.event.release.html_url }}
|
||||
|
||||
reddit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: reddit
|
||||
uses: bluwy/release-for-reddit-action@v1 # https://github.com/bluwy/release-for-reddit-action
|
||||
with:
|
||||
username: ${{ secrets.REDDIT_USERNAME }}
|
||||
password: ${{ secrets.REDDIT_PASSWORD }}
|
||||
app-id: ${{ secrets.REDDIT_CLIENT_ID }}
|
||||
app-secret: ${{ secrets.REDDIT_CLIENT_SECRET }}
|
||||
subreddit: ${{ secrets.REDDIT_SUBREDDIT }}
|
||||
title: ${{ github.event.repository.name }} ${{ github.ref_name }} Released
|
||||
url: ${{ github.event.release.html_url }}
|
||||
flair-id: ${{ secrets.REDDIT_FLAIR_ID }} # https://www.reddit.com/r/<subreddit>>/api/link_flair.json
|
||||
comment: ${{ github.event.release.body }}
|
||||
|
||||
twitter:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: twitter
|
||||
uses: ethomson/send-tweet-action@v1 # https://github.com/ethomson/send-tweet-action
|
||||
with:
|
||||
consumer-key: ${{ secrets.TWITTER_API_KEY }}
|
||||
consumer-secret: ${{ secrets.TWITTER_API_SECRET }}
|
||||
access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}
|
||||
access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
|
||||
status: ${{ github.event.release.html_url }}
|
||||
17
.github/workflows/winget.yml
vendored
Normal file
17
.github/workflows/winget.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Publish to WinGet
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
jobs:
|
||||
winget-releaser:
|
||||
name: winget releaser
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: winget releaser
|
||||
uses: vedantmgoyal2009/winget-releaser@latest
|
||||
with:
|
||||
identifier: LizardByte.Sunshine
|
||||
token: ${{ secrets.GH_BOT_TOKEN }}
|
||||
46
.github/workflows/yaml-lint.yml
vendored
Normal file
46
.github/workflows/yaml-lint.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
# This action is centrally managed in https://github.com/<organization>/.github/
|
||||
# Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in
|
||||
# the above-mentioned repo.
|
||||
|
||||
name: yaml lint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [master, nightly]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
yaml-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: yaml lint
|
||||
id: yaml-lint
|
||||
uses: ibiqlik/action-yamllint@v3
|
||||
with:
|
||||
# https://yamllint.readthedocs.io/en/stable/configuration.html#default-configuration
|
||||
config_data: |
|
||||
extends: default
|
||||
rules:
|
||||
comments:
|
||||
level: error
|
||||
line-length:
|
||||
max: 120
|
||||
truthy:
|
||||
allowed-values: ['true', 'false', 'on'] # GitHub uses "on" for workflow event triggers
|
||||
check-keys: true
|
||||
level: error
|
||||
|
||||
- name: Log
|
||||
run: |
|
||||
echo ${{ steps.yaml-lint.outputs.logfile }}
|
||||
|
||||
- name: Upload logs
|
||||
uses: actions/upload-artifact@v2
|
||||
if: failure()
|
||||
with:
|
||||
name: yamllint-logfile
|
||||
path: ${{ steps.yaml-lint.outputs.logfile }}
|
||||
16
.gitignore
vendored
16
.gitignore
vendored
@@ -7,4 +7,18 @@ cmake-build*
|
||||
*.kdev4
|
||||
|
||||
.cache
|
||||
.idea
|
||||
.idea
|
||||
|
||||
# Extra FontAwesome files
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/css/*.css
|
||||
!/src_assets/common/assets/web/fonts/fontawesome-free-web/css/*min.css
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/js/
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/less/
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/metadata/
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/scss/
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/sprites/
|
||||
/src_assets/common/assets/web/fonts/fontawesome-free-web/svgs/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -10,3 +10,9 @@
|
||||
[submodule "third-party/miniupnp"]
|
||||
path = third-party/miniupnp
|
||||
url = https://github.com/miniupnp/miniupnp
|
||||
[submodule "third-party/nv-codec-headers"]
|
||||
path = third-party/nv-codec-headers
|
||||
url = https://github.com/FFmpeg/nv-codec-headers
|
||||
[submodule "third-party/TPCircularBuffer"]
|
||||
path = third-party/TPCircularBuffer
|
||||
url = https://github.com/michaeltyson/TPCircularBuffer
|
||||
|
||||
1
.prettierrc.json
Normal file
1
.prettierrc.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
45
.readthedocs.yaml
Normal file
45
.readthedocs.yaml
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
# .readthedocs.yaml
|
||||
# Read the Docs configuration file
|
||||
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||
|
||||
# Required
|
||||
version: 2
|
||||
|
||||
# Set the version of Python
|
||||
build:
|
||||
os: ubuntu-20.04
|
||||
tools:
|
||||
python: "3.9"
|
||||
|
||||
## apt packages required packages to run cmake on sunshine, note that additional packages are required
|
||||
# apt_packages:
|
||||
# - cmake
|
||||
# - ffmpeg
|
||||
# - libboost-filesystem-dev
|
||||
# - libboost-log-dev
|
||||
# - libboost-thread-dev
|
||||
|
||||
## run cmake
|
||||
# jobs:
|
||||
# pre_build:
|
||||
# - cmake .
|
||||
|
||||
## Include the submodules, required for cmake
|
||||
# submodules:
|
||||
# include: all
|
||||
# recursive: true
|
||||
|
||||
# Build documentation in the docs/ directory with Sphinx
|
||||
sphinx:
|
||||
builder: html
|
||||
configuration: docs/source/conf.py
|
||||
fail_on_warning: true
|
||||
|
||||
# Using Sphinx, build docs in additional formats
|
||||
formats: all
|
||||
|
||||
python:
|
||||
install:
|
||||
- requirements: ./scripts/requirements.txt
|
||||
system_packages: true
|
||||
152
CHANGELOG.md
Normal file
152
CHANGELOG.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Changelog
|
||||
|
||||
## [0.14.1] - 2022-08-09
|
||||
### Added
|
||||
- (Linux) Flatpak package added
|
||||
- (Linux) AUR package automated updates
|
||||
- (Windows) Winget package automated updates
|
||||
### Changed
|
||||
- (General) Moved repo to @LizardByte GitHub org
|
||||
- (WebUI) Fixed button spacing on home page
|
||||
- (WebUI) Added Discord WidgetBot Crate
|
||||
### Fixed
|
||||
- (Linux/Mac) Default config and app files now copied to user home directory
|
||||
- (Windows) Default config and app files now copied to working directory
|
||||
|
||||
## [0.14.0] - 2022-06-15
|
||||
### Added
|
||||
- (Documentation) Added Sphinx documentation available at https://sunshinestream.readthedocs.io/en/latest/
|
||||
- (Development) Initial support for Localization
|
||||
- (Linux) Add rpm package as release asset
|
||||
- (MacOS) Add Portfile as release asset
|
||||
- (Windows) Add DwmFlush() call to improve capture
|
||||
- (Windows) Add Windows installer
|
||||
### Fixed
|
||||
- (AMD) Fixed hwdevice being destroyed before context
|
||||
- (Linux) Added missing dependencies to AppImage
|
||||
- (Linux) Fixed rumble events causing game to freeze
|
||||
- (Linux) Improved Pulse/Pipewire compatibility
|
||||
- (Linux) Moved to single deb package
|
||||
- (MacOS) Fixed missing TPCircularBuffer submodule
|
||||
- (Stream) Properly catch exceptions in stream broadcast handlers
|
||||
- (Stream/Video) AVPacket fix
|
||||
|
||||
## [0.13.0] - 2022-02-27
|
||||
### Added
|
||||
- (MacOS) Initial support for MacOS (#40)
|
||||
|
||||
## [0.12.0] - 2022-02-13
|
||||
### Added
|
||||
- New command line argument `--version`
|
||||
- Custom png poster support
|
||||
### Changed
|
||||
- Correct software bitrate calculation
|
||||
- Increase vbv-bufsize to 1/10 of requested bitrate
|
||||
- Improvements to Web UI
|
||||
|
||||
## [0.11.1] - 2021-10-04
|
||||
### Changed
|
||||
- (Linux) Fix search path for config file and assets
|
||||
|
||||
## [0.11.0] - 2021-10-04
|
||||
### Added
|
||||
- (Linux) Added support for wlroots based compositors on Wayland.
|
||||
- (Windows) Added an icon for the executable
|
||||
### Changed
|
||||
- Fixed a bug causing segfault when connecting multiple controllers.
|
||||
- (Linux) Improved NVENC, it now offloads converting images from RGB to NV12
|
||||
- (Linux) Fixed a bug causes stuttering
|
||||
|
||||
## [0.10.1] - 2021-08-21
|
||||
### Changed
|
||||
- (Linux) Re-enabled KMS
|
||||
|
||||
## [0.10.0] - 2021-08-20
|
||||
### Added
|
||||
- Added support for Rumble with gamepads.
|
||||
- Added support for keyboard shortcuts <--- See the README for details.
|
||||
- (Windows) A very basic script has been added in Sunshine-Windows\tools <-- This will start Sunshine at boot with the highest privileges which is needed to display the login prompt.
|
||||
### Changed
|
||||
- Some cosmetic changes to the WebUI.
|
||||
- The first time the WebUI is opened, it will request the creation of a username/password pair from the user.
|
||||
- Fixed audio crackling introduced in version 0.8.0
|
||||
- (Linux) VAAPI hardware encoding now works on Intel i7-6700 at least. <-- For the best experience, using ffmpeg version 4.3 or higher is recommended.
|
||||
- (Windows) Installing from debian package shouldn't overwrite your configuration files anymore. <-- It's recommended that you back up `/etc/sunshine/` before testing this.
|
||||
|
||||
## [0.9.0] - 2021-07-11
|
||||
### Added
|
||||
- Added audio encryption
|
||||
- (Linux) Added basic NVENC support on Linux
|
||||
- (Windows) The Windows version can now capture the lock screen and the UAC prompt as long as it's run through `PsExec.exe` https://docs.microsoft.com/en-us/sysinternals/downloads/psexec
|
||||
### Changed
|
||||
- Sunshine will now accept expired or not-yet-valid certificates, as long as they are signed properly.
|
||||
- Fixed compatibility with iOS version of Moonlight
|
||||
- Drastically reduced chance of being forced to skip error correction due to video frame size
|
||||
- (Linux) sunshine.service will be installed automatically.
|
||||
|
||||
## [0.8.0] - 2021-06-30
|
||||
### Added
|
||||
- Added mDNS support: Moonlight will automatically find Sunshine.
|
||||
- Added UPnP support. It's off by default.
|
||||
|
||||
## [0.7.7] - 2021-06-24
|
||||
### Added
|
||||
- (Linux) Added installation package for Debian
|
||||
### Changed
|
||||
- Fixed incorrect scaling for absolute mouse coordinates when using multiple monitors.
|
||||
- Fixed incorrect colors when scaling for software encoder
|
||||
|
||||
## [0.7.1] - 2021-06-18
|
||||
### Changed
|
||||
- (Linux) Fixed an issue where it was impossible to start sunshine on ubuntu 20.04
|
||||
|
||||
## [0.7.0] - 2021-06-16
|
||||
### Added
|
||||
- Added a Web Manager. Accessible through: https://localhost:47990 or https://<ip of your pc>:47990
|
||||
- (Linux) Added hardware encoding support for AMD on Linux
|
||||
### Changed
|
||||
- (Linux) Moved certificates and saved pairings generated during runtime to .config/sunshine on Linux
|
||||
|
||||
## [0.6.0] - 2021-05-26
|
||||
### Added
|
||||
- Added support for surround audio
|
||||
### Changed
|
||||
- Maintain aspect ratio when scaling video
|
||||
- Fix issue where Sunshine is forced to drop frames when they are too large
|
||||
|
||||
## [0.5.0] - 2021-05-13
|
||||
### Added
|
||||
- Added support for absolute mouse coordinates
|
||||
- (Linux) Added support for streaming specific monitor on Linux
|
||||
- (Windows) Added support for AMF on Windows
|
||||
|
||||
## [0.4.0] - 2020-05-03
|
||||
### Changed
|
||||
- prep-cmd is now optional in apps.json
|
||||
- Fixed bug causing video artifacts
|
||||
- Fixed bug preventing Moonlight from closing app on exit
|
||||
- Fixed bug causing preventing keyboard keys from repeating on latest version of Moonlight
|
||||
- Fixed bug causing segfault when another session of sunshine was already running
|
||||
- Fixed bug causing crash when monitor has resolution 1366x768
|
||||
|
||||
## [0.3.1] - 2020-04-24
|
||||
### Changed
|
||||
- Fix a memory leak.
|
||||
|
||||
## [0.3.0] - 2020-04-23
|
||||
### Changed
|
||||
- Hardware acceleration on NVidia GPU's for Video encoding on Windows
|
||||
|
||||
## [0.2.0] - 2020-03-21
|
||||
### Changed
|
||||
- Multicasting is now supported: You can set the maximum simultaneous connections with the configurable option: channels
|
||||
- Configuration variables can be overwritten on the command line: "name=value" --> it can be useful to set min_log_level=debug without modifying the configuration file
|
||||
- Switches to make testing the pairing mechanism more convenient has been added, see "sunshine --help" for details
|
||||
|
||||
## [0.1.1] - 2020-01-30
|
||||
### Added
|
||||
- (Linux) Added deb package and service for Linux
|
||||
|
||||
## [0.1.0] - 2020-01-27
|
||||
### Added
|
||||
- The first official release for Sunshine!
|
||||
587
CMakeLists.txt
587
CMakeLists.txt
@@ -1,9 +1,62 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(Sunshine)
|
||||
project(Sunshine VERSION 0.14.1
|
||||
DESCRIPTION "Sunshine is a Gamestream host for Moonlight."
|
||||
HOMEPAGE_URL "https://app.lizardbyte.dev"
|
||||
)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(PROJECT_LONG_DESCRIPTION "Sunshine is a self hosted, low latency, cloud gaming solution with support for AMD, \
|
||||
Intel, and Nvidia GPUs. It is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield. \
|
||||
Connect to Sunshine from any Moonlight client, available for nearly any device imaginable.")
|
||||
|
||||
option(SUNSHINE_CONFIGURE_APPIMAGE "Configure files required for AppImage." OFF)
|
||||
option(SUNSHINE_CONFIGURE_AUR "Configure files required for AUR." OFF)
|
||||
option(SUNSHINE_CONFIGURE_FLATPAK "Configure files required for Flatpak." OFF)
|
||||
option(SUNSHINE_CONFIGURE_PORTFILE "Configure macOS Portfile." OFF)
|
||||
option(SUNSHINE_CONFIGURE_ONLY "Configure special files only, then exit." OFF)
|
||||
|
||||
if(${SUNSHINE_CONFIGURE_APPIMAGE})
|
||||
configure_file(packaging/linux/sunshine.desktop sunshine.desktop @ONLY)
|
||||
elseif(${SUNSHINE_CONFIGURE_AUR})
|
||||
configure_file(packaging/linux/aur/PKGBUILD PKGBUILD @ONLY)
|
||||
elseif(${SUNSHINE_CONFIGURE_FLATPAK})
|
||||
configure_file(packaging/linux/flatpak/dev.lizardbyte.sunshine.yml dev.lizardbyte.sunshine.yml @ONLY)
|
||||
elseif(${SUNSHINE_CONFIGURE_PORTFILE})
|
||||
configure_file(packaging/macos/Portfile Portfile @ONLY)
|
||||
endif()
|
||||
|
||||
# return if configure only is set
|
||||
if(${SUNSHINE_CONFIGURE_ONLY})
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
set(SUNSHINE_SOURCE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src_assets")
|
||||
|
||||
if(WIN32)
|
||||
# Ugly hack to compile with #include <qos2.h>
|
||||
add_compile_definitions(
|
||||
QOS_FLOWID=UINT32
|
||||
PQOS_FLOWID=UINT32*
|
||||
QOS_NON_ADAPTIVE_FLOW=2)
|
||||
endif()
|
||||
if(APPLE)
|
||||
macro(ADD_FRAMEWORK fwname appname)
|
||||
find_library(FRAMEWORK_${fwname}
|
||||
NAMES ${fwname}
|
||||
PATHS ${CMAKE_OSX_SYSROOT}/System/Library
|
||||
PATH_SUFFIXES Frameworks
|
||||
NO_DEFAULT_PATH)
|
||||
if( ${FRAMEWORK_${fwname}} STREQUAL FRAMEWORK_${fwname}-NOTFOUND)
|
||||
MESSAGE(ERROR ": Framework ${fwname} not found")
|
||||
else()
|
||||
TARGET_LINK_LIBRARIES(${appname} "${FRAMEWORK_${fwname}}/${fwname}")
|
||||
MESSAGE(STATUS "Framework ${fwname} found at ${FRAMEWORK_${fwname}}")
|
||||
endif()
|
||||
endmacro(ADD_FRAMEWORK)
|
||||
endif()
|
||||
|
||||
add_subdirectory(third-party/moonlight-common-c/enet)
|
||||
add_subdirectory(third-party/Simple-Web-Server)
|
||||
|
||||
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "no shared libraries")
|
||||
@@ -13,21 +66,18 @@ set(UPNPC_NO_INSTALL ON CACHE BOOL "Don't install any libraries build for miniup
|
||||
add_subdirectory(third-party/miniupnp/miniupnpc)
|
||||
include_directories(third-party/miniupnp)
|
||||
|
||||
if(WIN32)
|
||||
# Ugly hack to compile with #include <qos2.h>
|
||||
add_compile_definitions(
|
||||
QOS_FLOWID=UINT32
|
||||
PQOS_FLOWID=UINT32*
|
||||
QOS_NON_ADAPTIVE_FLOW=2)
|
||||
endif()
|
||||
add_subdirectory(third-party/moonlight-common-c/enet)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
if(NOT APPLE)
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
find_package(Boost COMPONENTS log filesystem REQUIRED)
|
||||
|
||||
list(APPEND SUNSHINE_COMPILE_OPTIONS -fPIC -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare)
|
||||
list(APPEND SUNSHINE_COMPILE_OPTIONS -Wall -Wno-missing-braces -Wno-maybe-uninitialized -Wno-sign-compare)
|
||||
|
||||
if(WIN32)
|
||||
enable_language(RC)
|
||||
set(CMAKE_RC_COMPILER windres)
|
||||
file(
|
||||
DOWNLOAD "https://github.com/TheElixZammuto/sunshine-prebuilt/releases/download/1.0.0/pre-compiled.zip" "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||
TIMEOUT 60
|
||||
@@ -37,7 +87,7 @@ if(WIN32)
|
||||
INPUT "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled.zip"
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/pre-compiled)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
|
||||
|
||||
if(NOT DEFINED SUNSHINE_PREPARED_BINARIES)
|
||||
set(SUNSHINE_PREPARED_BINARIES "${CMAKE_CURRENT_BINARY_DIR}/pre-compiled/windows")
|
||||
endif()
|
||||
@@ -45,20 +95,23 @@ if(WIN32)
|
||||
add_compile_definitions(SUNSHINE_PLATFORM="windows")
|
||||
add_subdirectory(tools) #This is temporary, only tools for Windows are needed, for now
|
||||
|
||||
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_windows.json")
|
||||
|
||||
include_directories(third-party/ViGEmClient/include)
|
||||
|
||||
if(NOT DEFINED SUNSHINE_ICON_PATH)
|
||||
set(SUNSHINE_ICON_PATH "${CMAKE_CURRENT_SOURCE_DIR}/sunshine.ico")
|
||||
endif()
|
||||
configure_file(src/platform/windows/windows.rs.in windows.rc @ONLY)
|
||||
set(PLATFORM_TARGET_FILES
|
||||
sunshine/platform/windows/publish.cpp
|
||||
sunshine/platform/windows/misc.h
|
||||
sunshine/platform/windows/misc.cpp
|
||||
sunshine/platform/windows/input.cpp
|
||||
sunshine/platform/windows/display.h
|
||||
sunshine/platform/windows/display_base.cpp
|
||||
sunshine/platform/windows/display_vram.cpp
|
||||
sunshine/platform/windows/display_ram.cpp
|
||||
sunshine/platform/windows/audio.cpp
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/windows.rc"
|
||||
src/platform/windows/publish.cpp
|
||||
src/platform/windows/misc.h
|
||||
src/platform/windows/misc.cpp
|
||||
src/platform/windows/input.cpp
|
||||
src/platform/windows/display.h
|
||||
src/platform/windows/display_base.cpp
|
||||
src/platform/windows/display_vram.cpp
|
||||
src/platform/windows/display_ram.cpp
|
||||
src/platform/windows/audio.cpp
|
||||
third-party/ViGEmClient/src/ViGEmClient.cpp
|
||||
third-party/ViGEmClient/include/ViGEm/Client.h
|
||||
third-party/ViGEmClient/include/ViGEm/Common.h
|
||||
@@ -89,72 +142,212 @@ if(WIN32)
|
||||
libstdc++.a
|
||||
libwinpthread.a
|
||||
libssp.a
|
||||
Qwave
|
||||
winmm
|
||||
ksuser
|
||||
wsock32
|
||||
ws2_32
|
||||
iphlpapi
|
||||
d3d11 dxgi D3DCompiler
|
||||
setupapi
|
||||
dnsapi
|
||||
dwmapi
|
||||
)
|
||||
|
||||
set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp PROPERTIES COMPILE_DEFINITIONS "UNICODE=1;ERROR_INVALID_DEVICE_OBJECT_PARAMETER=650")
|
||||
set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp PROPERTIES COMPILE_FLAGS "-Wno-unknown-pragmas -Wno-misleading-indentation -Wno-class-memaccess")
|
||||
else()
|
||||
add_compile_definitions(SUNSHINE_PLATFORM="linux")
|
||||
list(APPEND SUNSHINE_DEFINITIONS APPS_JSON="apps_linux.json")
|
||||
elseif(APPLE)
|
||||
add_compile_definitions(SUNSHINE_PLATFORM="macos")
|
||||
|
||||
option(SUNSHINE_MACOS_PACKAGE "Should only be used when creating a MACOS package/dmg." OFF)
|
||||
|
||||
link_directories(/opt/local/lib)
|
||||
link_directories(/usr/local/lib)
|
||||
ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
|
||||
|
||||
find_package(X11 REQUIRED)
|
||||
find_package(FFmpeg REQUIRED)
|
||||
FIND_LIBRARY(APP_SERVICES_LIBRARY ApplicationServices )
|
||||
FIND_LIBRARY(AV_FOUNDATION_LIBRARY AVFoundation )
|
||||
FIND_LIBRARY(CORE_MEDIA_LIBRARY CoreMedia )
|
||||
FIND_LIBRARY(CORE_VIDEO_LIBRARY CoreVideo )
|
||||
FIND_LIBRARY(FOUNDATION_LIBRARY Foundation )
|
||||
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||
${APP_SERVICES_LIBRARY}
|
||||
${AV_FOUNDATION_LIBRARY}
|
||||
${CORE_MEDIA_LIBRARY}
|
||||
${CORE_VIDEO_LIBRARY}
|
||||
${FOUNDATION_LIBRARY})
|
||||
|
||||
set(PLATFORM_INCLUDE_DIRS
|
||||
${Boost_INCLUDE_DIR})
|
||||
|
||||
set(APPLE_PLIST_FILE ${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/Info.plist)
|
||||
|
||||
set(PLATFORM_TARGET_FILES
|
||||
sunshine/platform/linux/publish.cpp
|
||||
sunshine/platform/linux/vaapi.h
|
||||
sunshine/platform/linux/vaapi.cpp
|
||||
sunshine/platform/linux/misc.h
|
||||
sunshine/platform/linux/misc.cpp
|
||||
sunshine/platform/linux/display.cpp
|
||||
sunshine/platform/linux/audio.cpp
|
||||
sunshine/platform/linux/input.cpp
|
||||
src/platform/macos/av_audio.h
|
||||
src/platform/macos/av_audio.m
|
||||
src/platform/macos/av_img_t.h
|
||||
src/platform/macos/av_video.h
|
||||
src/platform/macos/av_video.m
|
||||
src/platform/macos/display.mm
|
||||
src/platform/macos/input.cpp
|
||||
src/platform/macos/microphone.mm
|
||||
src/platform/macos/misc.cpp
|
||||
src/platform/macos/misc.h
|
||||
src/platform/macos/nv12_zero_device.cpp
|
||||
src/platform/macos/nv12_zero_device.h
|
||||
src/platform/macos/publish.cpp
|
||||
third-party/TPCircularBuffer/TPCircularBuffer.c
|
||||
third-party/TPCircularBuffer/TPCircularBuffer.h
|
||||
${APPLE_PLIST_FILE})
|
||||
else()
|
||||
add_compile_definitions(SUNSHINE_PLATFORM="linux")
|
||||
|
||||
option(SUNSHINE_ENABLE_DRM "Enable KMS grab if available" ON)
|
||||
option(SUNSHINE_ENABLE_X11 "Enable X11 grab if available" ON)
|
||||
option(SUNSHINE_ENABLE_WAYLAND "Enable building wayland specific code" ON)
|
||||
option(SUNSHINE_ENABLE_CUDA "Enable cuda specific code" ON)
|
||||
|
||||
if(${SUNSHINE_ENABLE_X11})
|
||||
find_package(X11)
|
||||
else()
|
||||
set(X11_FOUND OFF)
|
||||
endif()
|
||||
|
||||
set(CUDA_FOUND OFF)
|
||||
if(${SUNSHINE_ENABLE_CUDA})
|
||||
include(CheckLanguage)
|
||||
check_language(CUDA)
|
||||
|
||||
if(CMAKE_CUDA_COMPILER)
|
||||
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
|
||||
set(CMAKE_CUDA_ARCHITECTURES 35)
|
||||
endif()
|
||||
|
||||
set(CUDA_FOUND ON)
|
||||
enable_language(CUDA)
|
||||
endif()
|
||||
endif()
|
||||
if(${SUNSHINE_ENABLE_DRM})
|
||||
find_package(LIBDRM)
|
||||
find_package(LIBCAP)
|
||||
else()
|
||||
set(LIBDRM_FOUND OFF)
|
||||
set(LIBCAP_FOUND OFF)
|
||||
endif()
|
||||
if(${SUNSHINE_ENABLE_WAYLAND})
|
||||
find_package(Wayland)
|
||||
else()
|
||||
set(WAYLAND_FOUND OFF)
|
||||
endif()
|
||||
|
||||
find_package(FFMPEG REQUIRED)
|
||||
|
||||
if(X11_FOUND)
|
||||
add_compile_definitions(SUNSHINE_BUILD_X11)
|
||||
include_directories(${X11_INCLUDE_DIR})
|
||||
list(APPEND PLATFORM_TARGET_FILES src/platform/linux/x11grab.cpp)
|
||||
endif()
|
||||
|
||||
if(CUDA_FOUND)
|
||||
include_directories(third-party/nvfbc)
|
||||
list(APPEND PLATFORM_TARGET_FILES
|
||||
src/platform/linux/cuda.cu
|
||||
src/platform/linux/cuda.cpp
|
||||
third-party/nvfbc/NvFBC.h)
|
||||
|
||||
add_compile_definitions(SUNSHINE_BUILD_CUDA)
|
||||
endif()
|
||||
|
||||
if(LIBDRM_FOUND AND LIBCAP_FOUND)
|
||||
add_compile_definitions(SUNSHINE_BUILD_DRM)
|
||||
include_directories(${LIBDRM_INCLUDE_DIRS} ${LIBCAP_INCLUDE_DIRS})
|
||||
list(APPEND PLATFORM_LIBRARIES ${LIBDRM_LIBRARIES} ${LIBCAP_LIBRARIES})
|
||||
list(APPEND PLATFORM_TARGET_FILES src/platform/linux/kmsgrab.cpp)
|
||||
list(APPEND SUNSHINE_DEFINITIONS EGL_NO_X11=1)
|
||||
elseif(LIBDRM_FOUND)
|
||||
message(WARNING "Found libdrm, yet there is no libcap")
|
||||
elseif(LIBDRM_FOUND)
|
||||
message(WARNING "Found libcap, yet there is no libdrm")
|
||||
endif()
|
||||
|
||||
if(WAYLAND_FOUND)
|
||||
add_compile_definitions(SUNSHINE_BUILD_WAYLAND)
|
||||
macro(genWayland FILENAME)
|
||||
make_directory(${CMAKE_BINARY_DIR}/generated-src)
|
||||
|
||||
message("wayland-scanner private-code ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c")
|
||||
message("wayland-scanner client-header ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h")
|
||||
execute_process(
|
||||
COMMAND wayland-scanner private-code ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c
|
||||
COMMAND wayland-scanner client-header ${CMAKE_SOURCE_DIR}/third-party/wayland-protocols/${FILENAME}.xml ${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h
|
||||
|
||||
RESULT_VARIABLE EXIT_INT
|
||||
)
|
||||
|
||||
if(NOT ${EXIT_INT} EQUAL 0)
|
||||
message(FATAL_ERROR "wayland-scanner failed")
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_TARGET_FILES
|
||||
${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.c
|
||||
${CMAKE_BINARY_DIR}/generated-src/${FILENAME}.h
|
||||
)
|
||||
endmacro()
|
||||
|
||||
genWayland(xdg-output-unstable-v1)
|
||||
genWayland(wlr-export-dmabuf-unstable-v1)
|
||||
|
||||
include_directories(
|
||||
${WAYLAND_INCLUDE_DIRS}
|
||||
${CMAKE_BINARY_DIR}/generated-src
|
||||
)
|
||||
|
||||
list(APPEND PLATFORM_LIBRARIES ${WAYLAND_LIBRARIES})
|
||||
list(APPEND PLATFORM_TARGET_FILES
|
||||
src/platform/linux/wlgrab.cpp
|
||||
src/platform/linux/wayland.cpp)
|
||||
endif()
|
||||
if(NOT ${X11_FOUND} AND NOT (${LIBDRM_FOUND} AND ${LIBCAP_FOUND}) AND NOT ${WAYLAND_FOUND} AND NOT ${})
|
||||
message(FATAL_ERROR "Couldn't find either x11, wayland, cuda or (libdrm and libcap)")
|
||||
endif()
|
||||
|
||||
list(APPEND PLATFORM_TARGET_FILES
|
||||
src/platform/linux/publish.cpp
|
||||
src/platform/linux/vaapi.h
|
||||
src/platform/linux/vaapi.cpp
|
||||
src/platform/linux/cuda.h
|
||||
src/platform/linux/graphics.h
|
||||
src/platform/linux/graphics.cpp
|
||||
src/platform/linux/misc.h
|
||||
src/platform/linux/misc.cpp
|
||||
src/platform/linux/audio.cpp
|
||||
src/platform/linux/input.cpp
|
||||
src/platform/linux/x11grab.h
|
||||
src/platform/linux/wayland.h
|
||||
third-party/glad/src/egl.c
|
||||
third-party/glad/src/gl.c
|
||||
third-party/glad/include/EGL/eglplatform.h
|
||||
third-party/glad/include/KHR/khrplatform.h
|
||||
third-party/glad/include/glad/gl.h
|
||||
third-party/glad/include/glad/egl.h)
|
||||
|
||||
set(PLATFORM_LIBRARIES
|
||||
Xfixes
|
||||
Xtst
|
||||
xcb
|
||||
xcb-shm
|
||||
xcb-xfixes
|
||||
Xrandr
|
||||
${X11_LIBRARIES}
|
||||
|
||||
list(APPEND PLATFORM_LIBRARIES
|
||||
dl
|
||||
evdev
|
||||
pulse
|
||||
pulse-simple
|
||||
)
|
||||
|
||||
set(PLATFORM_INCLUDE_DIRS
|
||||
${X11_INCLUDE_DIR}
|
||||
|
||||
include_directories(
|
||||
/usr/include/libevdev-1.0
|
||||
third-party/nv-codec-headers/include
|
||||
third-party/glad/include)
|
||||
|
||||
if(NOT DEFINED SUNSHINE_EXECUTABLE_PATH)
|
||||
set(SUNSHINE_EXECUTABLE_PATH "sunshine")
|
||||
endif()
|
||||
configure_file(gen-deb.in gen-deb @ONLY)
|
||||
configure_file(sunshine.service.in sunshine.service @ONLY)
|
||||
endif()
|
||||
|
||||
add_subdirectory(third-party/cbs)
|
||||
|
||||
set(Boost_USE_STATIC_LIBS ON)
|
||||
find_package(Boost COMPONENTS log filesystem REQUIRED)
|
||||
configure_file(version.h.in version.h @ONLY)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(SUNSHINE_TARGET_FILES
|
||||
third-party/moonlight-common-c/reedsolomon/rs.c
|
||||
@@ -163,47 +356,47 @@ set(SUNSHINE_TARGET_FILES
|
||||
third-party/moonlight-common-c/src/Rtsp.h
|
||||
third-party/moonlight-common-c/src/RtspParser.c
|
||||
third-party/moonlight-common-c/src/Video.h
|
||||
sunshine/upnp.cpp
|
||||
sunshine/upnp.h
|
||||
sunshine/cbs.cpp
|
||||
sunshine/utility.h
|
||||
sunshine/uuid.h
|
||||
sunshine/config.h
|
||||
sunshine/config.cpp
|
||||
sunshine/main.cpp
|
||||
sunshine/main.h
|
||||
sunshine/crypto.cpp
|
||||
sunshine/crypto.h
|
||||
sunshine/nvhttp.cpp
|
||||
sunshine/nvhttp.h
|
||||
sunshine/httpcommon.cpp
|
||||
sunshine/httpcommon.h
|
||||
sunshine/confighttp.cpp
|
||||
sunshine/confighttp.h
|
||||
sunshine/rtsp.cpp
|
||||
sunshine/rtsp.h
|
||||
sunshine/stream.cpp
|
||||
sunshine/stream.h
|
||||
sunshine/video.cpp
|
||||
sunshine/video.h
|
||||
sunshine/input.cpp
|
||||
sunshine/input.h
|
||||
sunshine/audio.cpp
|
||||
sunshine/audio.h
|
||||
sunshine/platform/common.h
|
||||
sunshine/process.cpp
|
||||
sunshine/process.h
|
||||
sunshine/network.cpp
|
||||
sunshine/network.h
|
||||
sunshine/move_by_copy.h
|
||||
sunshine/task_pool.h
|
||||
sunshine/thread_pool.h
|
||||
sunshine/thread_safe.h
|
||||
sunshine/sync.h
|
||||
sunshine/round_robin.h
|
||||
src/upnp.cpp
|
||||
src/upnp.h
|
||||
src/cbs.cpp
|
||||
src/utility.h
|
||||
src/uuid.h
|
||||
src/config.h
|
||||
src/config.cpp
|
||||
src/main.cpp
|
||||
src/main.h
|
||||
src/crypto.cpp
|
||||
src/crypto.h
|
||||
src/nvhttp.cpp
|
||||
src/nvhttp.h
|
||||
src/httpcommon.cpp
|
||||
src/httpcommon.h
|
||||
src/confighttp.cpp
|
||||
src/confighttp.h
|
||||
src/rtsp.cpp
|
||||
src/rtsp.h
|
||||
src/stream.cpp
|
||||
src/stream.h
|
||||
src/video.cpp
|
||||
src/video.h
|
||||
src/input.cpp
|
||||
src/input.h
|
||||
src/audio.cpp
|
||||
src/audio.h
|
||||
src/platform/common.h
|
||||
src/process.cpp
|
||||
src/process.h
|
||||
src/network.cpp
|
||||
src/network.h
|
||||
src/move_by_copy.h
|
||||
src/task_pool.h
|
||||
src/thread_pool.h
|
||||
src/thread_safe.h
|
||||
src/sync.h
|
||||
src/round_robin.h
|
||||
${PLATFORM_TARGET_FILES})
|
||||
|
||||
set_source_files_properties(sunshine/upnp.cpp PROPERTIES COMPILE_FLAGS -Wno-pedantic)
|
||||
set_source_files_properties(src/upnp.cpp PROPERTIES COMPILE_FLAGS -Wno-pedantic)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
@@ -215,11 +408,13 @@ include_directories(
|
||||
${PLATFORM_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_subdirectory(third-party/cbs)
|
||||
|
||||
string(TOUPPER "x${CMAKE_BUILD_TYPE}" BUILD_TYPE)
|
||||
if("${BUILD_TYPE}" STREQUAL "XDEBUG")
|
||||
list(APPEND SUNSHINE_COMPILE_OPTIONS -O0 -pedantic -ggdb3)
|
||||
list(APPEND SUNSHINE_COMPILE_OPTIONS -O0 -ggdb3)
|
||||
if(WIN32)
|
||||
set_source_files_properties(sunshine/nvhttp.cpp PROPERTIES COMPILE_FLAGS -O2)
|
||||
set_source_files_properties(src/nvhttp.cpp PROPERTIES COMPILE_FLAGS -O2)
|
||||
endif()
|
||||
else()
|
||||
add_definitions(-DNDEBUG)
|
||||
@@ -227,7 +422,16 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT SUNSHINE_ASSETS_DIR)
|
||||
set(SUNSHINE_ASSETS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/assets")
|
||||
set(SUNSHINE_ASSETS_DIR "${CMAKE_CURRENT_BINARY_DIR}/assets")
|
||||
endif()
|
||||
|
||||
if(NOT SUNSHINE_CONFIG_DIR)
|
||||
set(SUNSHINE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/config")
|
||||
endif()
|
||||
|
||||
if(UNIX AND CMAKE_INSTALL_PREFIX AND NOT ${SUNSHINE_CONFIGURE_APPIMAGE})
|
||||
set(SUNSHINE_ASSETS_DIR "${CMAKE_INSTALL_PREFIX}/${SUNSHINE_ASSETS_DIR}")
|
||||
set(SUNSHINE_CONFIG_DIR "${CMAKE_INSTALL_PREFIX}/${SUNSHINE_CONFIG_DIR}")
|
||||
endif()
|
||||
|
||||
list(APPEND CBS_EXTERNAL_LIBRARIES
|
||||
@@ -237,7 +441,6 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||
libminiupnpc-static
|
||||
${CBS_EXTERNAL_LIBRARIES}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
stdc++fs
|
||||
enet
|
||||
opus
|
||||
${FFMPEG_LIBRARIES}
|
||||
@@ -245,10 +448,182 @@ list(APPEND SUNSHINE_EXTERNAL_LIBRARIES
|
||||
${OPENSSL_LIBRARIES}
|
||||
${PLATFORM_LIBRARIES})
|
||||
|
||||
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_ASSETS_DIR="${SUNSHINE_ASSETS_DIR}")
|
||||
add_executable(sunshine ${SUNSHINE_TARGET_FILES})
|
||||
target_link_libraries(sunshine ${SUNSHINE_EXTERNAL_LIBRARIES})
|
||||
target_compile_definitions(sunshine PUBLIC ${SUNSHINE_DEFINITIONS})
|
||||
set_target_properties(sunshine PROPERTIES CXX_STANDARD 17)
|
||||
if(NOT WIN32)
|
||||
list(APPEND SUNSHINE_EXTERNAL_LIBRARIES Boost::log)
|
||||
endif()
|
||||
|
||||
target_compile_options(sunshine PRIVATE ${SUNSHINE_COMPILE_OPTIONS})
|
||||
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_ASSETS_DIR="${SUNSHINE_ASSETS_DIR}")
|
||||
list(APPEND SUNSHINE_DEFINITIONS SUNSHINE_CONFIG_DIR="${SUNSHINE_CONFIG_DIR}")
|
||||
add_executable(sunshine ${SUNSHINE_TARGET_FILES})
|
||||
target_link_libraries(sunshine ${SUNSHINE_EXTERNAL_LIBRARIES} ${EXTRA_LIBS})
|
||||
target_compile_definitions(sunshine PUBLIC ${SUNSHINE_DEFINITIONS})
|
||||
set_target_properties(sunshine PROPERTIES CXX_STANDARD 17
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION ${PROJECT_VERSION_MAJOR}
|
||||
)
|
||||
|
||||
if(NOT DEFINED CMAKE_CUDA_STANDARD)
|
||||
set(CMAKE_CUDA_STANDARD 17)
|
||||
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_link_options(sunshine PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${APPLE_PLIST_FILE})
|
||||
endif()
|
||||
|
||||
foreach(flag IN LISTS SUNSHINE_COMPILE_OPTIONS)
|
||||
list(APPEND SUNSHINE_COMPILE_OPTIONS_CUDA "$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${flag}>")
|
||||
endforeach()
|
||||
|
||||
target_compile_options(sunshine PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${SUNSHINE_COMPILE_OPTIONS}>;$<$<COMPILE_LANGUAGE:CUDA>:${SUNSHINE_COMPILE_OPTIONS_CUDA};-std=c++17>)
|
||||
|
||||
# CPACK / Packaging
|
||||
|
||||
# Common options
|
||||
set(CPACK_PACKAGE_NAME "Sunshine")
|
||||
set(CPACK_PACKAGE_VENDOR "LizardByte")
|
||||
set(CPACK_PACKAGE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/cpack_artifacts)
|
||||
set(CPACK_PACKAGE_CONTACT "https://app.lizardbyte.dev")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "https://github.com/LizardByte")
|
||||
set(CPACK_PACKAGE_DESCRIPTION ${CMAKE_PROJECT_DESCRIPTION})
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL ${CMAKE_PROJECT_HOMEPAGE_URL})
|
||||
set(CPACK_RESOURCE_FILE_LICENSE ${PROJECT_SOURCE_DIR}/LICENSE)
|
||||
set(CPACK_PACKAGE_ICON ${PROJECT_SOURCE_DIR}/sunshine.png)
|
||||
set(CPACK_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_STRIP_FILES YES)
|
||||
|
||||
# Platform specific options
|
||||
if(WIN32) # see options at: https://cmake.org/cmake/help/latest/cpack_gen/nsis.html
|
||||
install(TARGETS sunshine RUNTIME DESTINATION "." COMPONENT application)
|
||||
|
||||
# Adding tools
|
||||
install(TARGETS dxgi-info RUNTIME DESTINATION "tools" COMPONENT dxgi)
|
||||
install(TARGETS audio-info RUNTIME DESTINATION "tools" COMPONENT audio)
|
||||
install(TARGETS sunshinesvc RUNTIME DESTINATION "tools" COMPONENT sunshinesvc)
|
||||
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}" COMPONENT assets)
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}" COMPONENT assets)
|
||||
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}" COMPONENT config)
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/windows/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}" COMPONENT config)
|
||||
|
||||
|
||||
# set(CPACK_NSIS_MUI_HEADERIMAGE "") # TODO: image should be 150x57 bmp
|
||||
|
||||
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}\\\\sunshine.ico")
|
||||
set(CPACK_NSIS_INSTALLED_ICON_NAME "${PROJECT__DIR}\\\\${PROJECT_EXE}")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") # The name of the directory that will be created in C:/Program files/
|
||||
string(APPEND CPACK_NSIS_DEFINES "\n RequestExecutionLevel admin") # TODO: Not sure if this is needed but it took me a while to figure out where to put this option so I'm leaving it here
|
||||
|
||||
# Sets permissions on the installed folder so that we can write in it
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS
|
||||
"${CPACK_NSIS_EXTRA_INSTALL_COMMANDS}
|
||||
ExecWait 'icacls \\\"$INSTDIR\\\" /grant:r Users:\\\(OI\\\)\\\(CI\\\)\\\(F\\\)'
|
||||
")
|
||||
|
||||
# Adding an option for the start menu and PATH
|
||||
set(CPACK_NSIS_MODIFY_PATH "OFF") # TODO: it asks to add it to the PATH but is not working https://gitlab.kitware.com/cmake/cmake/-/issues/15635
|
||||
set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".")
|
||||
set(CPACK_NSIS_MUI_FINISHPAGE_RUN "${CMAKE_PROJECT_NAME}.exe")
|
||||
set(CPACK_NSIS_INSTALLED_ICON_NAME "${CMAKE_PROJECT_NAME}.exe") # This will be shown on the installed apps Windows settings
|
||||
set(CPACK_NSIS_CREATE_ICONS "CreateShortCut '\$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\${CMAKE_PROJECT_NAME}.lnk' '\$INSTDIR\\\\${CMAKE_PROJECT_NAME}.exe'")
|
||||
|
||||
# Checking for previous installed versions
|
||||
# set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL "ON") # TODO: doesn't work on my machine when Sunshine is already installed
|
||||
|
||||
# Setting components groups and dependencies
|
||||
# sunshine binary
|
||||
set(CPACK_COMPONENT_APPLICATION_DISPLAY_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_COMPONENT_APPLICATION_DESCRIPTION "The main application.")
|
||||
set(CPACK_COMPONENT_APPLICATION_GROUP "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_COMPONENT_APPLICATION_REQUIRED true)
|
||||
set(CPACK_COMPONENT_APPLICATION_DEPENDS assets)
|
||||
|
||||
# assets
|
||||
set(CPACK_COMPONENT_ASSETS_DISPLAY_NAME "Assets")
|
||||
set(CPACK_COMPONENT_ASSETS_DESCRIPTION "Shaders, default box art, and web ui.")
|
||||
set(CPACK_COMPONENT_ASSETS_GROUP "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_COMPONENT_ASSETS_REQUIRED true)
|
||||
|
||||
# config
|
||||
set(CPACK_COMPONENT_CONFIG_DISPLAY_NAME "Config")
|
||||
set(CPACK_COMPONENT_CONFIG_DESCRIPTION "Default config and apps.json files.")
|
||||
set(CPACK_COMPONENT_CONFIG_GROUP "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_COMPONENT_CONFIG_REQUIRED true)
|
||||
|
||||
# audio tool
|
||||
set(CPACK_COMPONENT_AUDIO_DISPLAY_NAME "audio-info.exe")
|
||||
set(CPACK_COMPONENT_AUDIO_DESCRIPTION "CLI tool that allows you to get information about sound devices.")
|
||||
set(CPACK_COMPONENT_AUDIO_GROUP "Tools")
|
||||
|
||||
# display tool
|
||||
set(CPACK_COMPONENT_DXGI_DISPLAY_NAME "dxgi-info.exe")
|
||||
set(CPACK_COMPONENT_DXGI_DESCRIPTION "CLI tool that allows you to get information about graphics cards and displays.")
|
||||
set(CPACK_COMPONENT_DXGI_GROUP "Tools")
|
||||
|
||||
# service tool
|
||||
set(CPACK_COMPONENT_SUNSHINESVC_DISPLAY_NAME "sunshinesvc.exe")
|
||||
set(CPACK_COMPONENT_SUNSHINESVC_DESCRIPTION "CLI tool that allows you to enable/disable the Sunshine service.")
|
||||
set(CPACK_COMPONENT_SUNSHINESVC_GROUP "Tools")
|
||||
endif()
|
||||
if(APPLE)
|
||||
# TODO: bundle doesn't produce a valid .app use cpack -G DragNDrop
|
||||
set(CPACK_BUNDLE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_BUNDLE_PLIST "${APPLE_PLIST_FILE}")
|
||||
set(CPACK_BUNDLE_ICON "${PROJECT_SOURCE_DIR}/sunshine.icns")
|
||||
# set(CPACK_BUNDLE_STARTUP_COMMAND "${INSTALL_RUNTIME_DIR}/sunshine")
|
||||
endif()
|
||||
if(APPLE AND SUNSHINE_MACOS_PACKAGE) # TODO
|
||||
set(prefix "${CMAKE_PROJECT_NAME}.app/Contents")
|
||||
set(INSTALL_RUNTIME_DIR "${prefix}/MacOS")
|
||||
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}")
|
||||
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}")
|
||||
|
||||
install(TARGETS sunshine
|
||||
BUNDLE DESTINATION . COMPONENT Runtime
|
||||
RUNTIME DESTINATION ${INSTALL_RUNTIME_DIR} COMPONENT Runtime)
|
||||
elseif(UNIX)
|
||||
# Installation destination dir
|
||||
set(CPACK_SET_DESTDIR true)
|
||||
if(NOT CMAKE_INSTALL_PREFIX)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local/sunshine")
|
||||
endif()
|
||||
|
||||
install(TARGETS sunshine RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/common/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}")
|
||||
|
||||
if(APPLE)
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}")
|
||||
|
||||
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/macos/misc/uninstall_pkg.sh" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
else()
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/assets/" DESTINATION "${SUNSHINE_ASSETS_DIR}")
|
||||
install(DIRECTORY "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/config/" DESTINATION "${SUNSHINE_CONFIG_DIR}")
|
||||
|
||||
install(FILES "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/85-sunshine.rules" DESTINATION "${CMAKE_INSTALL_LIBDIR}/udev/rules.d")
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sunshine.service" DESTINATION "${CMAKE_INSTALL_LIBDIR}/systemd/user")
|
||||
|
||||
# Pre and post install
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA
|
||||
"${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/preinst"
|
||||
"${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst"
|
||||
"${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/conffiles")
|
||||
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/preinst")
|
||||
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${SUNSHINE_SOURCE_ASSETS_DIR}/linux/misc/postinst")
|
||||
|
||||
# Dependencies
|
||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "openssl, libavdevice58, libboost-thread1.67.0 | libboost-thread1.71.0 | libboost-thread1.74.0, libboost-filesystem1.67.0 | libboost-filesystem1.71.0 | libboost-filesystem1.74.0, libboost-log1.67.0 | libboost-log1.71.0 | libboost-log1.74.0, libpulse0, libopus0, libxcb-shm0, libxcb-xfixes0, libxtst6, libevdev2, libdrm2, libcap2")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "openssl >= 1.1, libavdevice >= 4.3, boost-thread >= 1.67.0, boost-filesystem >= 1.67.0, boost-log >= 1.67.0, pulseaudio-libs >= 10.0, libopusenc >= 0.2.1, libxcb >= 1.13, libXtst >= 1.2.3, libevdev >= 1.5.6, libdrm >= 2.4.97, libcap >= 2.22")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) # This should automatically figure out dependencies, doesn't work with the current config
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
|
||||
101
DOCKER_README.md
Normal file
101
DOCKER_README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# Docker
|
||||
|
||||
## Using docker run
|
||||
Create and run the container (substitute your `<values>`):
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name=sunshine \
|
||||
--restart=unless-stopped
|
||||
-v <path to data>:/config \
|
||||
-e PUID=<uid> \
|
||||
-e PGID=<gid> \
|
||||
-e TZ=<timezone> \
|
||||
-p 47984-47990:47984-47990/tcp \
|
||||
-p 48010:48010 \
|
||||
-p 47998-48000:47998-48000/udp \
|
||||
lizardbyte/sunshine
|
||||
```
|
||||
|
||||
To update the container it must be removed and recreated:
|
||||
|
||||
```bash
|
||||
# Stop the container
|
||||
docker stop sunshine
|
||||
# Remove the container
|
||||
docker rm sunshine
|
||||
# Pull the latest update
|
||||
docker pull lizardbyte/sunshine
|
||||
# Run the container with the same parameters as before
|
||||
docker run -d ...
|
||||
```
|
||||
|
||||
## Using docker-compose
|
||||
|
||||
Create a `docker-compose.yml` file with the following contents (substitute your `<values>`):
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
sunshine:
|
||||
image: lizardbyte/sunshine
|
||||
container_name: sunshine
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- <path to data>:/config
|
||||
environment:
|
||||
- PUID=<uid>
|
||||
- PGID=<gid>
|
||||
- TZ=<timezone>
|
||||
ports:
|
||||
- 47984-47990:47984-47990/tcp
|
||||
- 48010:48010
|
||||
- 47998-48000:47998-48000/udp
|
||||
```
|
||||
|
||||
Create and start the container (run the command from the same folder as your `docker-compose.yml` file):
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
To update the container:
|
||||
```bash
|
||||
# Pull the latest update
|
||||
docker-compose pull
|
||||
# Update and restart the container
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## Parameters
|
||||
You must substitute the `<values>` with your own settings.
|
||||
|
||||
Parameters are split into two halves separated by a colon. The left side represents the host and the right side the
|
||||
container.
|
||||
|
||||
**Example:** `-p external:internal` - This shows the port mapping from internal to external of the container.
|
||||
Therefore `-p 47990:47990` would expose port `47990` from inside the container to be accessible from the host's IP on
|
||||
port `47990` (e.g. `http://<host_ip>:47990`). The internal port must be `47990`, but the external port may be changed
|
||||
(e.g. `-p 8080:47990`). All the ports listed in the `docker run` and `docker-compose` examples are required.
|
||||
|
||||
|
||||
| Parameter | Function | Example Value | Required |
|
||||
| --------------------------- | -------------------- | ------------------- | -------- |
|
||||
| `-p <port>:47990` | Web UI Port | `47990` | True |
|
||||
| `-v <path to data>:/config` | Volume mapping | `/home/sunshine` | True |
|
||||
| `-e PUID=<uid>` | User ID | `1001` | False |
|
||||
| `-e PGID=<gid>` | Group ID | `1001` | False |
|
||||
| `-e TZ=<timezone>` | Lookup TZ value [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) | `America/New_York` | True |
|
||||
|
||||
### User / Group Identifiers:
|
||||
|
||||
When using data volumes (-v flags) permissions issues can arise between the host OS and the container. To avoid this
|
||||
issue you can specify the user PUID and group PGID. Ensure the data volume directory on the host is owned by the same
|
||||
user you specify.
|
||||
|
||||
In this instance `PUID=1001` and `PGID=1001`. To find yours use id user as below:
|
||||
|
||||
```bash
|
||||
$ id dockeruser
|
||||
uid=1001(dockeruser) gid=1001(dockergroup) groups=1001(dockergroup)
|
||||
```
|
||||
3
NOTICE
Normal file
3
NOTICE
Normal file
@@ -0,0 +1,3 @@
|
||||
©2018 Valve Corporation. Steam and the Steam logo are trademarks and/or
|
||||
registered trademarks of Valve Corporation in the U.S. and/or other countries. All
|
||||
rights reserved.
|
||||
199
README.md
199
README.md
@@ -1,199 +0,0 @@
|
||||
# Introduction
|
||||
Sunshine is a Gamestream host for Moonlight
|
||||
|
||||
[](https://ci.appveyor.com/project/loki-47-6F-64/sunshine/branch/master)
|
||||
[](https://github.com/Loki-47-6F-64/sunshine/releases)
|
||||
|
||||
- [Building](README.md#building)
|
||||
- [Credits](README.md#credits)
|
||||
|
||||
# Building
|
||||
- [Linux](README.md#linux)
|
||||
- [Windows](README.md#windows-10)
|
||||
|
||||
## Linux
|
||||
|
||||
### Requirements:
|
||||
Ubuntu 20.04:
|
||||
Install the following
|
||||
```
|
||||
sudo apt install cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
||||
```
|
||||
|
||||
### Compilation:
|
||||
- `git clone https://github.com/loki-47-6F-64/sunshine.git --recurse-submodules`
|
||||
- `cd sunshine && mkdir build && cd build`
|
||||
- `cmake ..`
|
||||
- `make -j ${nproc}`
|
||||
|
||||
|
||||
### Setup:
|
||||
sunshine needs access to uinput to create mouse and gamepad events:
|
||||
- Add user to group 'input':
|
||||
`usermod -a -G input $USER`
|
||||
- Create udev rules:
|
||||
- Run the following command:
|
||||
`nano /etc/udev/rules.d/85-sunshine-input.rules`
|
||||
- Input the following contents:
|
||||
`KERNEL=="uinput", GROUP="input", MODE="0660"`
|
||||
- Save the file and exit
|
||||
1. `CTRL+X` to start exit
|
||||
2. `Y` to save modifications
|
||||
- `assets/sunshine.conf` is an example configuration file. Modify it as you see fit, then use it by running:
|
||||
`sunshine path/to/sunshine.conf`
|
||||
- Configure autostart service
|
||||
`path/to/build/dir/sunshine.service` is used to start sunshine in the background. To use it, do the following:
|
||||
1. Copy it to the users systemd, `cp sunshine.service ~/.config/systemd/user/`
|
||||
2. Starting
|
||||
- Onetime:
|
||||
`systemctl --user start sunshine`
|
||||
- Always on boot:
|
||||
`systemctl --user enable sunshine`
|
||||
|
||||
- `assets/apps.json` is an [example](README.md#application-list) of a list of applications that are started just before running a stream
|
||||
|
||||
### Trouleshooting:
|
||||
- If you get "Could not create Sunshine Gamepad: Permission Denied", ensure you are part of the group "input":
|
||||
- `groups $USER`
|
||||
|
||||
- If Sunshine sends audio from the microphone instead of the speaker, try the following steps:
|
||||
1. `$ pacmd list-sources | grep "name:"` or `$ pactl info | grep Source` if running pipewire.
|
||||
2. Copy the name to the configuration option "audio_sink"
|
||||
3. restart sunshine
|
||||
|
||||
## Windows 10
|
||||
|
||||
### Requirements:
|
||||
|
||||
mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git mingw-w64-x86_64-make
|
||||
|
||||
### Compilation:
|
||||
- `git clone https://github.com/loki-47-6F-64/sunshine.git --recursive`
|
||||
- `cd sunshine && mkdir build && cd build`
|
||||
- `cmake -G"Unix Makefiles" ..`
|
||||
- `mingw32-make`
|
||||
|
||||
### Setup:
|
||||
- **OPTIONAL** Gamepad support: Download and run 'ViGEmBus_Setup_1.16.116.exe' from [https://github.com/ViGEm/ViGEmBus/releases]
|
||||
|
||||
|
||||
|
||||
# Common
|
||||
|
||||
## Usage:
|
||||
- run "sunshine path/to/sunshine.conf"
|
||||
- If running for the first time, make sure to note the username and password Sunshine showed to you, since you **cannot get back later**!
|
||||
- In Moonlight: Add PC manually
|
||||
- When Moonlight request you insert the correct pin on sunshine:
|
||||
- Type in the URL bar of your browser: `https://xxx.xxx.xxx.xxx:47990` where `xxx.xxx.xxx.xxx` is the IP address of your computer
|
||||
- Ignore any warning given by your browser about "insecure website"
|
||||
- Type in the username and password shown the first time you run Sunshine
|
||||
- Go to "PIN" in the Header
|
||||
- Type in your PIN and press Enter, you should get a Success Message
|
||||
- Click on one of the Applications listed
|
||||
- Have fun :)
|
||||
|
||||
|
||||
## Note:
|
||||
- The Windows key is not passed through by Moonlight, therefore Sunshine maps Right-Alt key to the Windows key
|
||||
- If you set Video Bitrate to 0.5Mb/s:
|
||||
- Sunshine will use CRF or QP to controll the quality of the stream. (See example configuration file for more details)
|
||||
- This is less CPU intensive and it has lower average bandwith requirements compared to manually setting bitrate to acceptable quality
|
||||
- However, it has higher peak bitrates, forcing Sunshine to drop entire frames when streaming 1080P due to their size.
|
||||
- When this happens, the video portion of the stream appears to be frozen.
|
||||
- This is rare enough that using this for the desktop environment is tolerable (in my opinion), however for gaming not so much.
|
||||
|
||||
|
||||
## Credits:
|
||||
- [Simple-Web-Server](https://gitlab.com/eidheim/Simple-Web-Server)
|
||||
- [Moonlight](https://github.com/moonlight-stream)
|
||||
- [Looking-Glass](https://github.com/gnif/LookingGlass) (For showing me how to properly capture frames on Windows, saving me a lot of time :)
|
||||
- [Eretik](http://eretik.omegahg.com/) (For creating PolicyConfig.h, allowing me to change the default audio device on Windows programmatically)
|
||||
|
||||
## Application List:
|
||||
**Note:** You can change the Application List in the "Apps" section of the User Interface `https://xxx.xxx.xxx.xxx:47990/`
|
||||
- You can use Environment variables in place of values
|
||||
- $(HOME) will be replaced by the value of $HOME
|
||||
- $$ will be replaced by $ --> $$(HOME) will be replaced by $(HOME)
|
||||
- env: Adds or overwrites Environment variables for the commands/applications run by Sunshine.
|
||||
- "Variable name":"Variable value"
|
||||
- apps: The list of applications
|
||||
- Example:
|
||||
```json
|
||||
{
|
||||
"name":"An App",
|
||||
"cmd":"command to open app",
|
||||
"prep-cmd":[
|
||||
{
|
||||
"do":"some-command",
|
||||
"undo":"undo-that-command"
|
||||
}
|
||||
],
|
||||
"detached":[
|
||||
"some-command",
|
||||
"another-command"
|
||||
]
|
||||
}
|
||||
```
|
||||
- name: Self explanatory
|
||||
- output <optional>: The file where the output of the command is stored
|
||||
- If it is not specified, the output is ignored
|
||||
- detached: A list of commands to be run and forgotten about
|
||||
- prep-cmd: A list of commands to be run before/after the application
|
||||
- If any of the prep-commands fail, starting the application is aborted
|
||||
- do: Run before the application
|
||||
- If it fails, all 'undo' commands of the previously succeeded 'do' commands are run
|
||||
- undo <optional>: Run after the application has terminated
|
||||
- This should not fail considering it is supposed to undo the 'do' commands.
|
||||
- If it fails, Sunshine is terminated
|
||||
- cmd <optional>: The main application
|
||||
- If not specified, a processs is started that sleeps indefinitely
|
||||
|
||||
1. When an application is started, if there is an application already running, it will be terminated.
|
||||
2. When the application has been shutdown, the stream shuts down as well.
|
||||
3. In addition to the apps listed, one app "Desktop" is hardcoded into Sunshine. It does not start an application, instead it simply starts a stream.
|
||||
|
||||
Linux
|
||||
```json
|
||||
{
|
||||
"env":{
|
||||
"DISPLAY":":0",
|
||||
"DRI_PRIME":"1",
|
||||
"XAUTHORITY":"$(HOME)/.Xauthority",
|
||||
"PATH":"$(PATH):$(HOME)/.local/bin"
|
||||
},
|
||||
"apps":[
|
||||
{
|
||||
"name":"Low Res Desktop",
|
||||
"prep-cmd":[
|
||||
{ "do":"xrandr --output HDMI-1 --mode 1920x1080", "undo":"xrandr --output HDMI-1 --mode 1920x1200" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"name":"Steam BigPicture",
|
||||
|
||||
"output":"steam.txt",
|
||||
"cmd":"steam -bigpicture",
|
||||
"prep-cmd":[]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Windows
|
||||
```json
|
||||
{
|
||||
"env":{
|
||||
"PATH":"$(PATH);C:\\Program Files (x86)\\Steam"
|
||||
},
|
||||
"apps":[
|
||||
{
|
||||
"name":"Steam BigPicture",
|
||||
|
||||
"output":"steam.txt",
|
||||
"prep-cmd":[
|
||||
{"do":"steam \"steam://open/bigpicture\""}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
67
README.rst
Normal file
67
README.rst
Normal file
@@ -0,0 +1,67 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/README.rst
|
||||
|
||||
Overview
|
||||
========
|
||||
LizardByte has the full documentation hosted on `Read the Docs <https://docs.lizardbyte.dev/projects/sunshine/>`_.
|
||||
|
||||
About
|
||||
-----
|
||||
Sunshine is a Game stream host for Moonlight.
|
||||
Sunshine is a self hosted, low latency, cloud gaming solution with support for AMD, Intel, and Nvidia gpus.
|
||||
It is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield.
|
||||
Connect to Sunshine from any Moonlight client, available for nearly any device imaginable.
|
||||
|
||||
These are the advantages of Sunshine over GeForce Experience.
|
||||
|
||||
- FOSS (Free and Open Source Software)
|
||||
- Multi-platform
|
||||
|
||||
- Linux
|
||||
- macOS
|
||||
- Windows
|
||||
|
||||
- Pair over web ui
|
||||
- Supports AMD, Intel, and Nvidia GPUs for encoding
|
||||
- Supports software encoding
|
||||
- Supports streaming to multiple clients
|
||||
- Web UI for configuration
|
||||
|
||||
Integrations
|
||||
------------
|
||||
|
||||
.. image:: https://img.shields.io/github/workflow/status/lizardbyte/sunshine/CI/master?label=CI%20build&logo=github&style=for-the-badge
|
||||
:alt: GitHub Workflow Status (CI)
|
||||
:target: https://github.com/LizardByte/Sunshine/actions/workflows/CI.yml?query=branch%3Amaster
|
||||
|
||||
.. image:: https://img.shields.io/github/workflow/status/lizardbyte/sunshine/localize/nightly?label=localize%20build&logo=github&style=for-the-badge
|
||||
:alt: GitHub Workflow Status (localize)
|
||||
:target: https://github.com/LizardByte/Sunshine/actions/workflows/localize.yml?query=branch%3Anightly
|
||||
|
||||
.. image:: https://img.shields.io/readthedocs/sunshinestream?label=Docs&style=for-the-badge&logo=readthedocs
|
||||
:alt: Read the Docs
|
||||
:target: http://sunshinestream.readthedocs.io/
|
||||
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=localized&style=for-the-badge&query=%24.progress..data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json&logo=crowdin
|
||||
:alt: CrowdIn
|
||||
:target: https://crowdin.com/project/sunshinestream
|
||||
|
||||
Support
|
||||
---------
|
||||
|
||||
Our support methods are listed in our `LizardByte Docs <https://docs.lizardbyte.dev/en/latest/about/support.html>`_.
|
||||
|
||||
Downloads
|
||||
---------
|
||||
|
||||
.. image:: https://img.shields.io/github/downloads/lizardbyte/sunshine/total?style=for-the-badge&logo=github
|
||||
:alt: GitHub Releases
|
||||
:target: https://github.com/LizardByte/Sunshine/releases/latest
|
||||
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=AUR&style=for-the-badge&query=$.results.0.NumVotes&url=https%3A%2F%2Fapp.lizardbyte.dev%2Funo%2Faur%2Fsunshine.json&logo=archlinux
|
||||
:alt: AUR votes
|
||||
:target: https://aur.archlinux.org/packages/sunshine
|
||||
|
||||
.. comment
|
||||
image:: https://img.shields.io/docker/pulls/lizardbyte/sunshine?style=for-the-badge&logo=docker
|
||||
:alt: Docker
|
||||
:target: https://hub.docker.com/r/lizardbyte/sunshine
|
||||
38
appveyor.yml
38
appveyor.yml
@@ -1,38 +0,0 @@
|
||||
image:
|
||||
- Ubuntu2004
|
||||
- Visual Studio 2019
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- BUILD_TYPE: Debug
|
||||
- BUILD_TYPE: Release
|
||||
|
||||
install:
|
||||
- sh: sudo apt update --ignore-missing
|
||||
- sh: sudo apt install -y build-essential fakeroot gcc-10 g++-10 cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
||||
- cmd: C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make"
|
||||
|
||||
before_build:
|
||||
- git submodule update --init --recursive
|
||||
- mkdir build
|
||||
- cd build
|
||||
|
||||
build_script:
|
||||
- cmd: set OLDPATH=%PATH%
|
||||
- cmd: set PATH=C:\msys64\mingw64\bin
|
||||
- sh: cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_EXECUTABLE_PATH=sunshine -DSUNSHINE_ASSETS_DIR=/etc/sunshine ..
|
||||
- cmd: cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DSUNSHINE_ASSETS_DIR=assets -G "MinGW Makefiles" ..
|
||||
- sh: make -j$(nproc)
|
||||
- cmd: mingw32-make -j2
|
||||
- cmd: set PATH=%OLDPATH%
|
||||
|
||||
after_build:
|
||||
- sh: ./gen-deb
|
||||
- cmd: Del ..\assets\apps_linux.json
|
||||
- cmd: 7z a Sunshine-Windows.zip ..\assets
|
||||
- cmd: 7z a Sunshine-Windows.zip sunshine.exe
|
||||
- cmd: 7z a Sunshine-Windows.zip tools\dxgi-info.exe
|
||||
- cmd: 7z a Sunshine-Windows.zip tools\audio-info.exe
|
||||
- cmd: appveyor PushArtifact Sunshine-Windows.zip
|
||||
- sh: appveyor PushArtifact package-deb/sunshine.deb
|
||||
- sh: appveyor PushArtifact sunshine.service
|
||||
@@ -1,271 +0,0 @@
|
||||
# If no external IP address is given, Sunshine will attempt to automatically detect external ip-address
|
||||
# external_ip = 123.456.789.12
|
||||
|
||||
# Set the familly of ports used by Sunshine
|
||||
# port = 47989
|
||||
|
||||
# The private key must be 2048 bits
|
||||
# pkey = /dir/pkey.pem
|
||||
|
||||
# The certificate must be signed with a 2048 bit key
|
||||
# cert = /dir/cert.pem
|
||||
|
||||
# The name displayed by Moonlight
|
||||
# If not specified, the PC's hostname is used
|
||||
# sunshine_name = Sunshine
|
||||
|
||||
# The minimum log level printed to standard out
|
||||
#
|
||||
# none -> no logs are printed to standard out
|
||||
#
|
||||
# verbose = [0]
|
||||
# debug = [1]
|
||||
# info = [2]
|
||||
# warning = [3]
|
||||
# error = [4]
|
||||
# fatal = [5]
|
||||
# none = [6]
|
||||
#
|
||||
# min_log_level = info
|
||||
|
||||
# The origin of the remote endpoint address that is not denied for HTTP method /pin
|
||||
# Could be any of the following values:
|
||||
# pc|lan|wan
|
||||
# pc: Only localhost may access /pin
|
||||
# lan: Only those in LAN may access /pin
|
||||
# wan: Anyone may access /pin
|
||||
#
|
||||
# origin_pin_allowed = pc
|
||||
|
||||
# The origin of the remote endpoint address that is not denied for HTTPS Web UI
|
||||
# Could be any of the following values:
|
||||
# pc|lan|wan
|
||||
# pc: Only localhost may access the Web Manager
|
||||
# lan: Only those in LAN may access the Web Manager
|
||||
# wan: Anyone may access the Web Manager
|
||||
#
|
||||
# origin_web_ui_allowed = lan
|
||||
|
||||
# If UPnP is enabled, Sunshine will attempt to open ports for streaming over the internet
|
||||
# To enable it, uncomment the following line:
|
||||
# upnp = on
|
||||
|
||||
# The file where current state of Sunshine is stored
|
||||
# file_state = sunshine_state.json
|
||||
|
||||
# The file where user credentials for the UI are stored
|
||||
# By default, credentials are stored in `file_state`
|
||||
# credentials_file = sunshine_state.json
|
||||
|
||||
# The display modes advertised by Sunshine
|
||||
#
|
||||
# Some versions of Moonlight, such as Moonlight-nx (Switch),
|
||||
# rely on this list to ensure that the requested resolutions and fps
|
||||
# are supported.
|
||||
#
|
||||
# fps = [10, 30, 60, 90, 120]
|
||||
# resolutions = [
|
||||
# 352x240,
|
||||
# 480x360,
|
||||
# 858x480,
|
||||
# 1280x720,
|
||||
# 1920x1080,
|
||||
# 2560x1080,
|
||||
# 3440x1440,
|
||||
# 1920x1200,
|
||||
# 3860x2160,
|
||||
# 3840x1600,
|
||||
# ]
|
||||
|
||||
# How long to wait in milliseconds for data from moonlight before shutting down the stream
|
||||
# ping_timeout = 10000
|
||||
|
||||
# The file where configuration for the different applications that Sunshine can run during a stream
|
||||
# file_apps = apps.json
|
||||
|
||||
# Percentage of error correcting packets per data packet in each video frame
|
||||
# Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage
|
||||
# The default value of 20 is what GeForce Experience uses
|
||||
#
|
||||
# The value must be greater than 0 and lower than or equal to 255
|
||||
# fec_percentage = 20
|
||||
|
||||
# When multicasting, it could be usefull to have different configurations for each connected Client.
|
||||
# For example:
|
||||
# Clients connected through WAN and LAN have different bitrate contstraints.
|
||||
# Decoders may require different settings for color
|
||||
#
|
||||
# Unlike simply broadcasting to multiple Client, this will generate distinct video streams.
|
||||
# Note, CPU usage increases for each distinct video stream generated
|
||||
# channels = 1
|
||||
|
||||
# The back/select button on the controller
|
||||
# On the Shield, the home and powerbutton are not passed to Moonlight
|
||||
# If, after the timeout, the back button is still pressed down, Home/Guide button press is emulated.
|
||||
# If back_button_timeout < 0, then the Home/Guide button will not be emulated
|
||||
# back_button_timeout = 2000
|
||||
|
||||
# !! Windows only !!
|
||||
# Control how fast keys will repeat themselves
|
||||
# The initial delay in milliseconds before repeating keys
|
||||
# key_repeat_delay = 500
|
||||
#
|
||||
# How often keys repeat every second
|
||||
# This configurable option supports decimals
|
||||
# key_repeat_frequency = 24.9
|
||||
|
||||
# The name of the audio sink used for Audio Loopback
|
||||
# If you do not specify this variable, pulseaudio will select the default monitor device.
|
||||
#
|
||||
# You can find the name of the audio sink using the following command:
|
||||
# !! Linux only !!
|
||||
# pacmd list-sinks | grep "name:" if running vanilla pulseaudio
|
||||
# pactl info | grep Source` if running pipewire
|
||||
# audio_sink = alsa_output.pci-0000_09_00.3.analog-stereo
|
||||
#
|
||||
# !! Windows only !!
|
||||
# tools\audio-info.exe
|
||||
# audio_sink = {0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B}
|
||||
#
|
||||
# The virtual sink, is the audio device that's virtual (Like Steam Streaming Speakers), it allows Sunshine
|
||||
# to stream audio, while muting the speakers.
|
||||
# virtual_sink = {0.0.0.00000000}.{8edba70c-1125-467c-b89c-15da389bc1d4}
|
||||
|
||||
# !! Windows only !!
|
||||
# You can select the video card you want to stream:
|
||||
# The appropriate values can be found using the following command:
|
||||
# tools\dxgi-info.exe
|
||||
# adapter_name = Radeon RX 580 Series
|
||||
# output_name = \\.\DISPLAY1
|
||||
|
||||
# !! Linux only !!
|
||||
# Set the display number to stream.
|
||||
# You can find them by the following command:
|
||||
# xrandr --listmonitors
|
||||
# Example output: "0: +HDMI-1 1920/518x1200/324+0+0 HDMI-1"
|
||||
# ^ <-- You need this.
|
||||
# output_name = 0
|
||||
|
||||
###############################################
|
||||
# FFmpeg software encoding parameters
|
||||
# Honestly, I have no idea what the optimal values would be.
|
||||
# Play around with this :)
|
||||
|
||||
# Constant Rate Factor. Between 1 and 52. It allows QP to go up during motion and down with still image, resulting in constant perceived quality
|
||||
# Higher value means more compression, but less quality
|
||||
# If crf == 0, then use QP directly instead
|
||||
# crf = 0
|
||||
|
||||
# Quantitization Parameter
|
||||
# Higher value means more compression, but less quality
|
||||
# If crf != 0, then this parameter is ignored
|
||||
# qp = 28
|
||||
|
||||
# Minimum number of threads used by ffmpeg to encode the video.
|
||||
# Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually
|
||||
# worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest
|
||||
# value that can reliably encode at your desired streaming settings on your hardware.
|
||||
# min_threads = 1
|
||||
|
||||
# Allows the client to request HEVC Main or HEVC Main10 video streams.
|
||||
# HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using software encoding.
|
||||
# If set to 0 (default), Sunshine will specify support for HEVC based on encoder
|
||||
# If set to 1, Sunshine will not advertise support for HEVC
|
||||
# If set to 2, Sunshine will advertise support for HEVC Main profile
|
||||
# If set to 3, Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles
|
||||
# hevc_mode = 2
|
||||
|
||||
# Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
||||
# supported encoders:
|
||||
# nvenc
|
||||
# amdvce # NOTE: alpha stage. The cursor is not yet displayed
|
||||
# software
|
||||
#
|
||||
# encoder = nvenc
|
||||
##################################### Software #####################################
|
||||
# See x264 --fullhelp for the different presets
|
||||
# sw_preset = superfast
|
||||
# sw_tune = zerolatency
|
||||
#
|
||||
|
||||
##################################### NVENC #####################################
|
||||
###### presets ###########
|
||||
# default
|
||||
# hp -- high performance
|
||||
# hq -- high quality
|
||||
# slow -- hq 2 passes
|
||||
# medium -- hq 1 pass
|
||||
# fast -- hp 1 pass
|
||||
# bd
|
||||
# ll -- low latency
|
||||
# llhq
|
||||
# llhp
|
||||
# lossless
|
||||
# losslesshp
|
||||
##########################
|
||||
# nv_preset = llhq
|
||||
#
|
||||
####### rate control #####
|
||||
# auto -- let ffmpeg decide rate control
|
||||
# constqp -- constant QP mode
|
||||
# vbr -- variable bitrate
|
||||
# cbr -- constant bitrate
|
||||
# cbr_hq -- cbr high quality
|
||||
# cbr_ld_hq -- cbr low delay high quality
|
||||
# vbr_hq -- vbr high quality
|
||||
##########################
|
||||
# nv_rc = auto
|
||||
|
||||
###### h264 entropy ######
|
||||
# auto -- let ffmpeg nvenc decide the entropy encoding
|
||||
# cabac
|
||||
# cavlc
|
||||
##########################
|
||||
# nv_coder = auto
|
||||
|
||||
##################################### AMD #####################################
|
||||
###### presets ###########
|
||||
# default
|
||||
# speed
|
||||
# balanced
|
||||
##########################
|
||||
# amd_preset = balanced
|
||||
#
|
||||
####### rate control #####
|
||||
# auto -- let ffmpeg decide rate control
|
||||
# constqp -- constant QP mode
|
||||
# vbr_latency -- Latency Constrained Variable Bitrate
|
||||
# vbr_peak -- Peak Contrained Variable Bitrate
|
||||
# cbr -- constant bitrate
|
||||
##########################
|
||||
# amd_rc = auto
|
||||
|
||||
###### h264 entropy ######
|
||||
# auto -- let ffmpeg nvenc decide the entropy encoding
|
||||
# cabac
|
||||
# cavlc
|
||||
##########################
|
||||
# amd_coder = auto
|
||||
|
||||
#################################### VAAPI ###################################
|
||||
####### adapter ##########
|
||||
# Unlike with `amdvce` and `nvenc`, it doesn't matter if video encoding is done
|
||||
# on a different GPU.
|
||||
# Run the following commands:
|
||||
# 1. ls /dev/dri/renderD*
|
||||
# to find all devices capable of VAAPI
|
||||
# 2. vainfo --display drm --device /dev/dri/renderD129 | grep -E "((VAProfileH264High|VAProfileHEVCMain|VAProfileHEVCMain10).*VAEntrypointEncSlice)|Driver version"
|
||||
# Lists the name and capabilities of the device.
|
||||
# To be supported by Sunshine, it needs to have at the very minimum:
|
||||
# VAProfileH264High : VAEntrypointEncSlice
|
||||
# adapter_name = /dev/dri/renderD128
|
||||
|
||||
##############################################
|
||||
# Some configurable parameters, are merely toggles for specific features
|
||||
# The first occurrence turns it on, the second occurence turns it off, the third occurence turns it on again, etc, etc
|
||||
# Here, you change the default state of any flag
|
||||
#
|
||||
# To set the initial state of flags -0 and -1 to on, set the following flags:
|
||||
# flags = 012
|
||||
#
|
||||
# See: sunshine --help for all options under the header: flags
|
||||
@@ -1,162 +0,0 @@
|
||||
<div id="app" class="container">
|
||||
<div class="my-4">
|
||||
<h1>Applications</h1>
|
||||
<div>Applications are refreshed only when Client is restarted</div>
|
||||
</div>
|
||||
<div class="card p-4">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(app,i) in apps" :key="i">
|
||||
<td>{{app.name}}</td>
|
||||
<td><button class="btn btn-primary" @click="editApp(i)">Edit</button>
|
||||
<button class="btn btn-danger" @click="showDeleteForm(i)">Delete</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="edit-form card mt-2" v-if="showEditForm">
|
||||
<div class="p-4">
|
||||
<!--name-->
|
||||
<div class="mb-3">
|
||||
<label for="appName" class="form-label">Application Name</label>
|
||||
<input type="text" class="form-control" id="appName" aria-describedby="appNameHelp" v-model="editForm.name">
|
||||
<div id="appNameHelp" class="form-text">Application Name, as shown on Moonlight</div>
|
||||
</div>
|
||||
<!--output-->
|
||||
<div class="mb-3">
|
||||
<label for="appOutput" class="form-label">Output</label>
|
||||
<input type="text" class="form-control monospace" id="appOutput" aria-describedby="appOutputHelp"
|
||||
v-model="editForm.output">
|
||||
<div id="appOutputHelp" class="form-text">The file where the output of the command is stored, if it is not
|
||||
specified, the output is ignored</div>
|
||||
</div>
|
||||
<!--prep-cmd-->
|
||||
<div class="mb-3 d-flex flex-column">
|
||||
<label for="appName" class="form-label">Command Preparations</label>
|
||||
<div class="form-text">A list of commands to be run before/after the application. <br> If any of the
|
||||
prep-commands fail, starting the application is aborted</div>
|
||||
<table v-if="editForm['prep-cmd'].length > 0">
|
||||
<thead>
|
||||
<th class="precmd-head">Do</th>
|
||||
<th class="precmd-head">Undo</th>
|
||||
<th style="width: 48px;"></th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(c,i) in editForm['prep-cmd']">
|
||||
<td><input type="text" class="form-control monospace" v-model="c.do"></td>
|
||||
<td><input type="text" class="form-control monospace" v-model="c.undo"></td>
|
||||
<td><button class="btn btn-danger" @click="editForm['prep-cmd'].splice(i,1)">×</button></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="mt-2 btn btn-success" style="margin: 0 auto;" @click="addPrepCmd">+ Add</button>
|
||||
</div>
|
||||
<!--detatched-->
|
||||
<div class="mb-3">
|
||||
<label for="appName" class="form-label">Detached Commands</label>
|
||||
<div v-for="(c,i) in editForm.detached" class="d-flex justify-content-between my-2">
|
||||
<pre>{{c}}</pre>
|
||||
<button class="btn btn-danger mx-2" @click="editForm.detached.splice(i,1)">×</button>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<input type="text" class="form-control monospace" v-model="detachedCmd">
|
||||
<button class="btn btn-success mx-2" @click="editForm.detached.push(detachedCmd);detachedCmd = '';">+</button>
|
||||
</div>
|
||||
<div class="form-text">A list of commands to be run and forgotten about</div>
|
||||
</div>
|
||||
<!--command-->
|
||||
<div class="mb-3">
|
||||
<label for="appCmd" class="form-label">Command</label>
|
||||
<input type="text" class="form-control monospace" id="appCmd" aria-describedby="appCmdHelp"
|
||||
v-model="editForm.cmd">
|
||||
<div id="appCmdHelp" class="form-text">The main application, if it is not specified, a processs is started that
|
||||
sleeps indefinitely</div>
|
||||
</div>
|
||||
<!--buttons-->
|
||||
<div class="d-flex">
|
||||
<button @click="showEditForm = false" class="btn btn-secondary m-2">Cancel</button>
|
||||
<button class="btn btn-primary m-2" @click="save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2" v-else>
|
||||
<button class="btn btn-primary" @click="newApp">+ Add New</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
apps: [],
|
||||
showEditForm: false,
|
||||
editForm: null,
|
||||
detachedCmd: '',
|
||||
}
|
||||
},
|
||||
created() {
|
||||
fetch("/api/apps").then(r => r.json()).then((r) => {
|
||||
console.log(r);
|
||||
this.apps = r.apps;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
newApp() {
|
||||
this.editForm = {
|
||||
name: '',
|
||||
output: '',
|
||||
cmd: [],
|
||||
index: -1,
|
||||
"prep-cmd": [],
|
||||
"detached": []
|
||||
};
|
||||
this.editForm.index = -1;
|
||||
this.showEditForm = true;
|
||||
},
|
||||
editApp(id) {
|
||||
this.editForm = JSON.parse(JSON.stringify(this.apps[id]));
|
||||
this.$set(this.editForm, "index", id);
|
||||
if (this.editForm["prep-cmd"] === undefined) this.$set(this.editForm, "prep-cmd", []);
|
||||
if (this.editForm["detached"] === undefined) this.$set(this.editForm, "detached", []);
|
||||
this.showEditForm = true;
|
||||
},
|
||||
showDeleteForm(id) {
|
||||
let resp = confirm("Are you sure to delete " + this.apps[id].name + "?");
|
||||
if (resp) {
|
||||
fetch("/api/apps/" + id, { method: "DELETE" }).then((r) => {
|
||||
if (r.status == 200) document.location.reload();
|
||||
});
|
||||
}
|
||||
},
|
||||
addPrepCmd() {
|
||||
this.editForm['prep-cmd'].push({
|
||||
do: '',
|
||||
undo: '',
|
||||
});
|
||||
},
|
||||
save() {
|
||||
fetch("/api/apps", { method: "POST", body: JSON.stringify(this.editForm) }).then((r) => {
|
||||
if (r.status == 200) document.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.precmd-head {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.monospace {
|
||||
font-family: monospace;
|
||||
}
|
||||
</style>
|
||||
@@ -1,592 +0,0 @@
|
||||
<div id="app" class="container">
|
||||
<h1 class="my-4">Configuration</h1>
|
||||
<div class="form" v-if="config">
|
||||
<!--Header-->
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item" v-for="tab in tabs" :key="tab.id">
|
||||
<a class="nav-link" :class="{'active': tab.id === currentTab}" href="#"
|
||||
@click="currentTab = tab.id">{{tab.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!--General Tab-->
|
||||
<div v-if="currentTab === 'general'" class="config-page">
|
||||
<!--Sunshine Name-->
|
||||
<div class="mb-3">
|
||||
<label for="sunshine_name" class="form-label">Sunshine Name</label>
|
||||
<input type="text" class="form-control" id="sunshine_name" placeholder="Sunshine"
|
||||
v-model="config.sunshine_name">
|
||||
<div class="form-text">The name displayed by Moonlight. If not specified, the PC's hostname is used
|
||||
</div>
|
||||
</div>
|
||||
<!--Log Level-->
|
||||
<div class="mb-3">
|
||||
<label for="min_log_level" class="form-label">Log Level</label>
|
||||
<select id="min_log_level" class="form-select" v-model="config.min_log_level">
|
||||
<option :value="0">Verbose</option>
|
||||
<option :value="1">Debug</option>
|
||||
<option :value="2">Info</option>
|
||||
<option :value="3">Warning</option>
|
||||
<option :value="4">Error</option>
|
||||
<option :value="5">Fatal</option>
|
||||
<option :value="6">None</option>
|
||||
</select>
|
||||
<div class="form-text">The minimum log level printed to standard out</div>
|
||||
</div>
|
||||
<!--Origin Web UI Allowed-->
|
||||
<div class="mb-3">
|
||||
<label for="origin_web_ui_allowed" class="form-label">Origin Web UI Allowed</label>
|
||||
<select id="origin_web_ui_allowed" class="form-select" v-model="config.origin_web_ui_allowed">
|
||||
<option value="pc">Only localhost may access Web UI</option>
|
||||
<option value="lan">Only those in LAN may access Web UI</option>
|
||||
<option value="wan">Anyone may access Web UI</option>
|
||||
</select>
|
||||
<div class="form-text">The origin of the remote endpoint address that is not denied access to Web UI
|
||||
</div>
|
||||
</div>
|
||||
<!--UPnP-->
|
||||
<div class="mb-3">
|
||||
<label for="upnp" class="form-label">UPnP</label>
|
||||
<select id="upnp" class="form-select" v-model="config.upnp">
|
||||
<option value="disabled">Disabled</option>
|
||||
<option value="enabled">Enabled</option>
|
||||
</select>
|
||||
<div class="form-text">Automatically configure port forwarding</div>
|
||||
</div>
|
||||
<!--Ping Timeout-->
|
||||
<div class="mb-3">
|
||||
<label for="ping_timeout" class="form-label">Ping Timeout</label>
|
||||
<input type="text" class="form-control" id="ping_timeout" placeholder="10000"
|
||||
v-model="config.ping_timeout">
|
||||
<div class="form-text">How long to wait in milliseconds for data from moonlight before shutting down the
|
||||
stream</div>
|
||||
</div>
|
||||
<!--Advertised FPS and Resolutions-->
|
||||
<div class="mb-3">
|
||||
<label for="ping_timeout" class="form-label">Advertised Resolutions and FPS</label>
|
||||
<div class="resolutions-container">
|
||||
<label>Resolutions</label>
|
||||
<div class="resolutions d-flex flex-wrap">
|
||||
<div class="p-2 ms-item m-2 d-flex justify-content-between" v-for="(r,i) in resolutions"
|
||||
:key="r">
|
||||
<span class="px-2">{{r}}</span>
|
||||
<span style="cursor: pointer;" @click="resolutions.splice(i,1)">×</span>
|
||||
</div>
|
||||
<form @submit.prevent="resolutions.push(resIn);resIn = '';" class="d-flex align-items-center">
|
||||
<input type="text" v-model="resIn" required pattern="[0-9]+x[0-9]+"
|
||||
style="border-top-right-radius: 0;border-bottom-right-radius: 0;" class="form-control">
|
||||
<button style="border-top-left-radius: 0;border-bottom-left-radius: 0;"
|
||||
class="btn btn-success">+</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fps-container">
|
||||
<label>FPS</label>
|
||||
<div class="fps d-flex flex-wrap">
|
||||
<div class="p-2 ms-item m-2 d-flex justify-content-between" v-for="(f,i) in fps" :key="f">
|
||||
<span class="px-2">{{f}}</span>
|
||||
<span style="cursor: pointer;" @click="fps.splice(i,1)">×</span>
|
||||
</div>
|
||||
<form @submit.prevent="fps.push(fpsIn);fpsIn = '';" class="d-flex align-items-center">
|
||||
<input type="text" v-model="fpsIn" required pattern="[0-9]+"
|
||||
style="width: 6ch;border-top-right-radius: 0;border-bottom-right-radius: 0;"
|
||||
class="form-control">
|
||||
<button style="border-top-left-radius: 0;border-bottom-left-radius: 0;"
|
||||
class="btn btn-success">+</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
The display modes advertised by Sunshine<br>
|
||||
Some versions of Moonlight, such as Moonlight-nx (Switch),
|
||||
rely on this list to ensure that the requested resolutions and fps
|
||||
are supported.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--Files Tab-->
|
||||
<div v-if="currentTab === 'files'" class="config-page">
|
||||
<!--Private Key-->
|
||||
<div class="mb-3">
|
||||
<label for="pkey" class="form-label">Private Key</label>
|
||||
<input type="text" class="form-control" id="pkey" placeholder="/dir/pkey.pem" v-model="config.pkey">
|
||||
<div class="form-text">The private key must be 2048 bits</div>
|
||||
</div>
|
||||
<!--Cert-->
|
||||
<div class="mb-3">
|
||||
<label for="cert" class="form-label">Cert</label>
|
||||
<input type="text" class="form-control" id="cert" placeholder="/dir/cert.pem" v-model="config.cert">
|
||||
<div class="form-text">The certificate must be signed with a 2048 bit key</div>
|
||||
</div>
|
||||
|
||||
<!--State File-->
|
||||
<div class="mb-3">
|
||||
<label for="file_state" class="form-label">State File</label>
|
||||
<input type="text" class="form-control" id="file_state" placeholder="sunshine_state.json"
|
||||
v-model="config.file_state">
|
||||
<div class="form-text">The file where current state of Sunshine is stored</div>
|
||||
</div>
|
||||
<!--Apps File-->
|
||||
<div class="mb-3">
|
||||
<label for="file_apps" class="form-label">Apps File</label>
|
||||
<input type="text" class="form-control" id="file_apps" placeholder="apps.json"
|
||||
v-model="config.file_apps">
|
||||
<div class="form-text">The file where current apps of Sunshine are stored</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentTab === 'input'" class="config-page">
|
||||
<!--Back Button Timeout-->
|
||||
<div class="mb-3">
|
||||
<label for="back_button_timeout" class="form-label">Back Button Timeout</label>
|
||||
<input type="text" class="form-control" id="back_button_timeout" placeholder="2000"
|
||||
v-model="config.back_button_timeout">
|
||||
<div class="form-text">
|
||||
The back/select button on the controller.<br>
|
||||
On the Shield, the home and powerbutton are not passed to Moonlight.<br>
|
||||
If, after the timeout, the back button is still pressed down, Home/Guide button press is
|
||||
emulated.<br>
|
||||
If back_button_timeout < 0, then the Home/Guide button will not be emulated<br>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Key Repeat Delay-->
|
||||
<div class="mb-3" v-if="platform === 'windows'">
|
||||
<label for="key_repeat_delay" class="form-label">Key Repeat Delay</label>
|
||||
<input type="text" class="form-control" id="key_repeat_delay" placeholder="500"
|
||||
v-model="config.key_repeat_delay">
|
||||
<div class="form-text">
|
||||
Control how fast keys will repeat themselves<br>
|
||||
The initial delay in milliseconds before repeating keys
|
||||
</div>
|
||||
</div>
|
||||
<!-- Key Repeat Frequency-->
|
||||
<div class="mb-3" v-if="platform === 'windows'">
|
||||
<label for="key_repeat_frequency" class="form-label">Key Repeat Frequency</label>
|
||||
<input type="text" class="form-control" id="key_repeat_frequency" placeholder="24.9"
|
||||
v-model="config.key_repeat_frequency">
|
||||
<div class="form-text">
|
||||
How often keys repeat every second<br>
|
||||
This configurable option supports decimals
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--Files Tab-->
|
||||
<div v-if="currentTab === 'av'" class="config-page">
|
||||
<!--Audio Sink-->
|
||||
<div class="mb-3" v-if="platform === 'windows'">
|
||||
<label for="audio_sink" class="form-label">Audio Sink</label>
|
||||
<input type="text" class="form-control" id="audio_sink"
|
||||
placeholder="{0.0.0.00000000}.{FD47D9CC-4218-4135-9CE2-0C195C87405B}" v-model="config.audio_sink">
|
||||
<div class="form-text">
|
||||
The name of the audio sink used for Audio Loopback<br>
|
||||
You can find the name of the audio sink using the following command:<br>
|
||||
<pre>tools\audio-info.exe</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3" v-if="platform === 'linux'">
|
||||
<label for="audio_sink" class="form-label">Audio Sink</label>
|
||||
<input type="text" class="form-control" id="audio_sink"
|
||||
placeholder="alsa_output.pci-0000_09_00.3.analog-stereo" v-model="config.audio_sink">
|
||||
<div class="form-text">
|
||||
The name of the audio sink used for Audio Loopback<br>
|
||||
If you do not specify this variable, pulseaudio will select the default monitor device.<br>
|
||||
<br>
|
||||
You can find the name of the audio sink using either command:<br>
|
||||
<pre>pacmd list-sinks | grep "name:"</pre>
|
||||
<pre>pactl info | grep Source</pre><br>
|
||||
</div>
|
||||
</div>
|
||||
<!--Virtual Sink-->
|
||||
<div class="mb-3" v-if="platform === 'windows'">
|
||||
<label for="virtual_sink" class="form-label">Virtual Sink</label>
|
||||
<input type="text" class="form-control" id="virtual_sink"
|
||||
placeholder="{0.0.0.00000000}.{8edba70c-1125-467c-b89c-15da389bc1d4}" v-model="config.virtual_sink">
|
||||
<div class="form-text">
|
||||
The virtual sink, is the audio device that's virtual (Like Steam Streaming Speakers), it allows
|
||||
Sunshine
|
||||
to stream audio, while muting the speakers.
|
||||
</div>
|
||||
</div>
|
||||
<!--Adapter Name -->
|
||||
<div class="mb-3" v-if="platform === 'windows'">
|
||||
<label for="adapter_name" class="form-label">Adapter Name</label>
|
||||
<input type="text" class="form-control" id="adapter_name" placeholder="Radeon RX 580 Series"
|
||||
v-model="config.adapter_name">
|
||||
<div class="form-text" v-if="platform === 'windows'">
|
||||
You can select the video card you want to stream:<br>
|
||||
The appropriate values can be found using the following command:<br>
|
||||
<pre>tools\dxgi-info.exe</pre>
|
||||
</div>
|
||||
</div>
|
||||
<!--Output Name -->
|
||||
<div class="mb-3" class="config-page" v-if="platform === 'windows'">
|
||||
<label for="output_name" class="form-label">Output Name</label>
|
||||
<input type="text" class="form-control" id="output_name" placeholder="\\.\DISPLAY1"
|
||||
v-model="config.output_name">
|
||||
<div class="form-text">
|
||||
You can select the video card you want to stream:<br>
|
||||
The appropriate values can be found using the following command:<br>
|
||||
tools\dxgi-info.exe<br><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3" class="config-page" v-if="platform === 'linux'">
|
||||
<label for="output_name" class="form-label">Monitor number</label>
|
||||
<input type="text" class="form-control" id="output_name" placeholder="0" v-model="config.output_name">
|
||||
<div class="form-text">
|
||||
xrandr --listmonitors<br>
|
||||
Example output:
|
||||
<pre> 0: +HDMI-1 1920/518x1200/324+0+0 HDMI-1</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentTab === 'advanced'" class="config-page">
|
||||
<!--Port familly-->
|
||||
<div class="mb-3">
|
||||
<label for="port" class="form-label">Port</label>
|
||||
<input type="number" min="0" max="65529" class="form-control" id="port" placeholder="47989"
|
||||
v-model="config.port">
|
||||
<div class="form-text">
|
||||
Set the familly of ports used by Sunshine
|
||||
</div>
|
||||
</div>
|
||||
<!--Constant Rate Factor-->
|
||||
<div class="mb-3">
|
||||
<label for="crf" class="form-label">Constant Rate Factor</label>
|
||||
<input type="number" min="0" max="52" class="form-control" id="crf" placeholder="0"
|
||||
v-model="config.crf">
|
||||
<div class="form-text">
|
||||
Constant Rate Factor. Between 1 and 52. It allows QP to go up during motion and down with still
|
||||
image,
|
||||
resulting in constant perceived quality<br>
|
||||
Higher value means more compression, but less quality<br>
|
||||
If crf == 0, then use QP directly instead
|
||||
</div>
|
||||
</div>
|
||||
<!-- Quantization Parameter -->
|
||||
<div class="mb-3">
|
||||
<label for="qp" class="form-label">Quantitization Parameter</label>
|
||||
<input type="number" class="form-control" id="qp" placeholder="28" v-model="config.qp">
|
||||
<div class="form-text">
|
||||
Quantitization Parameter<br>
|
||||
Higher value means more compression, but less quality<br>
|
||||
If crf != 0, then this parameter is ignored
|
||||
</div>
|
||||
</div>
|
||||
<!-- Min Threads -->
|
||||
<div class="mb-3">
|
||||
<label for="min_threads" class="form-label">Minimum number of threads used by ffmpeg to encode the
|
||||
video.</label>
|
||||
<input type="number" min="1" class="form-control" id="min_threads" placeholder="1"
|
||||
v-model="config.min_threads">
|
||||
<div class="form-text">
|
||||
Minimum number of threads used by ffmpeg to encode the video.<br>
|
||||
Increasing the value slightly reduces encoding efficiency, but the tradeoff is usually<br>
|
||||
worth it to gain the use of more CPU cores for encoding. The ideal value is the lowest<br>
|
||||
value that can reliably encode at your desired streaming settings on your hardware.
|
||||
</div>
|
||||
</div>
|
||||
<!--HEVC Suppport -->
|
||||
<div class="mb-3">
|
||||
<label for="hevc_mode" class="form-label">HEVC Support</label>
|
||||
<select id="hevc_mode" class="form-select" v-model="config.hevc_mode">
|
||||
<option value="0">Sunshine will specify support for HEVC based on encoder</option>
|
||||
<option value="1">Sunshine will not advertise support for HEVC</option>
|
||||
<option value="2">Sunshine will advertise support for HEVC Main profile</option>
|
||||
<option value="3">Sunshine will advertise support for HEVC Main and Main10 (HDR) profiles
|
||||
</option>
|
||||
</select>
|
||||
<div class="form-text">
|
||||
Allows the client to request HEVC Main or HEVC Main10 video streams.<br>
|
||||
HEVC is more CPU-intensive to encode, so enabling this may reduce performance when using
|
||||
software
|
||||
encoding.
|
||||
</div>
|
||||
</div>
|
||||
<!--Encoder -->
|
||||
<div class="mb-3">
|
||||
<label for="encoder" class="form-label">Force a Specific Encoder</label>
|
||||
<select id="encoder" class="form-select" v-model="config.encoder">
|
||||
<option :value="''">Autodetect</option>
|
||||
<option value="nvenc">nVidia NVENC</option>
|
||||
<option value="amdvce">AMD AMF/VCE</option>
|
||||
<option value="vaapi">VA-API</option>
|
||||
<option value="software">Software</option>
|
||||
</select>
|
||||
<div class="form-text">
|
||||
Force a specific encoder, otherwise Sunshine will use the first encoder that is available
|
||||
</div>
|
||||
</div>
|
||||
<!--FEC Percentage-->
|
||||
<div class="mb-3">
|
||||
<label for="fec_percentage" class="form-label">FEC Percentage</label>
|
||||
<input type="text" class="form-control" id="fec_percentage" placeholder="20"
|
||||
v-model="config.fec_percentage">
|
||||
<div class="form-text">
|
||||
Percentage of error correcting packets per data packet in each video frame.<br>
|
||||
Higher values can correct for more network packet loss, but at the cost of increasing bandwidth usage.<br>
|
||||
The default value of 20 is what GeForce Experience uses.
|
||||
</div>
|
||||
</div>
|
||||
<!--Channels-->
|
||||
<div class="mb-3">
|
||||
<label for="channels" class="form-label">Channels</label>
|
||||
<input type="text" class="form-control" id="channels" placeholder="1" v-model="config.channels">
|
||||
<div class="form-text">
|
||||
When multicasting, it could be useful to have different configurations for each connected
|
||||
Client.
|
||||
For example:
|
||||
<ul>
|
||||
<li>Clients connected through WAN and LAN have different bitrate contstraints.</li>
|
||||
<li>Decoders may require different settings for color</li>
|
||||
</ul>
|
||||
Unlike simply broadcasting to multiple Client, this will generate distinct video streams.<br>
|
||||
Note, CPU usage increases for each distinct video stream generated
|
||||
</div>
|
||||
</div>
|
||||
<!--Credentials File-->
|
||||
<div class="mb-3">
|
||||
<label for="credentials_file" class="form-label">Web Manager Credentials File</label>
|
||||
<input type="text" class="form-control" id="credentials_file" placeholder="sunshine_state.json"
|
||||
v-model="config.credentials_file">
|
||||
<div class="form-text">
|
||||
Store Username/Password seperately from Sunshine's state file.
|
||||
</div>
|
||||
</div>
|
||||
<!--Origin PIN Allowed-->
|
||||
<div class="mb-3">
|
||||
<label for="origin_pin_allowed" class="form-label">Origin PIN Allowed</label>
|
||||
<select id="origin_pin_allowed" class="form-select" v-model="config.origin_pin_allowed">
|
||||
<option value="pc">Only localhost may access /pin</option>
|
||||
<option value="lan">Only those in LAN may access /pin</option>
|
||||
<option value="wan">Anyone may access /pin</option>
|
||||
</select>
|
||||
<div class="form-text">The origin of the remote endpoint address that is not denied for HTTP method /pin
|
||||
</div>
|
||||
</div>
|
||||
<!--External IP-->
|
||||
<div class="mb-3">
|
||||
<label for="external_ip" class="form-label">External IP</label>
|
||||
<input type="text" class="form-control" id="external_ip" placeholder="123.456.789.12"
|
||||
v-model="config.external_ip">
|
||||
<div class="form-text">If no external IP address is given, Sunshine will automatically detect external
|
||||
IP</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--Software Settings-->
|
||||
<div v-if="currentTab === 'sw'" class="config-page">
|
||||
<div class="mb-3">
|
||||
<label for="sw_preset" class="form-label">SW Presets</label>
|
||||
<input class="form-control" id="sw_preset" placeholder="superfast" v-model="config.sw_preset">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="sw_tune" class="form-label">SW Tune</label>
|
||||
<input class="form-control" id="sw_tune" placeholder="zerolatency" v-model="config.sw_tune">
|
||||
</div>
|
||||
</div>
|
||||
<!--Nvidia Encoder Settings-->
|
||||
<div v-if="currentTab === 'nv'" class="config-page">
|
||||
<!--NVENC SETTINGS-->
|
||||
<div class="mb-3">
|
||||
<label for="nv_preset" class="form-label">NVEnc Preset</label>
|
||||
<select id="nv_preset" class="form-select" v-model="config.nv_preset">
|
||||
<option value="default">Default</option>
|
||||
<option value="hp">High Performance</option>
|
||||
<option value="hq">High Quality</option>
|
||||
<option value="slow">Slow - hq 2 passes</option>
|
||||
<option value="medium">medium -- hq 1 pass</option>
|
||||
<option value="fast">fast -- hp 1 pass</option>
|
||||
<option value="bd">bd</option>
|
||||
<option value="ll">ll -- low latency</option>
|
||||
<option value="llhq">llhq</option>
|
||||
<option value="llhp">llhp</option>
|
||||
<option value="lossless">lossless</option>
|
||||
<option value="losslesshp">losslesshp</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="nv_rc" class="form-label">NVEnc Rate Control</label>
|
||||
<select id="nv_rc" class="form-select" v-model="config.nv_rc">
|
||||
<option value="auto">auto -- let ffmpeg decide rate control</option>
|
||||
<option value="constqp">constqp -- constant QP mode</option>
|
||||
<option value="vbr">vbr -- variable bitrate</option>
|
||||
<option value="cbr">cbr -- constant bitrate</option>
|
||||
<option value="cbr_hq">cbr_hq -- cbr high quality</option>
|
||||
<option value="cbr_ld_hq">cbr_ld_hq -- cbr low delay high quality</option>
|
||||
<option value="vbr_hq">vbr_hq -- vbr high quality</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="nv_coder" class="form-label">NVEnc Coder</label>
|
||||
<select id="nv_coder" class="form-select" v-model="config.nv_coder">
|
||||
<option value="auto">auto</option>
|
||||
<option value="cabac">cabac</option>
|
||||
<option value="cavlc">cavlc</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<!--AMD Encoder Settings-->
|
||||
<div v-if="currentTab === 'amd'" class="config-page">
|
||||
<!--Presets-->
|
||||
<div class="mb-3">
|
||||
<label for="amd_quality" class="form-label">AMD AMF Quality</label>
|
||||
<select id="amd_quality" class="form-select" v-model="config.amd_quality">
|
||||
<option value="default">Default</option>
|
||||
<option value="speed">Speed</option>
|
||||
<option value="balanced">Balanced</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="amd_rc" class="form-label">AMD AMF Rate Control</label>
|
||||
<select id="amd_rc" class="form-select" v-model="config.amd_rc">
|
||||
<option value="auto">auto -- let ffmpeg decide rate control</option>
|
||||
<option value="constqp">constqp -- constant QP mode</option>
|
||||
<option value="vbr_latency">vbr_latency -- Latency Constrained Variable Bitrate</option>
|
||||
<option value="vbr_peak">vbr_peak -- Peak Contrained Variable Bitrate</option>
|
||||
<option value="cbr">cbr -- constant bitrate</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="amd_coder" class="form-label">AMD AMF Rate Control</label>
|
||||
<select id="amd_coder" class="form-select" v-model="config.amd_coder">
|
||||
<option value="auto">auto</option>
|
||||
<option value="cabac">cabac</option>
|
||||
<option value="cavlc">cavlc</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="currentTab === 'va-api'" class="config-page">
|
||||
<input class="form-control" id="adapter_name" placeholder="/dev/dri/renderD128"
|
||||
v-model="config.adapter_name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-success my-4" v-if="success"><b>Success!</b> Restart Sunshine to apply changes</div>
|
||||
<div class="mb-3 buttons">
|
||||
<button class="btn btn-primary" @click="save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
platform: '',
|
||||
success: false,
|
||||
config: null,
|
||||
fps: [],
|
||||
resolutions: [],
|
||||
currentTab: 'general',
|
||||
resIn: '',
|
||||
fpsIn: '',
|
||||
tabs: [{
|
||||
id: 'general',
|
||||
name: "General"
|
||||
},
|
||||
{
|
||||
id: 'files',
|
||||
name: "Files"
|
||||
},
|
||||
{
|
||||
id: 'input',
|
||||
name: "Input"
|
||||
},
|
||||
{
|
||||
id: 'av',
|
||||
name: "Audio/Video"
|
||||
},
|
||||
{
|
||||
id: 'advanced',
|
||||
name: "Advanced"
|
||||
},
|
||||
{
|
||||
id: "sw",
|
||||
name: "Software Encoder"
|
||||
},
|
||||
{
|
||||
id: "nv",
|
||||
name: "NVENC Encoder"
|
||||
},
|
||||
{
|
||||
id: "amd",
|
||||
name: "AMF Encoder"
|
||||
},
|
||||
{
|
||||
id: "va-api",
|
||||
name: "VA-API encoder"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
fetch("/api/config").then(r => r.json()).then((r) => {
|
||||
this.config = r;
|
||||
this.platform = this.config.platform;
|
||||
|
||||
var app = document.getElementById("app");
|
||||
if (this.platform == "windows") {
|
||||
this.tabs = this.tabs.filter(el => {
|
||||
return el.id !== "va-api";
|
||||
});
|
||||
}
|
||||
if (this.platform == "linux") {
|
||||
this.tabs = this.tabs.filter(el => {
|
||||
return el.id !== "amd";
|
||||
});
|
||||
}
|
||||
|
||||
delete this.config.status;
|
||||
delete this.config.platform;
|
||||
//Populate default values if not present in config
|
||||
this.config.upnp = this.config.upnp || 'disabled';
|
||||
this.config.min_log_level = this.config.min_log_level || 2;
|
||||
this.config.origin_pin_allowed = this.config.origin_pin_allowed || "pc";
|
||||
this.config.origin_web_ui_allowed = this.config.origin_web_manager_allowed || "lan";
|
||||
this.config.hevc_mode = this.config.hevc_mode || 0;
|
||||
this.config.encoder = this.config.encoder || '';
|
||||
this.config.nv_preset = this.config.nv_preset || 'default';
|
||||
this.config.nv_rc = this.config.nv_rc || 'auto';
|
||||
this.config.nv_coder = this.config.nv_coder || 'auto';
|
||||
this.config.amd_quality = this.config.amd_quality || 'default';
|
||||
this.config.amd_rc = this.config.amd_rc || 'auto';
|
||||
this.config.fps = this.config.fps || '[10, 30, 60, 90, 120]';
|
||||
this.config.resolutions = this.config.resolutions || '[352x240,480x360,858x480,1280x720,1920x1080,2560x1080,3440x1440,1920x1200,3860x2160,3840x1600]';
|
||||
this.fps = JSON.parse(this.config.fps);
|
||||
//Resolutions should be fixed because are not valid JSON
|
||||
let res = this.config.resolutions.substring(1, this.config.resolutions.length - 1);
|
||||
let resolutions = [];
|
||||
res.split(",").forEach(r => resolutions.push(r.trim()));
|
||||
this.resolutions = resolutions;
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.success = false;
|
||||
let nl = this.config === 'windows' ? "\r\n" : "\n";
|
||||
this.config.resolutions = "[" + nl + " " + this.resolutions.join("," + nl + " ") + nl + "]";
|
||||
this.config.fps = JSON.stringify(this.fps);
|
||||
fetch("/api/config", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(this.config)
|
||||
}).then((r) => {
|
||||
if (r.status == 200) this.success = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.config-page {
|
||||
padding: 1em;
|
||||
border: 1px solid #dee2e6;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
padding: 1em 0;
|
||||
}
|
||||
|
||||
.ms-item {
|
||||
background-color: #CCC;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
@@ -1,45 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Sunshine</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-wEmeIV1mKuiNpC+IOBjI7aAzPcEZeedi5yW5f2yOq55WWLwNGmvvx4Um1vskeMj0" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-p34f1UUtsS3wqzfto5wAAmdvj+osOnFyQFpp4Ua3gs/ZVWx6oOypYoCJhGGScy+8" crossorigin="anonymous">
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light" style="background-color: #ffc400;">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand">Sunshine</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
|
||||
aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/pin">PIN</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/apps">Applications</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/config">Configuration</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/password">Change Password</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -1,9 +0,0 @@
|
||||
<div id="content" class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-6 py-4" style="margin: 0 auto;">
|
||||
<h1>Hello, Sunshine!</h1>
|
||||
<p>Sunshine is a Gamestream host for Moonlight</p>
|
||||
<a href="https://github.com/loki-47-6F-64/sunshine">Official GitHub Repository</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,97 +0,0 @@
|
||||
<div id="app" class="container">
|
||||
<h1 class="my-4">Password Change</h1>
|
||||
<form @submit.prevent="save">
|
||||
<div class="card d-flex p-4 flex-row">
|
||||
<div class="col-md-6 px-4">
|
||||
<h4>Current Credentials</h4>
|
||||
<div class="mb-3">
|
||||
<label for="currentUsername" class="form-label">Username</label>
|
||||
<input required type="text" class="form-control" id="currentUsername" v-model="passwordData.currentUsername">
|
||||
<div class="form-text"> </div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="currentPassword" class="form-label">Password</label>
|
||||
<input autocomplete="current-password" type="password" class="form-control" id="currentPassword" v-model="passwordData.currentPassword">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 px-4">
|
||||
<h4>New Credentials</h4>
|
||||
<div class="mb-3">
|
||||
<label for="newUsername" class="form-label">New Username</label>
|
||||
<input type="text" class="form-control" id="newUsername" v-model="passwordData.newUsername">
|
||||
<div class="form-text">If not specified, the username will not change
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="newPassword" class="form-label">Password</label>
|
||||
<input autocomplete="new-password" required type="password" class="form-control" id="newPassword" v-model="passwordData.newPassword">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="confirmNewPassword" class="form-label">Confirm Password</label>
|
||||
<input autocomplete="new-password" required type="password" class="form-control" id="confirmNewPassword" v-model="passwordData.confirmNewPassword">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-danger" v-if="error"><b>Error: </b>{{error}}</div>
|
||||
<div class="alert alert-success" v-if="success"><b>Success! </b>This page will reload soon, your browser will ask you for the new credentials</div>
|
||||
<div class="mb-3 buttons">
|
||||
<button class="btn btn-primary">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
data() {
|
||||
return {
|
||||
error: null,
|
||||
success: false,
|
||||
passwordData: {
|
||||
currentUsername: '',
|
||||
currentPassword: '',
|
||||
newUsername: '',
|
||||
newPassword: '',
|
||||
confirmNewPassword: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.error = null;
|
||||
fetch("/api/password", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(this.passwordData)
|
||||
}).then((r) => {
|
||||
if (r.status == 200){
|
||||
r.json().then((rj) => {
|
||||
if(rj.status.toString() === "true"){
|
||||
this.success = true;
|
||||
setTimeout(()=>{
|
||||
document.location.reload();
|
||||
},5000);
|
||||
} else {
|
||||
this.error = rj.error;
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
this.error = "Internal Server Error"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.config-page {
|
||||
padding: 1em;
|
||||
border: 1px solid #dee2e6;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
padding: 1em 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
<div id="content" class="container">
|
||||
<h1 class="my-4">PIN Pairing</h1>
|
||||
<form action="" class="form d-flex flex-column align-items-center" id="form">
|
||||
<div class="card flex-column d-flex p-4 mb-4">
|
||||
<input type="number" placeholder="PIN" id="pin-input" class="form-control my-4">
|
||||
<button class="btn btn-primary">Send</button>
|
||||
</div>
|
||||
<div class="alert alert-warning">
|
||||
<b>Warning!</b> Make sure you have access to the client you are pairing with.<br>
|
||||
This software can give total control to your computer, so be careful!
|
||||
</div>
|
||||
<div id="status"></div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelector("#form").addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
let pin = document.querySelector("#pin-input").value;
|
||||
document.querySelector("#status").innerHTML = "";
|
||||
let b = JSON.stringify({pin: pin});
|
||||
fetch("/api/pin",{method: "POST",body: b}).then((response) => response.json()).then((response)=>{
|
||||
if(response.status){
|
||||
document.querySelector("#status").innerHTML = `<div class="alert alert-success" role="alert">Success! Please check Moonlight to continue</div>`;
|
||||
} else {
|
||||
document.querySelector("#status").innerHTML = `<div class="alert alert-danger" role="alert">PIN does not match, please check if it's typed correctly</div>`;
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
21
cmake/FindLIBCAP.cmake
Normal file
21
cmake/FindLIBCAP.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
# - Try to find Libcap
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBCAP_FOUND - system has Libcap
|
||||
# LIBCAP_INCLUDE_DIRS - the Libcap include directory
|
||||
# LIBCAP_LIBRARIES - the libraries needed to use Libcap
|
||||
# LIBCAP_DEFINITIONS - Compiler switches required for using Libcap
|
||||
|
||||
# Use pkg-config to get the directories and then use these values
|
||||
# in the find_path() and find_library() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_LIBCAP libcap)
|
||||
|
||||
set(LIBCAP_DEFINITIONS ${PC_LIBCAP_CFLAGS})
|
||||
|
||||
find_path(LIBCAP_INCLUDE_DIRS sys/capability.h PATHS ${PC_LIBCAP_INCLUDEDIR} ${PC_LIBCAP_INCLUDE_DIRS})
|
||||
find_library(LIBCAP_LIBRARIES NAMES libcap.so PATHS ${PC_LIBCAP_LIBDIR} ${PC_LIBCAP_LIBRARY_DIRS})
|
||||
mark_as_advanced(LIBCAP_INCLUDE_DIRS LIBCAP_LIBRARIES)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LIBCAP REQUIRED_VARS LIBCAP_LIBRARIES LIBCAP_INCLUDE_DIRS)
|
||||
21
cmake/FindLIBDRM.cmake
Normal file
21
cmake/FindLIBDRM.cmake
Normal file
@@ -0,0 +1,21 @@
|
||||
# - Try to find Libdrm
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBDRM_FOUND - system has Libdrm
|
||||
# LIBDRM_INCLUDE_DIRS - the Libdrm include directory
|
||||
# LIBDRM_LIBRARIES - the libraries needed to use Libdrm
|
||||
# LIBDRM_DEFINITIONS - Compiler switches required for using Libdrm
|
||||
|
||||
# Use pkg-config to get the directories and then use these values
|
||||
# in the find_path() and find_library() calls
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PC_LIBDRM libdrm)
|
||||
|
||||
set(LIBDRM_DEFINITIONS ${PC_LIBDRM_CFLAGS})
|
||||
|
||||
find_path(LIBDRM_INCLUDE_DIRS drm.h PATHS ${PC_LIBDRM_INCLUDEDIR} ${PC_LIBDRM_INCLUDE_DIRS} PATH_SUFFIXES libdrm)
|
||||
find_library(LIBDRM_LIBRARIES NAMES libdrm.so PATHS ${PC_LIBDRM_LIBDIR} ${PC_LIBDRM_LIBRARY_DIRS})
|
||||
mark_as_advanced(LIBDRM_INCLUDE_DIRS LIBDRM_LIBRARIES)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LIBDRM REQUIRED_VARS LIBDRM_LIBRARIES LIBDRM_INCLUDE_DIRS)
|
||||
78
cmake/FindWayland.cmake
Normal file
78
cmake/FindWayland.cmake
Normal file
@@ -0,0 +1,78 @@
|
||||
# Try to find Wayland on a Unix system
|
||||
#
|
||||
# This will define:
|
||||
#
|
||||
# WAYLAND_FOUND - True if Wayland is found
|
||||
# WAYLAND_LIBRARIES - Link these to use Wayland
|
||||
# WAYLAND_INCLUDE_DIRS - Include directory for Wayland
|
||||
# WAYLAND_DEFINITIONS - Compiler flags for using Wayland
|
||||
#
|
||||
# In addition the following more fine grained variables will be defined:
|
||||
#
|
||||
# Wayland_Client_FOUND WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES
|
||||
# Wayland_Server_FOUND WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES
|
||||
# Wayland_EGL_FOUND WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES
|
||||
# Wayland_Cursor_FOUND WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES
|
||||
#
|
||||
# Copyright (c) 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
# 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
IF (NOT WIN32)
|
||||
|
||||
# Use pkg-config to get the directories and then use these values
|
||||
# in the find_path() and find_library() calls
|
||||
find_package(PkgConfig)
|
||||
PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor)
|
||||
|
||||
set(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS})
|
||||
|
||||
find_path(WAYLAND_CLIENT_INCLUDE_DIRS NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
|
||||
find_library(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
|
||||
if(WAYLAND_CLIENT_INCLUDE_DIRS AND WAYLAND_CLIENT_LIBRARIES)
|
||||
set(Wayland_Client_FOUND TRUE)
|
||||
else()
|
||||
set(Wayland_Client_FOUND FALSE)
|
||||
endif()
|
||||
mark_as_advanced(WAYLAND_CLIENT_INCLUDE_DIRS WAYLAND_CLIENT_LIBRARIES)
|
||||
|
||||
find_path(WAYLAND_CURSOR_INCLUDE_DIRS NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
|
||||
find_library(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
|
||||
if(WAYLAND_CURSOR_INCLUDE_DIRS AND WAYLAND_CURSOR_LIBRARIES)
|
||||
set(Wayland_Cursor_FOUND TRUE)
|
||||
else()
|
||||
set(Wayland_Cursor_FOUND FALSE)
|
||||
endif()
|
||||
mark_as_advanced(WAYLAND_CURSOR_INCLUDE_DIRS WAYLAND_CURSOR_LIBRARIES)
|
||||
|
||||
find_path(WAYLAND_EGL_INCLUDE_DIRS NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
|
||||
find_library(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
|
||||
if(WAYLAND_EGL_INCLUDE_DIRS AND WAYLAND_EGL_LIBRARIES)
|
||||
set(Wayland_EGL_FOUND TRUE)
|
||||
else()
|
||||
set(Wayland_EGL_FOUND FALSE)
|
||||
endif()
|
||||
mark_as_advanced(WAYLAND_EGL_INCLUDE_DIRS WAYLAND_EGL_LIBRARIES)
|
||||
|
||||
find_path(WAYLAND_SERVER_INCLUDE_DIRS NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS})
|
||||
find_library(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS})
|
||||
if(WAYLAND_SERVER_INCLUDE_DIRS AND WAYLAND_SERVER_LIBRARIES)
|
||||
set(Wayland_Server_FOUND TRUE)
|
||||
else()
|
||||
set(Wayland_Server_FOUND FALSE)
|
||||
endif()
|
||||
mark_as_advanced(WAYLAND_SERVER_INCLUDE_DIRS WAYLAND_SERVER_LIBRARIES)
|
||||
|
||||
set(WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS} ${WAYLAND_SERVER_INCLUDE_DIRS} ${WAYLAND_EGL_INCLUDE_DIRS} ${WAYLAND_CURSOR_INCLUDE_DIRS})
|
||||
set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES})
|
||||
mark_as_advanced(WAYLAND_INCLUDE_DIRS WAYLAND_LIBRARIES)
|
||||
|
||||
list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIRS)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
find_package_handle_standard_args(Wayland REQUIRED_VARS WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIRS HANDLE_COMPONENTS)
|
||||
|
||||
ENDIF ()
|
||||
22
crowdin.yml
Normal file
22
crowdin.yml
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
"base_path": "."
|
||||
"base_url": "https://api.crowdin.com" # optional (for Crowdin Enterprise only)
|
||||
"preserve_hierarchy": false # flatten tree on crowdin
|
||||
"pull_request_labels": [
|
||||
"crowdin",
|
||||
"l10n"
|
||||
]
|
||||
|
||||
"files": [
|
||||
{
|
||||
"source": "/locale/*.po",
|
||||
"translation": "/locale/%two_letters_code%/LC_MESSAGES/%original_file_name%",
|
||||
"languages_mapping": {
|
||||
"two_letters_code": {
|
||||
# map non-two letter codes here, left side is crowdin designation, right side is babel designation
|
||||
"en-GB": "en_GB",
|
||||
"en-US": "en_US"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
35
docs/make.bat
Normal file
35
docs/make.bat
Normal file
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
1113
docs/source/about/advanced_usage.rst
Normal file
1113
docs/source/about/advanced_usage.rst
Normal file
File diff suppressed because it is too large
Load Diff
5
docs/source/about/docker.rst
Normal file
5
docs/source/about/docker.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/DOCKER_README.md
|
||||
|
||||
.. Todo:: This is a planned feature. Currently no Dockerfile or image exists for Sunshine.
|
||||
|
||||
.. mdinclude:: ../../../DOCKER_README.md
|
||||
160
docs/source/about/installation.rst
Normal file
160
docs/source/about/installation.rst
Normal file
@@ -0,0 +1,160 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/about/installation.rst
|
||||
|
||||
Installation
|
||||
============
|
||||
The recommended method for running Sunshine is to use the `binaries`_ bundled with the `latest release`_.
|
||||
|
||||
Binaries
|
||||
--------
|
||||
Binaries of Sunshine are created for each release. They are available for Linux, and Windows.
|
||||
Binaries can be found in the `latest release`_.
|
||||
|
||||
.. Tip:: Some third party packages also exist. See
|
||||
:ref:`Third Party Packages <about/third_party_packages:third party packages>`.
|
||||
|
||||
Docker
|
||||
------
|
||||
.. Todo:: Docker images of Sunshine are planned to be included in the future.
|
||||
They will be available on `Dockerhub.io`_ and `ghcr.io`_.
|
||||
|
||||
Linux
|
||||
-----
|
||||
Follow the instructions for your preferred package type below.
|
||||
|
||||
AppImage
|
||||
^^^^^^^^
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:appimage?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
According to AppImageLint the AppImage can run on the following distros.
|
||||
|
||||
- [✖] Debian oldstable (buster)
|
||||
- [✔] Debian stable (bullseye)
|
||||
- [✔] Debian testing (bookworm)
|
||||
- [✔] Debian unstable (sid)
|
||||
- [✔] Ubuntu jammy
|
||||
- [✔] Ubuntu impish
|
||||
- [✔] Ubuntu focal
|
||||
- [✖] Ubuntu bionic
|
||||
- [✖] Ubuntu xenial
|
||||
- [✖] Ubuntu trusty
|
||||
- [✖] CentOS 7
|
||||
|
||||
#. Download ``sunshine-appimage.zip`` and extract the contents to your home directory.
|
||||
|
||||
AUR Package
|
||||
^^^^^^^^^^^
|
||||
#. Open terminal and run the following code.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://aur.archlinux.org/sunshine-git.git
|
||||
cd sunshine-git
|
||||
makepkg -fi
|
||||
|
||||
Debian Package
|
||||
^^^^^^^^^^^^^^
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:deb?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
#. Download ``sunshine.deb`` and run the following code.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install -f ./sunshine.deb
|
||||
|
||||
.. Tip:: You can double click the deb file to see details about the package and begin installation.
|
||||
|
||||
Flatpak Package
|
||||
^^^^^^^^^^^^^^^
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:flatpak?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
.. Todo:: This package needs to have CUDA added.
|
||||
|
||||
#. Install `Flatpak <https://flatpak.org/setup/>`_ as required.
|
||||
#. Download ``sunshine.flatpak`` and run the following code.
|
||||
|
||||
System level (recommended)
|
||||
.. code-block:: bash
|
||||
|
||||
flatpak install --system sunshine.flatpak
|
||||
|
||||
User level
|
||||
.. code-block:: bash
|
||||
|
||||
flatpak install --user sunshine.flatpak
|
||||
|
||||
RPM Package
|
||||
^^^^^^^^^^^
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/pkg:rpm?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
#. Add `rpmfusion` repositories by running the following code.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \
|
||||
https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
|
||||
|
||||
#. Download ``sunshine.rpm`` and run the following code.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf install ./sunshine.rpm
|
||||
|
||||
.. Tip:: You can double click the rpm file to see details about the package and begin installation.
|
||||
|
||||
macOS
|
||||
-----
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:macos?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
pkg
|
||||
.. Warning:: The `pkg` does not include runtime dependencies and should be considered experimental.
|
||||
|
||||
#. Download the ``sunshine.pkg`` file and install it as normal.
|
||||
|
||||
Portfile
|
||||
#. Install `MacPorts <https://www.macports.org>`_
|
||||
#. Update the Macports sources.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo nano /opt/local/etc/macports/sources.conf
|
||||
|
||||
Add this line, replacing your username, below the line that starts with ``rsync``.
|
||||
|
||||
file://Users/<username>/ports
|
||||
|
||||
``Ctrl+x``, then ``Y`` to exit and save changes.
|
||||
|
||||
#. Download the ``Portfile`` to ``~/Downloads`` and run the following code.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir -p ~/ports/multimedia/sunshine
|
||||
mv ~/Downlaods/Portfile ~/ports/multimedia/sunshine
|
||||
cd ~/ports
|
||||
portindex
|
||||
sudo port install sunshine
|
||||
|
||||
#. The first time you start Sunshine, you will be asked to grant access to screen recording and your microphone.
|
||||
|
||||
Windows
|
||||
-------
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:windows:10?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
.. image:: https://img.shields.io/github/issues/lizardbyte/sunshine/os:windows:11?logo=github&style=for-the-badge
|
||||
:alt: GitHub issues by-label
|
||||
|
||||
Installed option:
|
||||
#. Download and install ``sunshine-windows.exe``
|
||||
|
||||
Standalone option:
|
||||
#. Download and extract ``sunshine-windows.zip``
|
||||
|
||||
.. _latest release: https://github.com/LizardByte/Sunshine/releases/latest
|
||||
.. _Dockerhub.io: https://hub.docker.com/repository/docker/lizardbyte/sunshine
|
||||
.. _ghcr.io: https://github.com/orgs/LizardByte/packages?repo_name=sunshine
|
||||
1
docs/source/about/overview.rst
Normal file
1
docs/source/about/overview.rst
Normal file
@@ -0,0 +1 @@
|
||||
.. include:: ../../../README.rst
|
||||
47
docs/source/about/third_party_packages.rst
Normal file
47
docs/source/about/third_party_packages.rst
Normal file
@@ -0,0 +1,47 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/about/third_party_packages.rst
|
||||
|
||||
Third Party Packages
|
||||
====================
|
||||
|
||||
.. Danger:: These packages are not maintained by LizardByte. Use at your own risk.
|
||||
|
||||
Chocolatey
|
||||
----------
|
||||
|
||||
.. image:: https://img.shields.io/chocolatey/v/Sunshine?style=for-the-badge&logo=chocolatey
|
||||
:alt: Chocolatey Version
|
||||
:target: https://community.chocolatey.org/packages/sunshine
|
||||
|
||||
.. image:: https://img.shields.io/chocolatey/dt/sunshine?style=for-the-badge&logo=chocolatey
|
||||
:alt: Chocolatey
|
||||
|
||||
Scoop
|
||||
-----
|
||||
|
||||
.. image:: https://img.shields.io/scoop/v/sunshine?bucket=extras&style=for-the-badge
|
||||
:alt: Scoop Version (extras bucket)
|
||||
:target: https://scoop.sh/#/apps?s=0&d=1&o=true&q=sunshine
|
||||
|
||||
Winget
|
||||
------
|
||||
.. image:: https://img.shields.io/badge/dynamic/xml?color=orange&label=Winget&style=for-the-badge&prefix=v&query=%2F%2Ftr%5B%40id%3D%27winget%27%5D%2Ftd%5B3%5D%2Fspan%2Fa&url=https%3A%2F%2Frepology.org%2Fproject%2Fsunshine%2Fversions&logo=microsoft
|
||||
:alt: Winget Version
|
||||
:target: https://github.com/microsoft/winget-pkgs/tree/master/manifests/l/LizardByte/Sunshine
|
||||
|
||||
Legacy GitHub Repo
|
||||
------------------
|
||||
|
||||
.. Attention:: This repo is not maintained. Thank you to Loki for bringing this amazing project to life!
|
||||
|
||||
.. image:: https://img.shields.io/static/v1?label=repo&message=loki-47-6F-64/sunshine&color=blue&style=for-the-badge&logo=github
|
||||
:alt: GitHub Maintainer
|
||||
:target: https://github.com/loki-47-6F-64/sunshine/releases
|
||||
|
||||
.. image:: https://img.shields.io/github/last-commit/loki-47-6F-64/sunshine?style=for-the-badge&logo=github
|
||||
:alt: GitHub last commit
|
||||
|
||||
.. image:: https://img.shields.io/github/release-date/loki-47-6F-64/sunshine?style=for-the-badge&logo=github
|
||||
:alt: GitHub Release Date
|
||||
|
||||
.. image:: https://img.shields.io/github/downloads/loki-47-6F-64/sunshine/total?style=for-the-badge&logo=github
|
||||
:alt: GitHub Releases
|
||||
221
docs/source/about/usage.rst
Normal file
221
docs/source/about/usage.rst
Normal file
@@ -0,0 +1,221 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/about/usage.rst
|
||||
|
||||
Usage
|
||||
=====
|
||||
#. See the `setup`_ section for your specific OS.
|
||||
#. Run ``sunshine <directory of conf file>/sunshine.conf``.
|
||||
|
||||
.. Note:: You do not need to specify a config file. If no config file is entered the default location will be used.
|
||||
|
||||
.. Attention:: The configuration file specified will be created if it doesn't exist.
|
||||
|
||||
.. Tip:: If using the Linux AppImage, replace ``sunshine`` with ``./sunshine.AppImage``
|
||||
|
||||
#. Configure Sunshine in the web ui
|
||||
The web ui is available on `https://localhost:47990 <https://localhost:47990>`_ by default. You may replace
|
||||
`localhost` with your internal ip address.
|
||||
|
||||
.. Attention:: Ignore any warning given by your browser about "insecure website".
|
||||
|
||||
.. Caution:: If running for the first time, make sure to note the username and password Sunshine showed to you,
|
||||
since you cannot get back later!
|
||||
|
||||
Add games and applications.
|
||||
This can be configured in the web ui.
|
||||
|
||||
.. Note:: Additionally, apps can be configured manually. `src_assets/<os>/config/apps.json` is an example of a
|
||||
list of applications that are started just before running a stream. This is the directory within the GitHub
|
||||
repo.
|
||||
|
||||
.. Attention:: Application list is not fully supported on macOS
|
||||
|
||||
#. In Moonlight, you may need to add the PC manually.
|
||||
#. When Moonlight request you insert the correct pin on sunshine:
|
||||
|
||||
- Login to the web ui
|
||||
- Go to "PIN" in the Navbar
|
||||
- Type in your PIN and press Enter, you should get a Success Message
|
||||
- In Moonlight, select one of the Applications listed
|
||||
|
||||
Network
|
||||
-------
|
||||
Sunshine will be available on port 47990 by default.
|
||||
|
||||
.. Danger:: Do not expose port 47990, or the web ui, to the internet!
|
||||
|
||||
Arguments
|
||||
---------
|
||||
To get a list of available arguments run the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sunshine --help
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
Linux
|
||||
^^^^^
|
||||
The deb and rpm packages handle these steps automatically. The AppImage does not, third party packages may not as well.
|
||||
|
||||
Sunshine needs access to `uinput` to create mouse and gamepad events.
|
||||
|
||||
#. Add user to group `input`, if this is the first time installing.
|
||||
.. code-block:: bash
|
||||
|
||||
sudo usermod -a -G input $USER
|
||||
|
||||
#. Create `udev` rules.
|
||||
.. code-block:: bash
|
||||
|
||||
sudo nano /etc/udev/rules.d/85-sunshine.rules
|
||||
|
||||
Input the following contents.
|
||||
|
||||
.. code-block::
|
||||
|
||||
KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput"
|
||||
|
||||
Save the file and exit:
|
||||
|
||||
#. ``CTRL+X`` to start exit.
|
||||
#. ``Y`` to save modifications.
|
||||
|
||||
#. Optionally, configure autostart service
|
||||
- filename: ``~/.config/systemd/user/sunshine.service``
|
||||
- contents:
|
||||
|
||||
.. code-block::
|
||||
|
||||
[Unit]
|
||||
Description=Sunshine Gamestream Server for Moonlight
|
||||
|
||||
[Service]
|
||||
ExecStart=<see table>
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
|
||||
.. table::
|
||||
:widths: auto
|
||||
|
||||
======== ============================================== ===============
|
||||
package ExecStart Auto Configured
|
||||
======== ============================================== ===============
|
||||
aur /usr/bin/sunshine ✔
|
||||
deb /usr/bin/sunshine ✔
|
||||
rpm /usr/bin/sunshine ✔
|
||||
AppImage ~/sunshine.AppImage ✖
|
||||
Flatpak flatpak run dev.lizardbyte.sunshine ✖
|
||||
======== ============================================== ===============
|
||||
|
||||
Start once
|
||||
.. code-block:: bash
|
||||
|
||||
systemctl --user start sunshine
|
||||
|
||||
Start on boot
|
||||
.. code-block:: bash
|
||||
|
||||
systemctl --user enable sunshine
|
||||
|
||||
#. Additional Setup for KMS
|
||||
.. Note:: ``cap_sys_admin`` may as well be root, except you don't need to be root to run it. It is necessary to
|
||||
allow Sunshine to use KMS.
|
||||
|
||||
Enable
|
||||
.. code-block:: bash
|
||||
|
||||
sudo setcap cap_sys_admin+p $(readlink -f $(which sunshine))
|
||||
|
||||
Disable
|
||||
.. code-block:: bash
|
||||
|
||||
sudo setcap -r $(readlink -f $(which sunshine))
|
||||
|
||||
#. Reboot
|
||||
.. code-block:: bash
|
||||
|
||||
sudo reboot now
|
||||
|
||||
macOS
|
||||
^^^^^
|
||||
Sunshine can only access microphones on macOS due to system limitations. To stream system audio use
|
||||
`Soundflower <https://github.com/mattingalls/Soundflower>`_ or
|
||||
`BlackHole <https://github.com/ExistentialAudio/BlackHole>`_ and
|
||||
select their sink as audio device in `sunshine.conf`.
|
||||
|
||||
.. Note:: Command Keys are not forwarded by Moonlight. Right Option-Key is mapped to CMD-Key.
|
||||
|
||||
.. Caution:: Gamepads are not currently supported.
|
||||
|
||||
Configure autostart service
|
||||
|
||||
MacPorts
|
||||
.. code-block:: bash
|
||||
|
||||
sudo port load Sunshine
|
||||
|
||||
Windows
|
||||
^^^^^^^
|
||||
For gamepad support, install `ViGEmBus <https://github.com/ViGEm/ViGEmBus/releases/latest>`_
|
||||
|
||||
Shortcuts
|
||||
---------
|
||||
All shortcuts start with CTRL + ALT + SHIFT, just like Moonlight
|
||||
|
||||
- ``CTRL + ALT + SHIFT + N`` - Hide/Unhide the cursor (This may be useful for Remote Desktop Mode for Moonlight)
|
||||
- ``CTRL + ALT + SHIFT + F1/F13`` - Switch to different monitor for Streaming
|
||||
|
||||
Application List
|
||||
----------------
|
||||
- You can use Environment variables in place of values
|
||||
- ``$(HOME)`` will be replaced by the value of ``$HOME``
|
||||
- ``$$`` will be replaced by ``$``, e.g. ``$$(HOME)`` will be replaced by ``$(HOME)``
|
||||
- ``env`` - Adds or overwrites Environment variables for the commands/applications run by Sunshine
|
||||
- ``"Variable name":"Variable value"``
|
||||
- ``apps`` - The list of applications
|
||||
- Example application:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"name":"An App",
|
||||
"cmd":"command to open app",
|
||||
"prep-cmd":[
|
||||
{
|
||||
"do":"some-command",
|
||||
"undo":"undo-that-command"
|
||||
}
|
||||
],
|
||||
"detached":[
|
||||
"some-command",
|
||||
"another-command"
|
||||
]
|
||||
}
|
||||
|
||||
- ``name`` - The name of the application/game
|
||||
- ``output`` - The file where the output of the command is stored
|
||||
- ``detached`` - A list of commands to be run and forgotten about
|
||||
- ``prep-cmd`` - A list of commands to be run before/after the application
|
||||
|
||||
- If any of the prep-commands fail, starting the application is aborted
|
||||
- ``do`` - Run before the application
|
||||
|
||||
- If it fails, all ``undo`` commands of the previously succeeded ``do`` commands are run
|
||||
|
||||
- ``undo`` - Run after the application has terminated
|
||||
|
||||
- This should not fail considering it is supposed to undo the ``do`` commands
|
||||
- If it fails, Sunshine is terminated
|
||||
|
||||
- ``cmd`` - The main application
|
||||
|
||||
- If not specified, a process is started that sleeps indefinitely
|
||||
|
||||
Considerations
|
||||
--------------
|
||||
- When an application is started, if there is an application already running, it will be terminated.
|
||||
- When the application has been shutdown, the stream shuts down as well.
|
||||
- In addition to the apps listed, one app "Desktop" is hardcoded into Sunshine. It does not start an application,
|
||||
instead it simply starts a stream.
|
||||
35
docs/source/building/build.rst
Normal file
35
docs/source/building/build.rst
Normal file
@@ -0,0 +1,35 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/building/build.rst
|
||||
|
||||
Build
|
||||
=====
|
||||
Sunshine binaries are built using `CMake <https://cmake.org/>`_. Cross compilation is not
|
||||
supported. That means the binaries must be built on the target operating system and architecture.
|
||||
|
||||
Building Locally
|
||||
----------------
|
||||
|
||||
Clone
|
||||
^^^^^
|
||||
Ensure `git <https://git-scm.com/>`_ is installed and run the following:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/lizardbyte/sunshine.git --recurse-submodules
|
||||
cd sunshine && mkdir build && cd build
|
||||
|
||||
Compile
|
||||
^^^^^^^
|
||||
See the section specific to your OS.
|
||||
|
||||
- :ref:`Linux <building/linux:linux>`
|
||||
- :ref:`macOS <building/macos:macos>`
|
||||
- :ref:`Windows <building/windows:windows>`
|
||||
|
||||
Remote Build
|
||||
------------
|
||||
It may be beneficial to build remotely in some cases. This will enable easier building on different operating systems.
|
||||
|
||||
#. Fork the project
|
||||
#. Activate workflows
|
||||
#. Trigger the `CI` workflow manually
|
||||
#. Download the artifacts/binaries from the workflow run summary
|
||||
302
docs/source/building/linux.rst
Normal file
302
docs/source/building/linux.rst
Normal file
@@ -0,0 +1,302 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/building/linux.rst
|
||||
|
||||
Linux
|
||||
=====
|
||||
|
||||
Requirements
|
||||
------------
|
||||
.. Danger:: Installing these dependencies may break your distribution. It is recommended to build in a virtual machine
|
||||
or to use the `Dockerfile builds`_ located in the `./scripts` directory.
|
||||
|
||||
Debian Bullseye
|
||||
^^^^^^^^^^^^^^^
|
||||
End of Life: TBD
|
||||
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt update && sudo apt install \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \ # KMS
|
||||
libdrm-dev \ # KMS
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \ # Wayland
|
||||
libx11-dev \ # X11
|
||||
libxcb-shm0-dev \ # X11
|
||||
libxcb-xfixes0-dev \ # X11
|
||||
libxcb1-dev \ # X11
|
||||
libxfixes-dev \ # X11
|
||||
libxrandr-dev \ # X11
|
||||
libxtst-dev \ # X11
|
||||
nvidia-cuda-dev \ # Cuda, NvFBC
|
||||
nvidia-cuda-toolkit \ # Cuda, NvFBC
|
||||
|
||||
Fedora 35
|
||||
^^^^^^^^^
|
||||
End of Life: TBD
|
||||
|
||||
Install Repositories
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf update && \
|
||||
sudo dnf group install "Development Tools" && \
|
||||
sudo dnf install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
|
||||
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf install \
|
||||
boost-devel \
|
||||
boost-static.x86_64 \
|
||||
cmake \
|
||||
ffmpeg-devel \
|
||||
gcc-c++ \
|
||||
libevdev-devel \
|
||||
libX11-devel \ # X11
|
||||
libxcb-devel \ # X11
|
||||
libXcursor-devel \ # X11
|
||||
libXfixes-devel \ # X11
|
||||
libXinerama-devel \ # X11
|
||||
libXi-devel \ # X11
|
||||
libXrandr-devel \ # X11
|
||||
libXtst-devel \ # X11
|
||||
mesa-libGL-devel \
|
||||
openssl-devel \
|
||||
opus-devel \
|
||||
pulseaudio-libs-devel \
|
||||
rpm-build \ # if you want to build an RPM binary package
|
||||
|
||||
Ubuntu 18.04
|
||||
^^^^^^^^^^^^
|
||||
End of Life: April 2028
|
||||
|
||||
Install Repositories
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt update && sudo apt install \
|
||||
software-properties-common \
|
||||
&& add-apt-repository ppa:savoury1/graphics && \
|
||||
add-apt-repository ppa:savoury1/multimedia && \
|
||||
add-apt-repository ppa:savoury1/ffmpeg4 && \
|
||||
add-apt-repository ppa:savoury1/boost-defaults-1.71 && \
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test && \
|
||||
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install \
|
||||
build-essential \
|
||||
cmake \
|
||||
gcc-10 \
|
||||
git \
|
||||
g++-10 \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem1.71-dev \
|
||||
libboost-log1.71-dev \
|
||||
libboost-regex1.71-dev \
|
||||
libboost-thread1.71-dev \
|
||||
libcap-dev \ # KMS
|
||||
libdrm-dev \ # KMS
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \ # Wayland
|
||||
libx11-dev \ # X11
|
||||
libxcb-shm0-dev \ # X11
|
||||
libxcb-xfixes0-dev \ # X11
|
||||
libxcb1-dev \ # X11
|
||||
libxfixes-dev \ # X11
|
||||
libxrandr-dev \ # X11
|
||||
libxtst-dev \ # X11
|
||||
wget \
|
||||
|
||||
Update gcc alias
|
||||
.. code-block:: bash
|
||||
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10
|
||||
|
||||
Install CuDA
|
||||
.. code-block:: bash
|
||||
|
||||
wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run --progress=bar:force:noscroll -q --show-progress -O ./cuda.run && chmod a+x ./cuda.run
|
||||
./cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm && rm ./cuda.run
|
||||
|
||||
Install CMake
|
||||
.. code-block:: bash
|
||||
|
||||
wget https://cmake.org/files/v3.22/cmake-3.22.2-linux-x86_64.sh
|
||||
mkdir /opt/cmake
|
||||
sh /cmake-3.22.2-linux-x86_64.sh --prefix=/opt/cmake --skip-license
|
||||
ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
|
||||
cmake --version
|
||||
|
||||
Ubuntu 20.04
|
||||
^^^^^^^^^^^^
|
||||
End of Life: April 2030
|
||||
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt update && sudo apt install \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
g++-10 \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \ # KMS
|
||||
libdrm-dev \ # KMS
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \ # Wayland
|
||||
libx11-dev \ # X11
|
||||
libxcb-shm0-dev \ # X11
|
||||
libxcb-xfixes0-dev \ # X11
|
||||
libxcb1-dev \ # X11
|
||||
libxfixes-dev \ # X11
|
||||
libxrandr-dev \ # X11
|
||||
libxtst-dev \ # X11
|
||||
wget \
|
||||
|
||||
Update gcc alias
|
||||
.. code-block:: bash
|
||||
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10
|
||||
|
||||
Install CuDA
|
||||
.. code-block:: bash
|
||||
|
||||
wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run --progress=bar:force:noscroll -q --show-progress -O ./cuda.run && chmod a+x ./cuda.run
|
||||
./cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm && rm ./cuda.run
|
||||
|
||||
Ubuntu 21.10
|
||||
^^^^^^^^^^^^
|
||||
End of Life: July 2022
|
||||
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt update && sudo apt install \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \ # KMS
|
||||
libdrm-dev \ # KMS
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \ # Wayland
|
||||
libx11-dev \ # X11
|
||||
libxcb-shm0-dev \ # X11
|
||||
libxcb-xfixes0-dev \ # X11
|
||||
libxcb1-dev \ # X11
|
||||
libxfixes-dev \ # X11
|
||||
libxrandr-dev \ # X11
|
||||
libxtst-dev \ # X11
|
||||
nvidia-cuda-dev \ # Cuda, NvFBC
|
||||
nvidia-cuda-toolkit \ # Cuda, NvFBC
|
||||
|
||||
Ubuntu 22.04
|
||||
^^^^^^^^^^^^
|
||||
End of Life: April 2027
|
||||
|
||||
.. Todo:: Create Ubuntu 22.04 Dockerfile and complete this documentation.
|
||||
|
||||
Build
|
||||
-----
|
||||
.. Attention:: Ensure you are in the build directory created during the clone step earlier before continuing.
|
||||
|
||||
Debian based OSes
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_C_COMPILER=gcc-10 -DCMAKE_CXX_COMPILER=g++-10 ..
|
||||
|
||||
Red Hat based Oses
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..
|
||||
|
||||
Finally
|
||||
.. code-block:: bash
|
||||
|
||||
make -j ${nproc}
|
||||
cpack -G DEB # optionally, create a deb package
|
||||
cpack -G RPM # optionally, create a rpm package
|
||||
|
||||
Dockerfile Builds
|
||||
-----------------
|
||||
You may wish to simply build sunshine from source, without bloating your OS with development files.
|
||||
There are scripts located in the ``./scripts`` directory that will create docker images that have the necessary
|
||||
packages. As a result, removing the development files after you're done is a single command away.
|
||||
These scripts use docker under the hood, as such, they can only be used to compile the Linux version
|
||||
|
||||
.. Todo:: Publish the Dockerfiles to Dockerhub and ghcr.
|
||||
|
||||
Requirements
|
||||
Install `Docker <https://docs.docker.com/engine/install/>`_
|
||||
|
||||
Instructions
|
||||
#. :ref:`Clone <building/build:clone>`. Sunshine.
|
||||
#. Select the desired Dockerfile from the ``./scripts`` directory.
|
||||
|
||||
Available Files:
|
||||
.. code-block:: text
|
||||
|
||||
Dockerfile-debian
|
||||
Dockerfile-fedora_33 # end of life
|
||||
Dockerfile-fedora_35
|
||||
Dockerfile-ubuntu_18_04
|
||||
Dockerfile-ubuntu_20_04
|
||||
Dockerfile-ubuntu_21_04 # end of life
|
||||
Dockerfile-ubuntu_21_10
|
||||
|
||||
#. Execute
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd scripts # move to the scripts directory
|
||||
./build-container.sh -f Dockerfile-<name> # create the container (replace the "<name>")
|
||||
./build-sunshine.sh -p -s .. # compile and build sunshine
|
||||
|
||||
#. Updating
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git pull # pull the latest changes from github
|
||||
./build-sunshine.sh -p -s .. # compile and build sunshine
|
||||
|
||||
#. Optionally, delete the container
|
||||
.. code-block:: bash
|
||||
|
||||
./build-container.sh -c delete
|
||||
|
||||
#. Install the resulting package
|
||||
|
||||
Debian
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install -f sunshine-build/sunshine.deb
|
||||
|
||||
Red Hat
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf install sunshine-build/sunshine.rpm
|
||||
43
docs/source/building/macos.rst
Normal file
43
docs/source/building/macos.rst
Normal file
@@ -0,0 +1,43 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/building/macos.rst
|
||||
|
||||
macOS
|
||||
=====
|
||||
|
||||
Requirements
|
||||
------------
|
||||
macOS Big Sur and Xcode 12.5+
|
||||
|
||||
Use either `MacPorts <https://www.macports.org>`_ or `Homebrew <https://brew.sh>`_
|
||||
|
||||
MacPorts
|
||||
""""""""
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
sudo port install cmake boost ffmpeg libopus
|
||||
|
||||
Homebrew
|
||||
""""""""
|
||||
Install Requirements
|
||||
.. code-block:: bash
|
||||
|
||||
brew install boost cmake ffmpeg opus
|
||||
# if there are issues with an SSL header that is not found:
|
||||
cd /usr/local/include
|
||||
ln -s ../opt/openssl/include/openssl .
|
||||
|
||||
Build
|
||||
-----
|
||||
.. Attention:: Ensure you are in the build directory created during the clone step earlier before continuing.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake ..
|
||||
make -j ${nproc}
|
||||
|
||||
cpack -G DragNDrop # optionally, create a macOS dmg package
|
||||
|
||||
If cmake fails complaining to find Boost, try to set the path explicitly.
|
||||
|
||||
``cmake -DBOOST_ROOT=[boost path] ..``, e.g., ``cmake -DBOOST_ROOT=/opt/local/libexec/boost/1.76 ..``
|
||||
|
||||
27
docs/source/building/windows.rst
Normal file
27
docs/source/building/windows.rst
Normal file
@@ -0,0 +1,27 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/building/windows.rst
|
||||
|
||||
Windows
|
||||
=======
|
||||
|
||||
Requirements
|
||||
------------
|
||||
First you need to install `MSYS2 <https://www.msys2.org>`_, then startup "MSYS2 MinGW 64-bit" and install the
|
||||
following packages using:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pacman -S mingw-w64-x86_64-binutils mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git mingw-w64-x86_64-make cmake make gcc
|
||||
|
||||
Build
|
||||
-----
|
||||
.. Attention:: Ensure you are in the build directory created during the clone step earlier before continuing.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cmake -G"Unix Makefiles" ..
|
||||
cmake -G"MinGW Makefiles" .. # alternatively
|
||||
|
||||
mingw32-make
|
||||
|
||||
cpack -G NSIS # optionally, create a windows installer
|
||||
cpack -G ZIP # optionally, create a windows standalone package
|
||||
97
docs/source/conf.py
Normal file
97
docs/source/conf.py
Normal file
@@ -0,0 +1,97 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# standard imports
|
||||
from datetime import datetime
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__)) # the directory of this file
|
||||
source_dir = os.path.dirname(script_dir) # the source folder directory
|
||||
root_dir = os.path.dirname(source_dir) # the root folder directory
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
project = 'Sunshine'
|
||||
copyright = f'{datetime.now ().year}, {project}'
|
||||
author = 'ReenigneArcher'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
with open(os.path.join(root_dir, 'CMakeLists.txt'), 'r') as f:
|
||||
version = re.search(r"project\(Sunshine VERSION ((\d+)\.(\d+)\.(\d+))", str(f.read())).group(1)
|
||||
"""
|
||||
To use cmake method for obtaining version instead of regex,
|
||||
1. Within CMakeLists.txt add the following line without backticks:
|
||||
``configure_file(docs/source/conf.py.in "${CMAKE_CURRENT_SOURCE_DIR}/docs/source/conf.py" @ONLY)``
|
||||
2. Rename this file to ``conf.py.in``
|
||||
3. Uncomment the next line
|
||||
"""
|
||||
# version = '@PROJECT_VERSION@' # use this for cmake configure_file method
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'm2r2', # enable markdown files
|
||||
'sphinx.ext.autosectionlabel',
|
||||
'sphinx.ext.todo', # enable to-do sections
|
||||
'sphinx.ext.viewcode', # add links to view source code
|
||||
'sphinx_copybutton', # add a copy button to code blocks
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
# templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['toc.rst']
|
||||
|
||||
# Extensions to include.
|
||||
source_suffix = ['.rst', '.md']
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
# html_static_path = ['_static']
|
||||
|
||||
html_logo = os.path.join(root_dir, 'sunshine.png')
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
html_theme_options = {
|
||||
# 'analytics_id': 'G-XXXXXXXXXX', # Provided by Google in your dashboard
|
||||
# 'analytics_anonymize_ip': False,
|
||||
'logo_only': False,
|
||||
'display_version': False,
|
||||
'prev_next_buttons_location': 'bottom',
|
||||
'style_external_links': True,
|
||||
'vcs_pageview_mode': 'blob',
|
||||
'style_nav_header_background': '#151515',
|
||||
# Toc options
|
||||
'collapse_navigation': True,
|
||||
'sticky_navigation': True,
|
||||
'navigation_depth': 4,
|
||||
'includehidden': True,
|
||||
'titles_only': False,
|
||||
}
|
||||
|
||||
# extension config options
|
||||
autosectionlabel_prefix_document = True # Make sure the target is unique
|
||||
todo_include_todos = True
|
||||
39
docs/source/contributing/contributing.rst
Normal file
39
docs/source/contributing/contributing.rst
Normal file
@@ -0,0 +1,39 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/contributing/contributing.rst
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
.. Tip:: If this is your first time contributing to an open source project, it is a good idea to read
|
||||
MDN's `Basic etiquette for open source projects`_ first. There are a few best practices to adopt that will help
|
||||
ensure that you and the other project contributors feel valued and safe, and stay productive.
|
||||
|
||||
#. Fork the repo on GitHub
|
||||
#. Create a new branch for the feature you are adding or the issue you are fixing
|
||||
|
||||
.. Tip:: Base the new branch off the `nightly` branch. It will make your life easier when you submit the PR!
|
||||
|
||||
#. Make changes, push commits, etc.
|
||||
#. Files should contain an empty line at the end.
|
||||
#. Document your code!
|
||||
#. Test your code!
|
||||
#. When ready create a PR to this repo on the `nightly` branch.
|
||||
|
||||
.. Hint:: If you accidentally make your PR against a different branch, a bot will comment letting you know it's on
|
||||
the wrong branch. Don't worry. You can edit the PR to change the target branch. There is no reason to close the
|
||||
PR!
|
||||
|
||||
.. Note:: Draft PRs are also welcome as you work through issues. The benefit of creating a draft PR is that an
|
||||
automated build can run in a github runner.
|
||||
|
||||
.. Attention:: Do not expect partially complete PRs to be merged. These topics will be considered before merging.
|
||||
|
||||
- Does the code follows the style guidelines of this project?
|
||||
|
||||
.. Tip:: Look at examples of existing code in the project!
|
||||
|
||||
- Is the code well commented?
|
||||
- Were documentation blocks updated for new or modified components?
|
||||
|
||||
.. Note:: Developers and maintainers will attempt to assist with challenging issues.
|
||||
|
||||
.. _Basic etiquette for open source projects: https://developer.mozilla.org/en-US/docs/MDN/Contribute/Open_source_etiquette
|
||||
84
docs/source/contributing/localization.rst
Normal file
84
docs/source/contributing/localization.rst
Normal file
@@ -0,0 +1,84 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/contributing/localization.rst
|
||||
|
||||
Localization
|
||||
============
|
||||
Sunshine is being localized into various languages. The default language is `en` (English) and is highlighted green.
|
||||
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=de&style=for-the-badge&query=%24.progress.0.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=green&label=en&style=for-the-badge&query=%24.progress.1.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=en-GB&style=for-the-badge&query=%24.progress.2.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=en-US&style=for-the-badge&query=%24.progress.3.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=es-ES&style=for-the-badge&query=%24.progress.4.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=fr&style=for-the-badge&query=%24.progress.5.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=it&style=for-the-badge&query=%24.progress.6.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
.. image:: https://img.shields.io/badge/dynamic/json?color=blue&label=ru&style=for-the-badge&query=%24.progress.7.data.translationProgress&url=https%3A%2F%2Fbadges.awesome-crowdin.com%2Fstats-15178612-503956.json
|
||||
|
||||
Graph
|
||||
.. image:: https://badges.awesome-crowdin.com/translation-15178612-503956.png
|
||||
|
||||
CrowdIn
|
||||
-------
|
||||
The translations occur on
|
||||
`CrowdIn <https://crowdin.com/project/sunshinestream>`_. Feel free to contribute to localization there.
|
||||
Only elements of the API are planned to be translated.
|
||||
|
||||
.. Attention:: The rest API has not yet been implemented.
|
||||
|
||||
Translations Basics
|
||||
- The brand names `LizardByte` and `Sunshine` should never be translated.
|
||||
- Other brand names should never be translated.
|
||||
Examples:
|
||||
|
||||
- AMD
|
||||
- Nvidia
|
||||
|
||||
CrowdIn Integration
|
||||
How does it work?
|
||||
|
||||
When a change is made to sunshine source code, a workflow generates new translation templates
|
||||
that get pushed to CrowdIn automatically.
|
||||
|
||||
When translations are updated on CrowdIn, a push gets made to the `l10n_nightly` branch and a PR is made against the
|
||||
`nightly` branch. Once PR is merged, all updated translations are part of the project and will be included in the
|
||||
next release.
|
||||
|
||||
Extraction
|
||||
----------
|
||||
There should be minimal cases where strings need to be extracted from source code; however it may be necessary in some
|
||||
situations. For example if a system tray icon is added it should be localized as it is user interfacing.
|
||||
|
||||
- Wrap the string to be extracted in a function as shown.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
#include <boost/locale.hpp>
|
||||
boost::locale::translate("Hello world!")
|
||||
|
||||
.. Tip:: More examples can be found in the documentation for
|
||||
`boost locale <https://www.boost.org/doc/libs/1_70_0/libs/locale/doc/html/messages_formatting.html>`_.
|
||||
|
||||
.. Warning:: This is for information only. Contributors should never include manually updated template files, or
|
||||
manually compiled language files in Pull Requests.
|
||||
|
||||
Strings are automatically extracted from the code to the `locale/sunshine.po` template file. The generated file is
|
||||
used by CrowdIn to generate language specific template files. The file is generated using the
|
||||
`.github/workflows/localize.yml` workflow and is run on any push event into the `nightly` branch. Jobs are only run if
|
||||
any of the following paths are modified.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- 'src/**'
|
||||
|
||||
When testing locally it may be desirable to manually extract, initialize, update, and compile strings. Python is
|
||||
required for this, along with the python dependencies in the `./scripts/requirements.txt` file. Additionally,
|
||||
`xgettext <https://www.gnu.org/software/gettext/>`_ must be installed.
|
||||
|
||||
Extract, initialize, and update
|
||||
.. code-block:: bash
|
||||
|
||||
python ./scripts/_locale.py --extract --init --update
|
||||
|
||||
Compile
|
||||
.. code-block:: bash
|
||||
|
||||
python ./scripts/_locale.py --compile
|
||||
42
docs/source/contributing/testing.rst
Normal file
42
docs/source/contributing/testing.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
:github_url: https://github.com/RetroArcher/RetroArcher/tree/nightly/docs/source/contributing/testing.rst
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
Clang Format
|
||||
------------
|
||||
Source code is tested against the `.clang-format` file for linting errors. The workflow file responsible for clang
|
||||
format testing is `.github/workflows/clang.yml`.
|
||||
|
||||
Test clang-format locally.
|
||||
.. Todo:: This documentation needs to be improved.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
clang-format ...
|
||||
|
||||
Sphinx
|
||||
------
|
||||
Sunshine uses `Sphinx <https://www.sphinx-doc.org/en/master/>`_ for documentation building. Sphinx is included
|
||||
in the `./scripts/requirements.txt` file. Python is required to build sphinx docs. Installation and setup of python
|
||||
will not be covered here.
|
||||
|
||||
The config file for Sphinx is `docs/source/conf.py`. This is already included in the repo and should not be modified.
|
||||
|
||||
Test with Sphinx
|
||||
.. code-block:: bash
|
||||
|
||||
cd docs
|
||||
make html
|
||||
|
||||
Alternatively
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd docs
|
||||
sphinx-build -b html source build
|
||||
|
||||
Unit Testing
|
||||
------------
|
||||
.. Todo:: Sunshine does not currently have any unit tests. If you would like to help us improve please get in contact
|
||||
with us, or make a PR with suggested changes.
|
||||
5
docs/source/index.rst
Normal file
5
docs/source/index.rst
Normal file
@@ -0,0 +1,5 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/index.rst
|
||||
|
||||
Table of Contents
|
||||
=================
|
||||
.. include:: toc.rst
|
||||
36
docs/source/toc.rst
Normal file
36
docs/source/toc.rst
Normal file
@@ -0,0 +1,36 @@
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: About
|
||||
|
||||
about/overview
|
||||
about/installation
|
||||
about/docker
|
||||
about/third_party_packages
|
||||
about/usage
|
||||
about/advanced_usage
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Troubleshooting
|
||||
|
||||
troubleshooting/general
|
||||
troubleshooting/linux
|
||||
troubleshooting/macos
|
||||
troubleshooting/windows
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Build
|
||||
|
||||
building/build
|
||||
building/linux
|
||||
building/macos
|
||||
building/windows
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contributing
|
||||
|
||||
contributing/contributing
|
||||
contributing/localization
|
||||
contributing/testing
|
||||
13
docs/source/troubleshooting/general.rst
Normal file
13
docs/source/troubleshooting/general.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/troubleshooting/general.rst
|
||||
|
||||
General
|
||||
=======
|
||||
If you forgot your credentials to the web UI, try this.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sunshine -creds <new username> <new password>
|
||||
|
||||
Can't access the web UI?
|
||||
|
||||
#. Check firefall rules.
|
||||
9
docs/source/troubleshooting/linux.rst
Normal file
9
docs/source/troubleshooting/linux.rst
Normal file
@@ -0,0 +1,9 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/troubleshooting/linux.rst
|
||||
|
||||
Linux
|
||||
=====
|
||||
If screencasting fails with Wayland, you may need to run the following to force screencasting with X11.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo setcap -r $(readlink -f $(which sunshine))
|
||||
29
docs/source/troubleshooting/macos.rst
Normal file
29
docs/source/troubleshooting/macos.rst
Normal file
@@ -0,0 +1,29 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/troubleshooting/macos.rst
|
||||
|
||||
macOS
|
||||
=====
|
||||
If you get this error:
|
||||
|
||||
``Dynamic session lookup supported but failed: launchd did not provide a socket path, verify that
|
||||
org.freedesktop.dbus-session.plist is loaded!``
|
||||
|
||||
Try this.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
launchctl load -w /Library/LaunchAgents/org.freedesktop.dbus-session.plist
|
||||
|
||||
Uninstall:
|
||||
|
||||
- pkg
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo chmod +x /opt/local/etc/sunshine/assets/uninstall_pkg.sh
|
||||
sudo /opt/local/etc/sunshine/assets/uninstall_pkg.sh
|
||||
|
||||
- Portfile
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo port uninstall Sunshine
|
||||
7
docs/source/troubleshooting/windows.rst
Normal file
7
docs/source/troubleshooting/windows.rst
Normal file
@@ -0,0 +1,7 @@
|
||||
:github_url: https://github.com/LizardByte/Sunshine/tree/nightly/docs/source/troubleshooting/windows.rst
|
||||
|
||||
Windows
|
||||
=======
|
||||
No gamepad is detected.
|
||||
|
||||
#. Verify that you've installed `ViGEmBus <https://github.com/ViGEm/ViGEmBus/releases/latest>`_.
|
||||
94
gen-deb.in
94
gen-deb.in
@@ -1,94 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ ! "@SUNSHINE_UNDEFINED_VARIABLE@" = "" ]; then
|
||||
echo "Please run gen-deb generated by cmake inside the build directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -d package-deb ]; then
|
||||
echo "package-deb already exists: It will be replaced"
|
||||
rm -rf package-deb
|
||||
fi
|
||||
|
||||
export DEBIAN=@CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine/DEBIAN
|
||||
export RULES=@CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine/etc/udev/rules.d
|
||||
export BIN=@CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine/usr/bin
|
||||
export SERVICE=@CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine/usr/lib/systemd/user
|
||||
export ASSETS=@CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine/etc/sunshine
|
||||
|
||||
mkdir -p $DEBIAN
|
||||
mkdir -p $RULES
|
||||
mkdir -p $BIN
|
||||
mkdir -p $ASSETS/shaders
|
||||
mkdir -p $SERVICE
|
||||
|
||||
if [ ! -f sunshine ]; then
|
||||
echo "Error: Can't find sunshine"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat << 'EOF' > $DEBIAN/conffiles
|
||||
/etc/sunshine/sunshine.conf
|
||||
/etc/sunshine/apps_linux.json
|
||||
EOF
|
||||
|
||||
cat << 'EOF' > $DEBIAN/control
|
||||
Package: sunshine
|
||||
Architecture: amd64
|
||||
Maintainer: @loki
|
||||
Priority: optional
|
||||
Version: 0.8.1
|
||||
Depends: libssl1.1, libavdevice58, libboost-thread1.67.0 | libboost-thread1.71.0, libboost-filesystem1.67.0 | libboost-filesystem1.71.0, libboost-log1.67.0 | libboost-log1.71.0, libpulse0, libopus0, libxcb-shm0, libxcb-xfixes0, libxtst6, libevdev2
|
||||
Description: Gamestream host for Moonlight
|
||||
EOF
|
||||
|
||||
cat << 'EOF' > $DEBIAN/postinst
|
||||
#!/bin/sh
|
||||
|
||||
export GROUP_INPUT=input
|
||||
|
||||
if [ -f /etc/group ]; then
|
||||
if ! grep -q $GROUP_INPUT /etc/group; then
|
||||
echo "Creating group $GROUP_INPUT"
|
||||
|
||||
groupadd $GROUP_INPUT
|
||||
fi
|
||||
else
|
||||
echo "Warning: /etc/group not found"
|
||||
fi
|
||||
|
||||
# Update permissions on config files for Web Manager
|
||||
if [ -f /etc/sunshine/apps_linux.json ]; then
|
||||
echo "chmod 666 /etc/sunshine/apps_linux.json"
|
||||
chmod 666 /etc/sunshine/apps_linux.json
|
||||
fi
|
||||
|
||||
if [ -f /etc/sunshine/sunshine.conf ]; then
|
||||
echo "chmod 666 /etc/sunshine/sunshine.conf"
|
||||
chmod 666 /etc/sunshine/sunshine.conf
|
||||
fi
|
||||
EOF
|
||||
|
||||
cat << 'EOF' > $RULES/85-sunshine-rules.rules
|
||||
KERNEL=="uinput", GROUP="input", MODE="0660"
|
||||
EOF
|
||||
|
||||
cp sunshine $BIN/sunshine
|
||||
cp @CMAKE_CURRENT_SOURCE_DIR@/assets/apps_linux.json $ASSETS/apps_linux.json
|
||||
cp @CMAKE_CURRENT_SOURCE_DIR@/assets/sunshine.conf $ASSETS/sunshine.conf
|
||||
cp @CMAKE_CURRENT_BINARY_DIR@/sunshine.service $SERVICE/sunshine.service
|
||||
cp -r @CMAKE_CURRENT_SOURCE_DIR@/assets/web $ASSETS/web
|
||||
cp -r @CMAKE_CURRENT_SOURCE_DIR@/assets/shaders/opengl $ASSETS/shaders/opengl
|
||||
|
||||
chmod 755 $DEBIAN/postinst
|
||||
chmod 755 $BIN/sunshine
|
||||
chmod 644 $RULES/85-sunshine-rules.rules
|
||||
chmod 666 $ASSETS/apps_linux.json
|
||||
chmod 666 $ASSETS/sunshine.conf
|
||||
|
||||
cd package-deb
|
||||
if fakeroot dpkg-deb --build sunshine; then
|
||||
echo "generated debian package: @CMAKE_CURRENT_BINARY_DIR@/package-deb/sunshine.deb"
|
||||
fi
|
||||
cd ..
|
||||
|
||||
55
packaging/linux/aur/PKGBUILD
Normal file
55
packaging/linux/aur/PKGBUILD
Normal file
@@ -0,0 +1,55 @@
|
||||
# Edit on github: https://github.com/LizardByte/Sunshine/tree/nightly/packaging/linux/aur/PKGBUILD
|
||||
# Reference: https://wiki.archlinux.org/title/PKGBUILD
|
||||
|
||||
pkgname=@SUNSHINE_AUR_PKG@
|
||||
pkgver=@PROJECT_VERSION@@SUNSHINE_SUB_VERSION@
|
||||
pkgrel=1
|
||||
pkgdesc="@PROJECT_DESCRIPTION@"
|
||||
arch=('x86_64' 'i686')
|
||||
url=@PROJECT_HOMEPAGE_URL@
|
||||
license=('GPL3')
|
||||
|
||||
depends=('avahi' 'boost-libs' 'ffmpeg4.4' 'libevdev' 'libpulse' 'libx11' 'libxcb' 'libxfixes' 'libxrandr' 'libxtst' 'openssl' 'opus' 'udev')
|
||||
makedepends=('boost' 'cmake' 'git' 'make')
|
||||
optdepends=('cuda' 'libcap' 'libdrm')
|
||||
|
||||
provides=(@SUNSHINE_AUR_PROVIDES@)
|
||||
conflicts=(@SUNSHINE_AUR_CONFLICTS@)
|
||||
|
||||
source=("$pkgname::git+@GITHUB_CLONE_URL@#commit=@GITHUB_COMMIT@")
|
||||
sha256sums=('SKIP')
|
||||
|
||||
prepare() {
|
||||
cd "$pkgname"
|
||||
git submodule update --recursive --init
|
||||
}
|
||||
|
||||
build() {
|
||||
export CFLAGS="${CFLAGS/-Werror=format-security/}"
|
||||
export CXXFLAGS="${CXXFLAGS/-Werror=format-security/}"
|
||||
|
||||
cmake \
|
||||
-S "$pkgname" \
|
||||
-B build \
|
||||
-Wno-dev \
|
||||
-D SUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine \
|
||||
-D CMAKE_INSTALL_PREFIX="/usr" \
|
||||
-D SUNSHINE_ASSETS_DIR="share/sunshine/assets" \
|
||||
-D SUNSHINE_CONFIG_DIR="share/sunshine/config" \
|
||||
-D LIBAVCODEC_INCLUDE_DIR=/usr/include/ffmpeg4.4 \
|
||||
-D LIBAVCODEC_LIBRARIES=/usr/lib/ffmpeg4.4/libavcodec.so \
|
||||
-D LIBAVDEVICE_INCLUDE_DIR=/usr/include/ffmpeg4.4 \
|
||||
-D LIBAVDEVICE_LIBRARIES=/usr/lib/ffmpeg4.4/libavdevice.so \
|
||||
-D LIBAVFORMAT_INCLUDE_DIR=/usr/include/ffmpeg4.4 \
|
||||
-D LIBAVFORMAT_LIBRARIES=/usr/lib/ffmpeg4.4/libavformat.so \
|
||||
-D LIBAVUTIL_INCLUDE_DIR=/usr/include/ffmpeg4.4 \
|
||||
-D LIBAVUTIL_LIBRARIES=/usr/lib/ffmpeg4.4/libavutil.so \
|
||||
-D LIBSWSCALE_INCLUDE_DIR=/usr/include/ffmpeg4.4 \
|
||||
-D LIBSWSCALE_LIBRARIES=/usr/lib/ffmpeg4.4/libswscale.so
|
||||
|
||||
make -C build
|
||||
}
|
||||
|
||||
package() {
|
||||
make -C build install DESTDIR="$pkgdir"
|
||||
}
|
||||
216
packaging/linux/flatpak/dev.lizardbyte.sunshine.yml
Normal file
216
packaging/linux/flatpak/dev.lizardbyte.sunshine.yml
Normal file
@@ -0,0 +1,216 @@
|
||||
---
|
||||
app-id: dev.lizardbyte.sunshine
|
||||
runtime: org.freedesktop.Platform
|
||||
runtime-version: "21.08"
|
||||
sdk: org.freedesktop.Sdk
|
||||
command: sunshine
|
||||
separate-locales: false
|
||||
finish-args:
|
||||
- --device=all
|
||||
- --env=PULSE_PROP_media.category=Manager
|
||||
- --persist=.config/sunshine
|
||||
- --share=ipc
|
||||
- --share=network
|
||||
- --socket=pulseaudio
|
||||
- --socket=wayland
|
||||
- --socket=x11
|
||||
- --system-talk-name=org.freedesktop.Avahi
|
||||
- --talk-name=org.freedesktop.Flatpak
|
||||
|
||||
cleanup:
|
||||
- /include
|
||||
- /lib/cmake
|
||||
- /lib/pkgconfig
|
||||
- /lib/*.la
|
||||
- /lib/*.a
|
||||
- /share
|
||||
|
||||
modules:
|
||||
- name: cuda
|
||||
disabled: false
|
||||
buildsystem: simple
|
||||
only-arches:
|
||||
- x86_64
|
||||
- aarch64
|
||||
cleanup:
|
||||
- '*'
|
||||
build-commands:
|
||||
- chmod u+x ./cuda.run
|
||||
- ./cuda.run --silent --toolkit --toolkitpath=$FLATPAK_DEST/cuda --no-opengl-libs --no-man-page --no-drm --tmpdir=$FLATPAK_BUILDER_BUILDDIR # yamllint disable-line rule:line-length
|
||||
- rm -r $FLATPAK_DEST/cuda/nsight-systems-2021.3.2
|
||||
- rm ./cuda.run
|
||||
sources:
|
||||
- type: file
|
||||
only-arches:
|
||||
- x86_64
|
||||
url: https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run
|
||||
sha256: bbd87ca0e913f837454a796367473513cddef555082e4d86ed9a38659cc81f0a
|
||||
dest-filename: cuda.run
|
||||
- type: file
|
||||
only-arches:
|
||||
- aarch64
|
||||
url: https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux_sbsa.run # yamllint disable-line rule:line-length
|
||||
sha256: f2c4a52e06329606c8dfb7c5ea3f4cb4c0b28f9d3fdffeeb734fcc98daf580d8
|
||||
dest-filename: cuda.run
|
||||
|
||||
- name: boost
|
||||
buildsystem: simple
|
||||
build-commands:
|
||||
- ./bootstrap.sh --prefix=$FLATPAK_DEST --with-libraries=system,thread,log
|
||||
- ./b2 install variant=release link=static,shared runtime-link=shared cxxflags="$CXXFLAGS" linkflags="$LDFLAGS" -j $FLATPAK_BUILDER_N_JOBS # yamllint disable-line rule:line-length
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2
|
||||
sha256: 475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39
|
||||
|
||||
- name: ffmpeg
|
||||
config-opts:
|
||||
- --enable-gpl
|
||||
- --disable-static
|
||||
- --enable-shared
|
||||
- --disable-doc
|
||||
- --disable-programs
|
||||
- --disable-decoders
|
||||
- --enable-libfontconfig
|
||||
- --enable-libfreetype
|
||||
- --enable-libopus
|
||||
- --enable-libvorbis
|
||||
- --enable-libvpx
|
||||
- --enable-libx264
|
||||
- --enable-libx265
|
||||
- --enable-nvenc
|
||||
- --enable-encoder=h264_v4l2m2m
|
||||
- --enable-encoder=hevc_v4l2m2m
|
||||
# - --enable-nonfree
|
||||
# - --enable-cuda-nvcc
|
||||
# - --enable-libnpp
|
||||
# - --extra-cflags=-I${FLATPAK_DEST}/cuda/include
|
||||
# - --extra-ldflags=-L${FLATPAK_DEST}/cuda/lib64
|
||||
# - --nvccflags="-gencode arch=compute_52,code=sm_52 -O2"
|
||||
cleanup:
|
||||
- /share/ffmpeg/examples
|
||||
sources:
|
||||
- type: archive
|
||||
url: http://archive.ubuntu.com/ubuntu/pool/universe/f/ffmpeg/ffmpeg_4.4.2.orig.tar.xz
|
||||
sha256: af419a7f88adbc56c758ab19b4c708afbcae15ef09606b82b855291f6a6faa93
|
||||
modules:
|
||||
- name: vmaf
|
||||
buildsystem: meson
|
||||
subdir: libvmaf
|
||||
cleanup:
|
||||
- /bin
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/Netflix/vmaf/archive/refs/tags/v2.3.1.tar.gz
|
||||
sha256: 8d60b1ddab043ada25ff11ced821da6e0c37fd7730dd81c24f1fc12be7293ef2
|
||||
- name: x264
|
||||
config-opts:
|
||||
- --disable-cli
|
||||
- --enable-shared
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://code.videolan.org/videolan/x264/-/archive/stable/x264-stable.tar.bz2
|
||||
sha256: 8fedb184045722d8cc39353099373a5b7350171d0964d01fff8eced21b959b29
|
||||
- name: x265
|
||||
buildsystem: cmake-ninja
|
||||
builddir: true
|
||||
subdir: source
|
||||
config-opts:
|
||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- -DENABLE_CLI=OFF
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://bitbucket.org/multicoreware/x265_git/downloads/x265_3.5.tar.gz
|
||||
sha256: e70a3335cacacbba0b3a20ec6fecd6783932288ebc8163ad74bcc9606477cae8
|
||||
- name: ffnvcodec
|
||||
no-autogen: true
|
||||
make-install-args:
|
||||
- PREFIX=${FLATPAK_DEST}
|
||||
cleanup:
|
||||
- '*'
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/FFmpeg/nv-codec-headers/archive/refs/tags/n11.1.5.1.tar.gz
|
||||
sha256: d095fbd56aa93772471a323be0ebe65504a0f43f06c76a30b6d25da77b06ae9c
|
||||
|
||||
- name: avahi
|
||||
cleanup:
|
||||
- /bin
|
||||
- /lib/avahi
|
||||
- /share/applications/*.desktop
|
||||
- /share/avahi
|
||||
config-opts:
|
||||
- --with-distro=none
|
||||
- --disable-gobject
|
||||
- --disable-introspection
|
||||
- --disable-qt3
|
||||
- --disable-qt4
|
||||
- --disable-qt5
|
||||
- --disable-gtk
|
||||
- --disable-core-docs
|
||||
- --disable-manpages
|
||||
- --disable-libdaemon
|
||||
- --disable-python
|
||||
- --disable-pygobject
|
||||
- --disable-mono
|
||||
- --disable-monodoc
|
||||
- --disable-autoipd
|
||||
- --disable-doxygen-doc
|
||||
- --disable-doxygen-dot
|
||||
- --disable-doxygen-xml
|
||||
- --disable-doxygen-html
|
||||
- --disable-manpages
|
||||
- --disable-xmltoman
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://avahi.org/download/avahi-0.8.tar.gz
|
||||
sha256: 060309d7a333d38d951bc27598c677af1796934dbd98e1024e7ad8de798fedda
|
||||
modules:
|
||||
- name: libevent
|
||||
cleanup:
|
||||
- /bin
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz # yamllint disable-line rule:line-length
|
||||
sha256: 92e6de1be9ec176428fd2367677e61ceffc2ee1cb119035037a27d346b0403bb
|
||||
|
||||
- name: libevdev
|
||||
buildsystem: meson
|
||||
cleanup:
|
||||
- /bin
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://www.freedesktop.org/software/libevdev/libevdev-1.12.1.tar.xz
|
||||
sha256: 1dbba41bc516d3ca7abc0da5b862efe3ea8a7018fa6e9b97ce9d39401b22426c
|
||||
modules:
|
||||
- name: libcheck
|
||||
buildsystem: cmake
|
||||
cleanup:
|
||||
- /bin
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/libcheck/check/archive/refs/tags/0.15.2.tar.gz
|
||||
sha256: 998d355294bb94072f40584272cf4424571c396c631620ce463f6ea97aa67d2e
|
||||
|
||||
- name: sunshine
|
||||
buildsystem: cmake
|
||||
no-make-install: false
|
||||
builddir: true
|
||||
build-options:
|
||||
cxxflags: -I${C_INCLUDE_PATH}/libevdev-1.0
|
||||
config-opts:
|
||||
- -DCMAKE_BUILD_TYPE=Release
|
||||
- -DCMAKE_INSTALL_PREFIX=/app
|
||||
- -DCMAKE_CUDA_COMPILER=/app/cuda/bin/nvcc
|
||||
- -DSUNSHINE_ASSETS_DIR=assets
|
||||
- -DSUNSHINE_CONFIG_DIR=config
|
||||
- -DSUNSHINE_EXECUTABLE_PATH=/app/bin/sunshine
|
||||
- -DSUNSHINE_ENABLE_WAYLAND=ON
|
||||
- -DSUNSHINE_ENABLE_X11=ON
|
||||
- -DSUNSHINE_ENABLE_DRM=ON
|
||||
- -DSUNSHINE_ENABLE_CUDA=ON
|
||||
sources:
|
||||
- type: git
|
||||
url: '@GITHUB_CLONE_URL@'
|
||||
branch: '@GITHUB_BRANCH@'
|
||||
commit: '@GITHUB_COMMIT@'
|
||||
12
packaging/linux/sunshine.desktop
Normal file
12
packaging/linux/sunshine.desktop
Normal file
@@ -0,0 +1,12 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=@PROJECT_NAME@
|
||||
Exec=sunshine
|
||||
Version=1.0
|
||||
Comment=@PROJECT_DESCRIPTION@
|
||||
Icon=sunshine
|
||||
Categories=Utility;
|
||||
Terminal=true
|
||||
X-AppImage-Name=sunshine
|
||||
X-AppImage-Version=@PROJECT_VERSION@
|
||||
X-AppImage-Arch=x86_64
|
||||
84
packaging/macos/Portfile
Normal file
84
packaging/macos/Portfile
Normal file
@@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
|
||||
|
||||
# initial PR into macports: https://github.com/macports/macports-ports/pull/15143
|
||||
|
||||
PortSystem 1.0
|
||||
PortGroup cmake 1.1
|
||||
PortGroup github 1.0
|
||||
PortGroup boost 1.0
|
||||
|
||||
name @PROJECT_NAME@
|
||||
version @PROJECT_VERSION@
|
||||
revision 0
|
||||
categories multimedia emulators games
|
||||
platforms darwin
|
||||
license GPL-3
|
||||
maintainers @LizardByte
|
||||
description @PROJECT_DESCRIPTION@
|
||||
|
||||
# long_description will not be split into multiple lines as it's configured by CMakeLists
|
||||
long_description @PROJECT_LONG_DESCRIPTION@
|
||||
homepage @PROJECT_HOMEPAGE_URL@
|
||||
master_sites https://github.com/lizardbyte/sunshine/releases
|
||||
|
||||
compiler.cxx_standard 2017
|
||||
fetch.type git
|
||||
|
||||
git.url @GITHUB_CLONE_URL@
|
||||
git.branch @GITHUB_COMMIT@
|
||||
|
||||
post-fetch {
|
||||
system -W ${worksrcpath} "${git.cmd} submodule update --init --recursive"
|
||||
}
|
||||
|
||||
depends_lib port:avahi \
|
||||
port:ffmpeg \
|
||||
port:libopus
|
||||
|
||||
boost.version 1.76
|
||||
|
||||
configure.args -DCMAKE_INSTALL_PREFIX=${prefix} \
|
||||
-DSUNSHINE_ASSETS_DIR=etc/sunshine/assets \
|
||||
-DSUNSHINE_CONFIG_DIR=etc/sunshine/config
|
||||
|
||||
startupitem.create yes
|
||||
startupitem.executable "${prefix}/bin/{$name}"
|
||||
startupitem.location LaunchDaemons
|
||||
startupitem.name ${name}
|
||||
startupitem.netchange yes
|
||||
|
||||
platform darwin {
|
||||
if { ${os.major} < 20 } {
|
||||
# See: https://github.com/LizardByte/Sunshine/discussions/117#discussioncomment-2513494
|
||||
notes-append "Port is limited to software encoding, when used with macOS releases prior to Big Sur."
|
||||
}
|
||||
}
|
||||
|
||||
# destroot not required as cmake install directive handles moving files
|
||||
|
||||
# # Rename files in `destroot`
|
||||
# post-destroot {
|
||||
# file rename ${destroot}${prefix}/etc/${name}/config/sunshine.conf ${destroot}${prefix}/etc/${name}/config/sunshine.conf.sample
|
||||
# file rename ${destroot}${prefix}/etc/${name}/config/apps.json ${destroot}${prefix}/etc/${name}/config/apps.json.sample
|
||||
# }
|
||||
|
||||
# # Don't overwrite existing preference files
|
||||
# post-activate {
|
||||
# if {![file exists ${prefix}/etc/${name}/config/sunshine.conf]} {
|
||||
# file copy ${destroot}${prefix}/etc/${name}/config/sunshine.conf.sample \
|
||||
# ${prefix}/etc/${name}/config/sunshine.conf
|
||||
# }
|
||||
# if {![file exists ${prefix}/etc/${name}/config/apps.json]} {
|
||||
# file copy ${destroot}${prefix}/etc/${name}/config/apps.json.sample \
|
||||
# ${prefix}/etc/${name}/config/apps.json
|
||||
# }
|
||||
# }
|
||||
|
||||
# disabled not overwriting config files... these are the default config files required by Sunshine
|
||||
# this did not work with pkg created by macports
|
||||
# we should always install the default files and user should start sunshine like "sunshine <path to user config file>"
|
||||
# if the file doesn't exist sunshine will copy the default config to that location
|
||||
notes-append "Run @PROJECT_NAME@ by executing 'sunshine <path to user config>', e.g. 'sunshine ~/sunshine.conf' "
|
||||
notes-append "The config file will be created if it doesn't exist."
|
||||
notes-append "It is recommended to set a location for the apps file in the config."
|
||||
notes-append "See our documentation at 'https://docs.lizardbyte.dev/projects/sunshine/en/v@PROJECT_VERSION@/' for further info."
|
||||
40
scripts/Dockerfile-debian
Normal file
40
scripts/Dockerfile-debian
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM debian:bullseye AS sunshine-debian
|
||||
|
||||
# Debian Bullseye end of life is TBD
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ="Europe/London"
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN echo deb http://deb.debian.org/debian/ bullseye main contrib non-free | tee /etc/apt/sources.list.d/non-free.list
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
nvidia-cuda-dev \
|
||||
nvidia-cuda-toolkit \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-deb"]
|
||||
32
scripts/Dockerfile-fedora_33
Normal file
32
scripts/Dockerfile-fedora_33
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM fedora:33 AS sunshine-fedora_33
|
||||
|
||||
# Fedora 33 end of life is November 2021
|
||||
# This file remains for reference only
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN dnf -y update && \
|
||||
dnf -y group install "Development Tools" && \
|
||||
dnf -y install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm && \
|
||||
dnf -y install \
|
||||
boost-devel \
|
||||
boost-static.x86_64 \
|
||||
cmake \
|
||||
ffmpeg-devel \
|
||||
libevdev-devel \
|
||||
libxcb-devel \
|
||||
libX11-devel \
|
||||
libXfixes-devel \
|
||||
libXrandr-devel \
|
||||
libXtst-devel \
|
||||
openssl-devel \
|
||||
opus-devel \
|
||||
pulseaudio-libs-devel \
|
||||
libcap-devel \
|
||||
libdrm-devel \
|
||||
rpm-build \
|
||||
&& dnf clean all \
|
||||
&& rm -rf /var/cache/yum
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-rpm"]
|
||||
36
scripts/Dockerfile-fedora_35
Normal file
36
scripts/Dockerfile-fedora_35
Normal file
@@ -0,0 +1,36 @@
|
||||
FROM fedora:35 AS sunshine-fedora_35
|
||||
|
||||
# Fedora 35 end of life is TBD
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN dnf -y update && \
|
||||
dnf -y group install "Development Tools" && \
|
||||
dnf -y install https://mirrors.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm && \
|
||||
dnf -y install \
|
||||
boost-devel \
|
||||
boost-static.x86_64 \
|
||||
cmake \
|
||||
ffmpeg-devel \
|
||||
gcc-c++ \
|
||||
libevdev-devel \
|
||||
libX11-devel \
|
||||
libxcb-devel \
|
||||
libXcursor-devel \
|
||||
libXfixes-devel \
|
||||
libXinerama-devel \
|
||||
libXi-devel \
|
||||
libXrandr-devel \
|
||||
libXtst-devel \
|
||||
mesa-libGL-devel \
|
||||
openssl-devel \
|
||||
opus-devel \
|
||||
pulseaudio-libs-devel \
|
||||
libcap-devel \
|
||||
libdrm-devel \
|
||||
rpm-build \
|
||||
&& dnf clean all \
|
||||
&& rm -rf /var/cache/yum
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-rpm"]
|
||||
63
scripts/Dockerfile-ubuntu_18_04
Normal file
63
scripts/Dockerfile-ubuntu_18_04
Normal file
@@ -0,0 +1,63 @@
|
||||
FROM ubuntu:18.04 AS sunshine-ubuntu_18_04
|
||||
|
||||
# Ubuntu 18.04 end of life is April 2028
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ="Europe/London"
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
software-properties-common \
|
||||
&& add-apt-repository ppa:savoury1/graphics && \
|
||||
add-apt-repository ppa:savoury1/multimedia && \
|
||||
add-apt-repository ppa:savoury1/ffmpeg4 && \
|
||||
add-apt-repository ppa:savoury1/boost-defaults-1.71 && \
|
||||
add-apt-repository ppa:ubuntu-toolchain-r/test && \
|
||||
apt-get update -y && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
gcc-10 \
|
||||
git \
|
||||
g++-10 \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem1.71-dev \
|
||||
libboost-log1.71-dev \
|
||||
libboost-regex1.71-dev \
|
||||
libboost-thread1.71-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
wget \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Update gcc alias
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10
|
||||
|
||||
# Install CuDA
|
||||
RUN wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run --progress=bar:force:noscroll -q --show-progress -O /root/cuda.run && chmod a+x /root/cuda.run
|
||||
RUN /root/cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm && rm /root/cuda.run
|
||||
|
||||
# Install cmake
|
||||
ADD https://cmake.org/files/v3.22/cmake-3.22.2-linux-x86_64.sh /cmake-3.22.2-linux-x86_64.sh
|
||||
RUN mkdir /opt/cmake
|
||||
RUN sh /cmake-3.22.2-linux-x86_64.sh --prefix=/opt/cmake --skip-license
|
||||
RUN ln -s /opt/cmake/bin/cmake /usr/local/bin/cmake
|
||||
RUN cmake --version
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-deb"]
|
||||
46
scripts/Dockerfile-ubuntu_20_04
Normal file
46
scripts/Dockerfile-ubuntu_20_04
Normal file
@@ -0,0 +1,46 @@
|
||||
FROM ubuntu:20.04 AS sunshine-ubuntu_20_04
|
||||
|
||||
# Ubuntu 20.04 end of life is April 2030
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ="Europe/London"
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
g++-10 \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
wget \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Update gcc alias
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10
|
||||
|
||||
# Install CuDA
|
||||
RUN wget https://developer.download.nvidia.com/compute/cuda/11.4.2/local_installers/cuda_11.4.2_470.57.02_linux.run --progress=bar:force:noscroll -q --show-progress -O /root/cuda.run && chmod a+x /root/cuda.run
|
||||
RUN /root/cuda.run --silent --toolkit --toolkitpath=/usr --no-opengl-libs --no-man-page --no-drm && rm /root/cuda.run
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-deb"]
|
||||
40
scripts/Dockerfile-ubuntu_21_04
Normal file
40
scripts/Dockerfile-ubuntu_21_04
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM ubuntu:21.04 AS sunshine-ubuntu_21_04
|
||||
|
||||
# Ubuntu 21.04 end of life is January 2022
|
||||
# This file remains for reference only
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ="Europe/London"
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavdevice-dev \
|
||||
libboost-thread-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
nvidia-cuda-dev \
|
||||
nvidia-cuda-toolkit \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-deb"]
|
||||
39
scripts/Dockerfile-ubuntu_21_10
Normal file
39
scripts/Dockerfile-ubuntu_21_10
Normal file
@@ -0,0 +1,39 @@
|
||||
FROM ubuntu:21.10 AS sunshine-ubuntu_21_10
|
||||
|
||||
# Ubuntu 21.10 end of life is July 2022
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TZ="Europe/London"
|
||||
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
RUN apt-get update -y && \
|
||||
apt-get install -y \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavdevice-dev \
|
||||
libboost-filesystem-dev \
|
||||
libboost-log-dev \
|
||||
libboost-thread-dev \
|
||||
libcap-dev \
|
||||
libdrm-dev \
|
||||
libevdev-dev \
|
||||
libpulse-dev \
|
||||
libopus-dev \
|
||||
libssl-dev \
|
||||
libwayland-dev \
|
||||
libx11-dev \
|
||||
libxcb-shm0-dev \
|
||||
libxcb-xfixes0-dev \
|
||||
libxcb1-dev \
|
||||
libxfixes-dev \
|
||||
libxrandr-dev \
|
||||
libxtst-dev \
|
||||
nvidia-cuda-dev \
|
||||
nvidia-cuda-toolkit \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Entrypoint
|
||||
COPY build-private.sh /root/build.sh
|
||||
ENTRYPOINT ["/root/build.sh", "-deb"]
|
||||
170
scripts/_locale.py
Normal file
170
scripts/_locale.py
Normal file
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
..
|
||||
_locale.py
|
||||
|
||||
Functions related to building, initializing, updating, and compiling localization translations.
|
||||
|
||||
Borrowed from RetroArcher.
|
||||
"""
|
||||
# standard imports
|
||||
import argparse
|
||||
import datetime
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
project_name = 'Sunshine'
|
||||
project_owner = 'LizardByte'
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
root_dir = os.path.dirname(script_dir)
|
||||
locale_dir = os.path.join(root_dir, 'locale')
|
||||
project_dir = os.path.join(root_dir, 'src')
|
||||
|
||||
year = datetime.datetime.now().year
|
||||
|
||||
# retroarcher target locales
|
||||
target_locales = [
|
||||
'de', # Deutsch
|
||||
'en', # English
|
||||
'en_GB', # English (United Kingdom)
|
||||
'en_US', # English (United States)
|
||||
'es', # español
|
||||
'fr', # français
|
||||
'it', # italiano
|
||||
'ru', # русский
|
||||
]
|
||||
|
||||
|
||||
def x_extract():
|
||||
"""Executes `xgettext extraction` in subprocess."""
|
||||
|
||||
pot_filepath = os.path.join(locale_dir, f'{project_name.lower()}.po')
|
||||
|
||||
commands = [
|
||||
'xgettext',
|
||||
'--keyword=translate:1,1t',
|
||||
'--keyword=translate:1c,2,2t',
|
||||
'--keyword=translate:1,2,3t',
|
||||
'--keyword=translate:1c,2,3,4t',
|
||||
'--keyword=gettext:1',
|
||||
'--keyword=pgettext:1c,2',
|
||||
'--keyword=ngettext:1,2',
|
||||
'--keyword=npgettext:1c,2,3',
|
||||
f'--default-domain={project_name.lower()}',
|
||||
f'--output={pot_filepath}',
|
||||
'--language=C++',
|
||||
'--boost',
|
||||
'--from-code=utf-8',
|
||||
'-F',
|
||||
f'--msgid-bugs-address=github.com/{project_owner.lower()}/{project_name.lower()}',
|
||||
f'--copyright-holder={project_owner}',
|
||||
f'--package-name={project_name}',
|
||||
'--package-version=v0'
|
||||
]
|
||||
|
||||
extensions = ['cpp', 'h', 'm', 'mm']
|
||||
|
||||
# find input files
|
||||
for root, dirs, files in os.walk(project_dir, topdown=True):
|
||||
for name in files:
|
||||
filename = os.path.join(root, name)
|
||||
extension = filename.rsplit('.', 1)[-1]
|
||||
if extension in extensions: # append input files
|
||||
commands.append(filename)
|
||||
|
||||
print(commands)
|
||||
subprocess.check_output(args=commands, cwd=root_dir)
|
||||
|
||||
try:
|
||||
# fix header
|
||||
body = ""
|
||||
with open(file=pot_filepath, mode='r') as file:
|
||||
for line in file.readlines():
|
||||
if line != '"Language: \\n"\n': # do not include this line
|
||||
if line == '# SOME DESCRIPTIVE TITLE.\n':
|
||||
body += f'# Translations template for {project_name}.\n'
|
||||
elif line.startswith('#') and 'YEAR' in line:
|
||||
body += line.replace('YEAR', str(year))
|
||||
elif line.startswith('#') and 'PACKAGE' in line:
|
||||
body += line.replace('PACKAGE', project_name)
|
||||
else:
|
||||
body += line
|
||||
|
||||
# rewrite pot file with updated header
|
||||
with open(file=pot_filepath, mode='w+') as file:
|
||||
file.write(body)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
|
||||
def babel_init(locale_code: str):
|
||||
"""Executes `pybabel init` in subprocess.
|
||||
|
||||
:param locale_code: str - locale code
|
||||
"""
|
||||
commands = [
|
||||
'pybabel',
|
||||
'init',
|
||||
'-i', os.path.join(locale_dir, f'{project_name.lower()}.po'),
|
||||
'-d', locale_dir,
|
||||
'-D', project_name.lower(),
|
||||
'-l', locale_code
|
||||
]
|
||||
|
||||
print(commands)
|
||||
subprocess.check_output(args=commands, cwd=root_dir)
|
||||
|
||||
|
||||
def babel_update():
|
||||
"""Executes `pybabel update` in subprocess."""
|
||||
commands = [
|
||||
'pybabel',
|
||||
'update',
|
||||
'-i', os.path.join(locale_dir, f'{project_name.lower()}.po'),
|
||||
'-d', locale_dir,
|
||||
'-D', project_name.lower(),
|
||||
'--update-header-comment'
|
||||
]
|
||||
|
||||
print(commands)
|
||||
subprocess.check_output(args=commands, cwd=root_dir)
|
||||
|
||||
|
||||
def babel_compile():
|
||||
"""Executes `pybabel compile` in subprocess."""
|
||||
commands = [
|
||||
'pybabel',
|
||||
'compile',
|
||||
'-d', locale_dir,
|
||||
'-D', project_name.lower()
|
||||
]
|
||||
|
||||
print(commands)
|
||||
subprocess.check_output(args=commands, cwd=root_dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Set up and gather command line arguments
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Script helps update locale translations. Translations must be done manually.')
|
||||
|
||||
parser.add_argument('--extract', action='store_true', help='Extract messages from c++ files.')
|
||||
parser.add_argument('--init', action='store_true', help='Initialize any new locales specified in target locales.')
|
||||
parser.add_argument('--update', action='store_true', help='Update existing locales.')
|
||||
parser.add_argument('--compile', action='store_true', help='Compile translated locales.')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.extract:
|
||||
x_extract()
|
||||
|
||||
if args.init:
|
||||
for locale_id in target_locales:
|
||||
if not os.path.isdir(os.path.join(locale_dir, locale_id)):
|
||||
babel_init(locale_code=locale_id)
|
||||
|
||||
if args.update:
|
||||
babel_update()
|
||||
|
||||
if args.compile:
|
||||
babel_compile()
|
||||
179
scripts/build-container.sh
Executable file
179
scripts/build-container.sh
Executable file
@@ -0,0 +1,179 @@
|
||||
#!/bin/bash -e
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo " -c: command --> default [build]"
|
||||
echo " | delete --> Delete the container, Dockerfile isn't mandatory"
|
||||
echo " | build --> Build the container, Dockerfile is mandatory"
|
||||
echo " | compile --> Builds the container, then compiles it. Dockerfile is mandatory"
|
||||
echo ""
|
||||
echo " -s: path: The path to the source for compilation"
|
||||
echo " -n: name: Docker container name --> default [sunshine]"
|
||||
echo " --> all: Build/Compile/Delete all available docker containers"
|
||||
echo " -f: Dockerfile: The name of the docker file"
|
||||
}
|
||||
|
||||
# Attempt to turn relative paths into absolute paths
|
||||
absolute_path() {
|
||||
RELATIVE_PATH=$1
|
||||
if which realpath >/dev/null 2>/dev/null
|
||||
then
|
||||
RELATIVE_PATH=$(realpath $RELATIVE_PATH)
|
||||
else
|
||||
echo "Warning: realpath is not installed on your system, ensure [$1] is absolute"
|
||||
fi
|
||||
|
||||
RETURN=$RELATIVE_PATH
|
||||
}
|
||||
|
||||
CONTAINER_NAME=sunshine
|
||||
COMMAND=BUILD
|
||||
|
||||
build_container() {
|
||||
CONTAINER_NAME=$1
|
||||
DOCKER_FILE=$2
|
||||
|
||||
if [ ! -f "$DOCKER_FILE" ]
|
||||
then
|
||||
echo "Error: $DOCKER_FILE doesn't exist"
|
||||
exit 7
|
||||
fi
|
||||
|
||||
echo "docker build . -t $CONTAINER_NAME -f $DOCKER_FILE"
|
||||
docker build . -t "$CONTAINER_NAME" -f "$DOCKER_FILE"
|
||||
}
|
||||
|
||||
delete() {
|
||||
CONTAINER_NAME_UPPER=$(echo "$CONTAINER_NAME" | tr '[:lower:]' '[:upper:]')
|
||||
if [ "$CONTAINER_NAME_UPPER" = "ALL" ]
|
||||
then
|
||||
shopt -s nullglob
|
||||
for file in $(find . -maxdepth 1 -iname "Dockerfile-*" -type f)
|
||||
do
|
||||
CURRENT_CONTAINER="sunshine-$(echo $file | cut -c 14-)"
|
||||
|
||||
if docker inspect "$CURRENT_CONTAINER" > /dev/null 2> /dev/null
|
||||
then
|
||||
echo "docker rmi $CURRENT_CONTAINER"
|
||||
docker rmi "$CURRENT_CONTAINER"
|
||||
fi
|
||||
done
|
||||
shopt -u nullglob #revert nullglob back to it's normal default state
|
||||
else
|
||||
if docker inspect "$CONTAINER_NAME" > /dev/null 2> /dev/null
|
||||
then
|
||||
echo "docker rmi $CONTAINER_NAME"
|
||||
docker rmi $CONTAINER_NAME
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
CONTAINER_NAME_UPPER=$(echo "$CONTAINER_NAME" | tr '[:lower:]' '[:upper:]')
|
||||
if [ "$CONTAINER_NAME_UPPER" = "ALL" ]
|
||||
then
|
||||
shopt -s nullglob
|
||||
for file in $(find . -maxdepth 1 -iname "Dockerfile-*" -type f)
|
||||
do
|
||||
CURRENT_CONTAINER="sunshine-$(echo $file | cut -c 14-)"
|
||||
build_container "$CURRENT_CONTAINER" "$file"
|
||||
done
|
||||
shopt -u nullglob #revert nullglob back to it's normal default state
|
||||
else
|
||||
if [[ -z "$DOCKER_FILE" ]]
|
||||
then
|
||||
echo "Error: if container name isn't equal to 'all', you need to specify the Dockerfile"
|
||||
exit 6
|
||||
fi
|
||||
|
||||
build_container "$CONTAINER_NAME" "$DOCKER_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
abort() {
|
||||
echo "$1"
|
||||
exit 10
|
||||
}
|
||||
|
||||
compile() {
|
||||
CONTAINER_NAME_UPPER=$(echo "$CONTAINER_NAME" | tr '[:lower:]' '[:upper:]')
|
||||
if [ "$CONTAINER_NAME_UPPER" = "ALL" ]
|
||||
then
|
||||
shopt -s nullglob
|
||||
|
||||
# If any docker container doesn't exist, we cannot compile all of them
|
||||
for file in $(find . -maxdepth 1 -iname "Dockerfile-*" -type f)
|
||||
do
|
||||
CURRENT_CONTAINER="sunshine-$(echo $file | cut -c 14-)"
|
||||
|
||||
# If container doesn't exist --> abort.
|
||||
docker inspect "$CURRENT_CONTAINER" > /dev/null 2> /dev/null || abort "Error: container image [$CURRENT_CONTAINER] doesn't exist"
|
||||
done
|
||||
|
||||
for file in $(find . -maxdepth 1 -iname "Dockerfile-*" -type f)
|
||||
do
|
||||
CURRENT_CONTAINER="sunshine-$(echo $file | cut -c 14-)"
|
||||
|
||||
echo "$PWD/build-sunshine.sh -p -n $CURRENT_CONTAINER $SUNSHINE_SOURCES"
|
||||
"$PWD/build-sunshine.sh" -p -n "$CURRENT_CONTAINER" $SUNSHINE_SOURCES
|
||||
done
|
||||
shopt -u nullglob #revert nullglob back to it's normal default state
|
||||
else
|
||||
# If container exists
|
||||
if docker inspect "$CONTAINER_NAME" > /dev/null 2> /dev/null
|
||||
then
|
||||
echo "$PWD/build-sunshine.sh -p -n $CONTAINER_NAME $SUNSHINE_SOURCES"
|
||||
"$PWD/build-sunshine.sh" -p -n "$CONTAINER_NAME" $SUNSHINE_SOURCES
|
||||
else
|
||||
echo "Error: container image [$CONTAINER_NAME] doesn't exist"
|
||||
exit 9
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
while getopts ":c:hn:f:s:" arg; do
|
||||
case ${arg} in
|
||||
s)
|
||||
SUNSHINE_SOURCES="-s $OPTARG"
|
||||
;;
|
||||
c)
|
||||
COMMAND=$(echo $OPTARG | tr '[:lower:]' '[:upper:]')
|
||||
;;
|
||||
n)
|
||||
echo "Container name: $OPTARG"
|
||||
CONTAINER_NAME="$OPTARG"
|
||||
;;
|
||||
f)
|
||||
echo "Using Dockerfile [$OPTARG]"
|
||||
DOCKER_FILE="$OPTARG"
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "$0 set to $(echo $COMMAND | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
if [ "$COMMAND" = "BUILD" ]
|
||||
then
|
||||
echo "Start building..."
|
||||
delete
|
||||
build
|
||||
echo "Done."
|
||||
elif [ "$COMMAND" = "COMPILE" ]
|
||||
then
|
||||
echo "Start compiling..."
|
||||
compile
|
||||
echo "Done."
|
||||
elif [ "$COMMAND" = "DELETE" ]
|
||||
then
|
||||
echo "Start deleting..."
|
||||
delete
|
||||
echo "Done."
|
||||
else
|
||||
echo "Unknown command [$(echo $COMMAND | tr '[:upper:]' '[:lower:]')]"
|
||||
exit 4
|
||||
fi
|
||||
48
scripts/build-private.sh
Executable file
48
scripts/build-private.sh
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/bin/bash -e
|
||||
set -e
|
||||
|
||||
CMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE:-Release}"
|
||||
SUNSHINE_EXECUTABLE_PATH="${SUNSHINE_EXECUTABLE_PATH:-/usr/bin/sunshine}"
|
||||
SUNSHINE_ASSETS_DIR="${SUNSHINE_ASSETS_DIR:-/etc/sunshine}"
|
||||
|
||||
|
||||
SUNSHINE_ROOT="${SUNSHINE_ROOT:-/root/sunshine}"
|
||||
SUNSHINE_TAG="${SUNSHINE_TAG:-master}"
|
||||
SUNSHINE_GIT_URL="${SUNSHINE_GIT_URL:-https://github.com/lizardbyte/sunshine.git}"
|
||||
|
||||
|
||||
SUNSHINE_ENABLE_WAYLAND=${SUNSHINE_ENABLE_WAYLAND:-ON}
|
||||
SUNSHINE_ENABLE_X11=${SUNSHINE_ENABLE_X11:-ON}
|
||||
SUNSHINE_ENABLE_DRM=${SUNSHINE_ENABLE_DRM:-ON}
|
||||
SUNSHINE_ENABLE_CUDA=${SUNSHINE_ENABLE_CUDA:-ON}
|
||||
|
||||
# For debugging, it would be usefull to have the sources on the host.
|
||||
if [[ ! -d "$SUNSHINE_ROOT" ]]
|
||||
then
|
||||
git clone --depth 1 --branch "$SUNSHINE_TAG" "$SUNSHINE_GIT_URL" --recurse-submodules "$SUNSHINE_ROOT"
|
||||
fi
|
||||
|
||||
if [[ ! -d /root/sunshine-build ]]
|
||||
then
|
||||
mkdir -p /root/sunshine-build
|
||||
fi
|
||||
cd /root/sunshine-build
|
||||
|
||||
cmake "-DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE" "-DSUNSHINE_EXECUTABLE_PATH=$SUNSHINE_EXECUTABLE_PATH" "-DSUNSHINE_ASSETS_DIR=$SUNSHINE_ASSETS_DIR" "-DSUNSHINE_ENABLE_WAYLAND=$SUNSHINE_ENABLE_WAYLAND" "-DSUNSHINE_ENABLE_X11=$SUNSHINE_ENABLE_X11" "-DSUNSHINE_ENABLE_DRM=$SUNSHINE_ENABLE_DRM" "-DSUNSHINE_ENABLE_CUDA=$SUNSHINE_ENABLE_CUDA" "$SUNSHINE_ROOT"
|
||||
|
||||
make -j ${nproc}
|
||||
|
||||
# Get preferred package format
|
||||
if [ "$1" == "-rpm" ]
|
||||
then
|
||||
echo "Packaging in .rpm format."
|
||||
./gen-rpm -d
|
||||
elif [ "$1" == "-deb" ]
|
||||
then
|
||||
echo "Packaging in .deb format."
|
||||
./gen-deb
|
||||
else
|
||||
echo "Preferred packaging not specified."
|
||||
echo "Use -deb or -rpm to specify preferred package format."
|
||||
exit 1
|
||||
fi
|
||||
132
scripts/build-sunshine.sh
Executable file
132
scripts/build-sunshine.sh
Executable file
@@ -0,0 +1,132 @@
|
||||
#!/bin/bash -e
|
||||
set -e
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0"
|
||||
echo " -d: Generate a debug build"
|
||||
echo " -p: Generate a linux package"
|
||||
echo " -e: Extension of package... i.e. 'deb', 'rpm' --> default [deb]"
|
||||
echo " -u: The input device is not a TTY"
|
||||
echo " -n name: Docker container name --> default [sunshine]"
|
||||
echo " -s path/to/sources/sunshine: Use local sources instead of a git repository"
|
||||
echo " -c path/to/cmake/binary/dir: Store cmake output on host OS"
|
||||
}
|
||||
|
||||
# Attempt to turn relative paths into absolute paths
|
||||
absolute_path() {
|
||||
RELATIVE_PATH=$1
|
||||
if which realpath >/dev/null 2>/dev/null
|
||||
then
|
||||
RELATIVE_PATH=$(realpath $RELATIVE_PATH)
|
||||
else
|
||||
echo "Warning: realpath is not installed on your system, ensure [$1] is absolute"
|
||||
fi
|
||||
|
||||
RETURN=$RELATIVE_PATH
|
||||
}
|
||||
|
||||
CMAKE_BUILD_TYPE="-e CMAKE_BUILD_TYPE=Release"
|
||||
SUNSHINE_PACKAGE_BUILD=OFF
|
||||
SUNSHINE_PACKAGE_EXTENSION=deb
|
||||
SUNSHINE_GIT_URL=https://github.com/lizardbyte/sunshine.git
|
||||
CONTAINER_NAME=sunshine
|
||||
|
||||
# Docker will fail if ctrl+c is passed through and the input is not a tty
|
||||
DOCKER_INTERACTIVE=-ti
|
||||
|
||||
while getopts ":dpuhc:e:s:n:" arg; do
|
||||
case ${arg} in
|
||||
u)
|
||||
echo "Input device is not a TTY"
|
||||
USERNAME="$USER"
|
||||
unset DOCKER_INTERACTIVE
|
||||
;;
|
||||
d)
|
||||
echo "Creating debug build"
|
||||
CMAKE_BUILD_TYPE="-e CMAKE_BUILD_TYPE=Debug"
|
||||
;;
|
||||
p)
|
||||
echo "Creating package build"
|
||||
SUNSHINE_PACKAGE_BUILD=ON
|
||||
SUNSHINE_ASSETS_DIR="-e SUNSHINE_ASSETS_DIR=/etc/sunshine"
|
||||
SUNSHINE_EXECUTABLE_PATH="-e SUNSHINE_EXECUTABLE_PATH=/usr/bin/sunshine"
|
||||
;;
|
||||
e)
|
||||
echo "Defining package extension: $OPTARG"
|
||||
if [ "$OPTARG" == "deb" ]
|
||||
then
|
||||
SUNSHINE_PACKAGE_EXTENSION=$OPTARG
|
||||
echo "Package extension: deb"
|
||||
elif [ "$OPTARG" == "rpm" ]
|
||||
then
|
||||
SUNSHINE_PACKAGE_EXTENSION=$OPTARG
|
||||
echo "Package extension: rpm"
|
||||
else
|
||||
echo "Package extension not supported: $OPTARG"
|
||||
echo "Falling back to default package extension: $SUNSHINE_PACKAGE_EXTENSION"
|
||||
fi
|
||||
;;
|
||||
s)
|
||||
absolute_path "$OPTARG"
|
||||
OPTARG="$RETURN"
|
||||
echo "Using sources from $OPTARG"
|
||||
SUNSHINE_ROOT="-v $OPTARG:/root/sunshine"
|
||||
;;
|
||||
c)
|
||||
[ "$USERNAME" == "" ] && USERNAME=$(logname)
|
||||
|
||||
absolute_path "$OPTARG"
|
||||
OPTARG="$RETURN"
|
||||
|
||||
echo "Using $OPTARG as cmake binary dir"
|
||||
if [[ ! -d $OPTARG ]]
|
||||
then
|
||||
echo "cmake binary dir doesn't exist, a new one will be created."
|
||||
mkdir -p "$OPTARG"
|
||||
[ "$USERNAME" == "$USER"] || chown $USERNAME:$USERNAME "$OPTARG"
|
||||
fi
|
||||
|
||||
CMAKE_ROOT="-v $OPTARG:/root/sunshine-build"
|
||||
;;
|
||||
n)
|
||||
echo "Container name: $OPTARG"
|
||||
CONTAINER_NAME=$OPTARG
|
||||
;;
|
||||
h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ "$USERNAME" = "" ] && USERNAME=$(logname)
|
||||
|
||||
BUILD_DIR="$PWD/$CONTAINER_NAME-build"
|
||||
[ "$SUNSHINE_ASSETS_DIR" = "" ] && SUNSHINE_ASSETS_DIR="-e SUNSHINE_ASSETS_DIR=$BUILD_DIR/assets"
|
||||
[ "$SUNSHINE_EXECUTABLE_PATH" = "" ] && SUNSHINE_EXECUTABLE_PATH="-e SUNSHINE_EXECUTABLE_PATH=$BUILD_DIR/sunshine"
|
||||
|
||||
echo "docker run $DOCKER_INTERACTIVE --privileged $SUNSHINE_ROOT $CMAKE_ROOT $SUNSHINE_ASSETS_DIR $SUNSHINE_EXECUTABLE_PATH $CMAKE_BUILD_TYPE --name $CONTAINER_NAME $CONTAINER_NAME"
|
||||
docker run $DOCKER_INTERACTIVE --privileged $SUNSHINE_ROOT $CMAKE_ROOT $SUNSHINE_ASSETS_DIR $SUNSHINE_EXECUTABLE_PATH $CMAKE_BUILD_TYPE --name $CONTAINER_NAME $CONTAINER_NAME
|
||||
|
||||
exit_code=$?
|
||||
|
||||
if [ $exit_code -eq 0 ]
|
||||
then
|
||||
mkdir -p $BUILD_DIR
|
||||
case $SUNSHINE_PACKAGE_BUILD in
|
||||
ON)
|
||||
echo "Downloading package to: $BUILD_DIR/$CONTAINER_NAME.$SUNSHINE_PACKAGE_EXTENSION"
|
||||
docker cp $CONTAINER_NAME:/root/sunshine-build/package-$SUNSHINE_PACKAGE_EXTENSION/sunshine.$SUNSHINE_PACKAGE_EXTENSION "$BUILD_DIR/$CONTAINER_NAME.$SUNSHINE_PACKAGE_EXTENSION"
|
||||
;;
|
||||
*)
|
||||
echo "Downloading binary and assets to: $BUILD_DIR"
|
||||
docker cp $CONTAINER_NAME:/root/sunshine/assets "$BUILD_DIR"
|
||||
docker cp $CONTAINER_NAME:/root/sunshine-build/sunshine "$BUILD_DIR"
|
||||
;;
|
||||
esac
|
||||
echo "chown --recursive $USERNAME:$USERNAME $BUILD_DIR"
|
||||
chown --recursive $USERNAME:$USERNAME "$BUILD_DIR"
|
||||
fi
|
||||
|
||||
echo "Removing docker container $CONTAINER_NAME"
|
||||
docker rm $CONTAINER_NAME
|
||||
5
scripts/requirements.txt
Normal file
5
scripts/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
Babel==2.10.3
|
||||
m2r2==0.3.2
|
||||
Sphinx==5.1.1
|
||||
sphinx-copybutton==0.5.0
|
||||
sphinx-rtd-theme==1.0.0
|
||||
@@ -87,11 +87,14 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
||||
OPUS_APPLICATION_AUDIO,
|
||||
nullptr) };
|
||||
|
||||
opus_multistream_encoder_ctl(opus.get(), OPUS_SET_VBR(0));
|
||||
// For some reason, audio is crackling when the encoder is set to constant bitstream.
|
||||
// We simulate a constant bitstream with OPUS_SET_BITRATE(OPUS_BITRATE_MAX) -->
|
||||
// which tries to occupy as much space as possible in the packet
|
||||
opus_multistream_encoder_ctl(opus.get(), OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
|
||||
|
||||
auto frame_size = config.packetDuration * stream->sampleRate / 1000;
|
||||
while(auto sample = samples->pop()) {
|
||||
buffer_t packet { 1024 }; // 1KB
|
||||
buffer_t packet { 1400 }; // 1KB
|
||||
|
||||
int bytes = opus_multistream_encode(opus.get(), sample->data(), frame_size, std::begin(packet), packet.size());
|
||||
if(bytes < 0) {
|
||||
@@ -101,6 +104,14 @@ void encodeThread(sample_queue_t samples, config_t config, void *channel_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Even with OPUS_SET_BITRATE(OPUS_BITRATE_MAX), silent packets are smaller than the rest
|
||||
// Drop silent packets to ensure Moonlight won't complain
|
||||
// A packet size of 128 seems a reasonable enough threshold
|
||||
if(bytes < 128) {
|
||||
BOOST_LOG(verbose) << "Dropped silent packet"sv;
|
||||
continue;
|
||||
}
|
||||
|
||||
packet.fake_resize(bytes);
|
||||
packets->raise(channel_data, std::move(packet));
|
||||
}
|
||||
@@ -119,14 +130,20 @@ void capture(safe::mail_t mail, config_t config, void *channel_data) {
|
||||
|
||||
auto &control = ref->control;
|
||||
if(!control) {
|
||||
BOOST_LOG(error) << "Couldn't create audio control"sv;
|
||||
shutdown_event->view();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::string *sink =
|
||||
config::audio.sink.empty() ? &ref->sink.host : &config::audio.sink;
|
||||
if(ref->sink.null) {
|
||||
// Order of priorty:
|
||||
// 1. Config
|
||||
// 2. Virtual if available
|
||||
// 3. Host
|
||||
std::string *sink = &ref->sink.host;
|
||||
if(!config::audio.sink.empty()) {
|
||||
sink = &config::audio.sink;
|
||||
}
|
||||
else if(ref->sink.null) {
|
||||
auto &null = *ref->sink.null;
|
||||
switch(stream->channelCount) {
|
||||
case 2:
|
||||
@@ -212,21 +229,29 @@ int map_stream(int channels, bool quality) {
|
||||
}
|
||||
|
||||
int start_audio_control(audio_ctx_t &ctx) {
|
||||
auto fg = util::fail_guard([]() {
|
||||
BOOST_LOG(warning) << "There will be no audio"sv;
|
||||
});
|
||||
|
||||
ctx.sink_flag = std::make_unique<std::atomic_bool>(false);
|
||||
|
||||
if(!(ctx.control = platf::audio_control())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto sink = ctx.control->sink_info();
|
||||
if(!sink) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// The default sink has not been replaced yet.
|
||||
ctx.restore_sink = false;
|
||||
|
||||
if(!(ctx.control = platf::audio_control())) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto sink = ctx.control->sink_info();
|
||||
if(!sink) {
|
||||
// Let the calling code know it failed
|
||||
ctx.control.reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctx.sink = std::move(*sink);
|
||||
|
||||
fg.disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ using namespace std::literals;
|
||||
#define PRIVATE_KEY_FILE CA_DIR "/cakey.pem"
|
||||
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
|
||||
|
||||
#define APPS_JSON_PATH SUNSHINE_ASSETS_DIR "/" APPS_JSON
|
||||
#define APPS_JSON_PATH platf::appdata().string() + "/apps.json"
|
||||
namespace config {
|
||||
|
||||
namespace nv {
|
||||
@@ -99,16 +99,22 @@ enum quality_e : int {
|
||||
_default = 0,
|
||||
speed,
|
||||
balanced,
|
||||
//quality2,
|
||||
};
|
||||
|
||||
enum rc_e : int {
|
||||
enum class rc_hevc_e : int {
|
||||
constqp, /**< Constant QP mode */
|
||||
vbr_latency, /**< Latency Constrained Variable Bitrate */
|
||||
vbr_peak, /**< Peak Contrained Variable Bitrate */
|
||||
cbr, /**< Constant bitrate mode */
|
||||
};
|
||||
|
||||
enum class rc_h264_e : int {
|
||||
constqp, /**< Constant QP mode */
|
||||
cbr, /**< Constant bitrate mode */
|
||||
vbr_peak, /**< Peak Contrained Variable Bitrate */
|
||||
vbr_latency, /**< Latency Constrained Variable Bitrate */
|
||||
};
|
||||
|
||||
enum coder_e : int {
|
||||
_auto = 0,
|
||||
cabac,
|
||||
@@ -120,15 +126,25 @@ std::optional<quality_e> quality_from_view(const std::string_view &quality) {
|
||||
if(quality == #x##sv) return x
|
||||
_CONVERT_(speed);
|
||||
_CONVERT_(balanced);
|
||||
//_CONVERT_(quality2);
|
||||
if(quality == "default"sv) return _default;
|
||||
#undef _CONVERT_
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<rc_e> rc_from_view(const std::string_view &rc) {
|
||||
std::optional<int> rc_h264_from_view(const std::string_view &rc) {
|
||||
#define _CONVERT_(x) \
|
||||
if(rc == #x##sv) return x
|
||||
if(rc == #x##sv) return (int)rc_h264_e::x
|
||||
_CONVERT_(constqp);
|
||||
_CONVERT_(vbr_latency);
|
||||
_CONVERT_(vbr_peak);
|
||||
_CONVERT_(cbr);
|
||||
#undef _CONVERT_
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<int> rc_hevc_from_view(const std::string_view &rc) {
|
||||
#define _CONVERT_(x) \
|
||||
if(rc == #x##sv) return (int)rc_hevc_e::x
|
||||
_CONVERT_(constqp);
|
||||
_CONVERT_(vbr_latency);
|
||||
_CONVERT_(vbr_peak);
|
||||
@@ -146,8 +162,43 @@ int coder_from_view(const std::string_view &coder) {
|
||||
}
|
||||
} // namespace amd
|
||||
|
||||
namespace vt {
|
||||
|
||||
enum coder_e : int {
|
||||
_auto = 0,
|
||||
cabac,
|
||||
cavlc
|
||||
};
|
||||
|
||||
int coder_from_view(const std::string_view &coder) {
|
||||
if(coder == "auto"sv) return _auto;
|
||||
if(coder == "cabac"sv || coder == "ac"sv) return cabac;
|
||||
if(coder == "cavlc"sv || coder == "vlc"sv) return cavlc;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int allow_software_from_view(const std::string_view &software) {
|
||||
if(software == "allowed"sv || software == "forced") return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int force_software_from_view(const std::string_view &software) {
|
||||
if(software == "forced") return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rt_from_view(const std::string_view &rt) {
|
||||
if(rt == "disabled" || rt == "off" || rt == "0") return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace vt
|
||||
|
||||
video_t video {
|
||||
0, // crf
|
||||
28, // qp
|
||||
|
||||
0, // hevc_mode
|
||||
@@ -166,11 +217,19 @@ video_t video {
|
||||
{
|
||||
amd::balanced,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
-1 }, // amd
|
||||
|
||||
{}, // encoder
|
||||
{}, // adapter_name
|
||||
{}, // output_name
|
||||
{
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
-1 }, // vt
|
||||
|
||||
{}, // encoder
|
||||
{}, // adapter_name
|
||||
{}, // output_name
|
||||
true // dwmflush
|
||||
};
|
||||
|
||||
audio_t audio {};
|
||||
@@ -211,20 +270,30 @@ nvhttp_t nvhttp {
|
||||
};
|
||||
|
||||
input_t input {
|
||||
2s, // back_button_timeout
|
||||
500ms, // key_repeat_delay
|
||||
std::chrono::duration<double> { 1 / 24.9 } // key_repeat_period
|
||||
{
|
||||
{ 0x10, 0xA0 },
|
||||
{ 0x11, 0xA2 },
|
||||
{ 0x12, 0xA4 },
|
||||
},
|
||||
2s, // back_button_timeout
|
||||
500ms, // key_repeat_delay
|
||||
std::chrono::duration<double> { 1 / 24.9 }, // key_repeat_period
|
||||
|
||||
{
|
||||
platf::supported_gamepads().front().data(),
|
||||
platf::supported_gamepads().front().size(),
|
||||
}, // Default gamepad
|
||||
};
|
||||
|
||||
sunshine_t sunshine {
|
||||
2, // min_log_level
|
||||
0, // flags
|
||||
{}, // User file
|
||||
{}, // Username
|
||||
{}, // Password
|
||||
{}, // Password Salt
|
||||
SUNSHINE_ASSETS_DIR "/sunshine.conf", // config file
|
||||
{}, // cmd args
|
||||
2, // min_log_level
|
||||
0, // flags
|
||||
{}, // User file
|
||||
{}, // Username
|
||||
{}, // Password
|
||||
{}, // Password Salt
|
||||
platf::appdata().string() + "/sunshine.conf", // config file
|
||||
{}, // cmd args
|
||||
47989,
|
||||
};
|
||||
|
||||
@@ -395,8 +464,20 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
||||
return;
|
||||
}
|
||||
|
||||
auto &val = it->second;
|
||||
input = util::from_chars(&val[0], &val[0] + val.size());
|
||||
std::string_view val = it->second;
|
||||
|
||||
// If value is something like: "756" instead of 756
|
||||
if(val.size() >= 2 && val[0] == '"') {
|
||||
val = val.substr(1, val.size() - 2);
|
||||
}
|
||||
|
||||
// If that integer is in hexadecimal
|
||||
if(val.size() >= 2 && val.substr(0, 2) == "0x"sv) {
|
||||
input = util::from_hex<int>(val.substr(2));
|
||||
}
|
||||
else {
|
||||
input = util::from_view(val);
|
||||
}
|
||||
|
||||
vars.erase(it);
|
||||
}
|
||||
@@ -408,8 +489,20 @@ void int_f(std::unordered_map<std::string, std::string> &vars, const std::string
|
||||
return;
|
||||
}
|
||||
|
||||
auto &val = it->second;
|
||||
input = util::from_chars(&val[0], &val[0] + val.size());
|
||||
std::string_view val = it->second;
|
||||
|
||||
// If value is something like: "756" instead of 756
|
||||
if(val.size() >= 2 && val[0] == '"') {
|
||||
val = val.substr(1, val.size() - 2);
|
||||
}
|
||||
|
||||
// If that integer is in hexadecimal
|
||||
if(val.size() >= 2 && val.substr(0, 2) == "0x"sv) {
|
||||
input = util::from_hex<int>(val.substr(2));
|
||||
}
|
||||
else {
|
||||
input = util::from_view(val);
|
||||
}
|
||||
|
||||
vars.erase(it);
|
||||
}
|
||||
@@ -541,7 +634,42 @@ void list_int_f(std::unordered_map<std::string, std::string> &vars, const std::s
|
||||
list_string_f(vars, name, list);
|
||||
|
||||
for(auto &el : list) {
|
||||
input.emplace_back(util::from_view(el));
|
||||
std::string_view val = el;
|
||||
|
||||
// If value is something like: "756" instead of 756
|
||||
if(val.size() >= 2 && val[0] == '"') {
|
||||
val = val.substr(1, val.size() - 2);
|
||||
}
|
||||
|
||||
int tmp;
|
||||
|
||||
// If the integer is a hexadecimal
|
||||
if(val.size() >= 2 && val.substr(0, 2) == "0x"sv) {
|
||||
tmp = util::from_hex<int>(val.substr(2));
|
||||
}
|
||||
else {
|
||||
tmp = util::from_view(val);
|
||||
}
|
||||
input.emplace_back(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void map_int_int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, std::unordered_map<int, int> &input) {
|
||||
std::vector<int> list;
|
||||
list_int_f(vars, name, list);
|
||||
|
||||
// The list needs to be a multiple of 2
|
||||
if(list.size() % 2) {
|
||||
std::cout << "Warning: expected "sv << name << " to have a multiple of two elements --> not "sv << list.size() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
while(x < list.size()) {
|
||||
auto key = list[x++];
|
||||
auto val = list[x++];
|
||||
|
||||
input.emplace(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,11 +701,14 @@ int apply_flags(const char *line) {
|
||||
}
|
||||
|
||||
void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||
if(!fs::exists(stream.file_apps.c_str())) {
|
||||
fs::copy_file(SUNSHINE_CONFIG_DIR "/apps.json", stream.file_apps);
|
||||
}
|
||||
|
||||
for(auto &[name, val] : vars) {
|
||||
std::cout << "["sv << name << "] -- ["sv << val << ']' << std::endl;
|
||||
}
|
||||
|
||||
int_f(vars, "crf", video.crf);
|
||||
int_f(vars, "qp", video.qp);
|
||||
int_f(vars, "min_threads", video.min_threads);
|
||||
int_between_f(vars, "hevc_mode", video.hevc_mode, { 0, 3 });
|
||||
@@ -588,12 +719,24 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||
int_f(vars, "nv_coder", video.nv.coder, nv::coder_from_view);
|
||||
|
||||
int_f(vars, "amd_quality", video.amd.quality, amd::quality_from_view);
|
||||
int_f(vars, "amd_rc", video.amd.rc, amd::rc_from_view);
|
||||
|
||||
std::string rc;
|
||||
string_f(vars, "amd_rc", rc);
|
||||
int_f(vars, "amd_coder", video.amd.coder, amd::coder_from_view);
|
||||
if(!rc.empty()) {
|
||||
video.amd.rc_h264 = amd::rc_h264_from_view(rc);
|
||||
video.amd.rc_hevc = amd::rc_hevc_from_view(rc);
|
||||
}
|
||||
|
||||
int_f(vars, "vt_coder", video.vt.coder, vt::coder_from_view);
|
||||
int_f(vars, "vt_software", video.vt.allow_sw, vt::allow_software_from_view);
|
||||
int_f(vars, "vt_software", video.vt.require_sw, vt::force_software_from_view);
|
||||
int_f(vars, "vt_realtime", video.vt.realtime, vt::rt_from_view);
|
||||
|
||||
string_f(vars, "encoder", video.encoder);
|
||||
string_f(vars, "adapter_name", video.adapter_name);
|
||||
string_f(vars, "output_name", video.output_name);
|
||||
bool_f(vars, "dwmflush", video.dwmflush);
|
||||
|
||||
path_f(vars, "pkey", nvhttp.pkey);
|
||||
path_f(vars, "cert", nvhttp.cert);
|
||||
@@ -626,6 +769,17 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||
path_f(vars, "file_apps", stream.file_apps);
|
||||
int_between_f(vars, "fec_percentage", stream.fec_percentage, { 1, 255 });
|
||||
|
||||
map_int_int_f(vars, "keybindings"s, input.keybindings);
|
||||
|
||||
// This config option will only be used by the UI
|
||||
// When editing in the config file itself, use "keybindings"
|
||||
bool map_rightalt_to_win = false;
|
||||
bool_f(vars, "key_rightalt_to_key_win", map_rightalt_to_win);
|
||||
|
||||
if(map_rightalt_to_win) {
|
||||
input.keybindings.emplace(0xA5, 0x5B);
|
||||
}
|
||||
|
||||
to = std::numeric_limits<int>::min();
|
||||
int_f(vars, "back_button_timeout", to);
|
||||
|
||||
@@ -646,6 +800,8 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||
input.key_repeat_delay = std::chrono::milliseconds { to };
|
||||
}
|
||||
|
||||
string_restricted_f(vars, "gamepad"s, input.gamepad, platf::supported_gamepads());
|
||||
|
||||
int port = sunshine.port;
|
||||
int_f(vars, "port"s, port);
|
||||
sunshine.port = (std::uint16_t)port;
|
||||
@@ -658,7 +814,7 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
|
||||
}
|
||||
|
||||
std::string log_level_string;
|
||||
string_restricted_f(vars, "min_log_level", log_level_string, { "verbose"sv, "debug"sv, "info"sv, "warning"sv, "error"sv, "fatal"sv, "none"sv });
|
||||
string_f(vars, "min_log_level", log_level_string);
|
||||
|
||||
if(!log_level_string.empty()) {
|
||||
if(log_level_string == "verbose"sv) {
|
||||
@@ -754,6 +910,10 @@ int parse(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!fs::exists(sunshine.config_file)) {
|
||||
fs::copy_file(SUNSHINE_CONFIG_DIR "/sunshine.conf", sunshine.config_file);
|
||||
}
|
||||
|
||||
auto vars = parse_config(read_file(sunshine.config_file.c_str()));
|
||||
|
||||
for(auto &[name, value] : cmd_vars) {
|
||||
@@ -11,8 +11,7 @@
|
||||
namespace config {
|
||||
struct video_t {
|
||||
// ffmpeg params
|
||||
int crf; // higher == more compression and less quality
|
||||
int qp; // higher == more compression and less quality, ignored if crf != 0
|
||||
int qp; // higher == more compression and less quality
|
||||
|
||||
int hevc_mode;
|
||||
|
||||
@@ -30,13 +29,22 @@ struct video_t {
|
||||
|
||||
struct {
|
||||
std::optional<int> quality;
|
||||
std::optional<int> rc;
|
||||
std::optional<int> rc_h264;
|
||||
std::optional<int> rc_hevc;
|
||||
int coder;
|
||||
} amd;
|
||||
|
||||
struct {
|
||||
int allow_sw;
|
||||
int require_sw;
|
||||
int realtime;
|
||||
int coder;
|
||||
} vt;
|
||||
|
||||
std::string encoder;
|
||||
std::string adapter_name;
|
||||
std::string output_name;
|
||||
bool dwmflush;
|
||||
};
|
||||
|
||||
struct audio_t {
|
||||
@@ -74,9 +82,13 @@ struct nvhttp_t {
|
||||
};
|
||||
|
||||
struct input_t {
|
||||
std::unordered_map<int, int> keybindings;
|
||||
|
||||
std::chrono::milliseconds back_button_timeout;
|
||||
std::chrono::milliseconds key_repeat_delay;
|
||||
std::chrono::duration<double> key_repeat_period;
|
||||
|
||||
std::string gamepad;
|
||||
};
|
||||
|
||||
namespace flag {
|
||||
@@ -73,6 +73,15 @@ void send_unauthorized(resp_https_t response, req_https_t request) {
|
||||
response->write(SimpleWeb::StatusCode::client_error_unauthorized, headers);
|
||||
}
|
||||
|
||||
void send_redirect(resp_https_t response, req_https_t request, const char *path) {
|
||||
auto address = request->remote_endpoint_address();
|
||||
BOOST_LOG(info) << "Web UI: ["sv << address << "] -- not authorized"sv;
|
||||
const SimpleWeb::CaseInsensitiveMultimap headers {
|
||||
{ "Location", path }
|
||||
};
|
||||
response->write(SimpleWeb::StatusCode::redirection_temporary_redirect, headers);
|
||||
}
|
||||
|
||||
bool authenticate(resp_https_t response, req_https_t request) {
|
||||
auto address = request->remote_endpoint_address();
|
||||
auto ip_type = net::from_address(address);
|
||||
@@ -83,6 +92,12 @@ bool authenticate(resp_https_t response, req_https_t request) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//If credentials are shown, redirect the user to a /welcome page
|
||||
if(config::sunshine.username.empty()) {
|
||||
send_redirect(response, request, "/welcome");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fg = util::fail_guard([&]() {
|
||||
send_unauthorized(response, request);
|
||||
});
|
||||
@@ -185,6 +200,91 @@ void getPasswordPage(resp_https_t response, req_https_t request) {
|
||||
response->write(header + content);
|
||||
}
|
||||
|
||||
void getWelcomePage(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
if(!config::sunshine.username.empty()) {
|
||||
send_redirect(response, request, "/");
|
||||
return;
|
||||
}
|
||||
std::string header = read_file(WEB_DIR "header-no-nav.html");
|
||||
std::string content = read_file(WEB_DIR "welcome.html");
|
||||
response->write(header + content);
|
||||
}
|
||||
|
||||
void getTroubleshootingPage(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
print_req(request);
|
||||
|
||||
std::string header = read_file(WEB_DIR "header.html");
|
||||
std::string content = read_file(WEB_DIR "troubleshooting.html");
|
||||
response->write(header + content);
|
||||
}
|
||||
|
||||
void getFaviconImage(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::ifstream in(WEB_DIR "images/favicon.ico", std::ios::binary);
|
||||
SimpleWeb::CaseInsensitiveMultimap headers;
|
||||
headers.emplace("Content-Type", "image/x-icon");
|
||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||
}
|
||||
|
||||
void getSunshineLogoImage(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::ifstream in(WEB_DIR "images/logo-sunshine-45.png", std::ios::binary);
|
||||
SimpleWeb::CaseInsensitiveMultimap headers;
|
||||
headers.emplace("Content-Type", "image/png");
|
||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||
}
|
||||
|
||||
void getFontAwesomeCss(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::string content = read_file(WEB_DIR "fonts/fontawesome-free-web/css/all.min.css");
|
||||
response->write(content);
|
||||
}
|
||||
|
||||
void getFontAwesomeBrands(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::ifstream in(WEB_DIR "fonts/fontawesome-free-web/webfonts/fa-brands-400.ttf", std::ios::binary);
|
||||
SimpleWeb::CaseInsensitiveMultimap headers;
|
||||
headers.emplace("Content-Type", "font/ttf");
|
||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||
}
|
||||
|
||||
void getFontAwesomeSolid(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::ifstream in(WEB_DIR "fonts/fontawesome-free-web/webfonts/fa-solid-900.ttf", std::ios::binary);
|
||||
SimpleWeb::CaseInsensitiveMultimap headers;
|
||||
headers.emplace("Content-Type", "font/ttf");
|
||||
response->write(SimpleWeb::StatusCode::success_ok, in, headers);
|
||||
}
|
||||
|
||||
void getBootstrapCss(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::string content = read_file(WEB_DIR "third_party/bootstrap.min.css");
|
||||
response->write(content);
|
||||
}
|
||||
|
||||
void getBootstrapJs(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::string content = read_file(WEB_DIR "third_party/bootstrap.bundle.min.js");
|
||||
response->write(content);
|
||||
}
|
||||
|
||||
void getVueJs(resp_https_t response, req_https_t request) {
|
||||
print_req(request);
|
||||
|
||||
std::string content = read_file(WEB_DIR "third_party/vue.js");
|
||||
response->write(content);
|
||||
}
|
||||
|
||||
void getApps(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
@@ -371,7 +471,7 @@ void saveConfig(resp_https_t response, req_https_t request) {
|
||||
}
|
||||
|
||||
void savePassword(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
if(!config::sunshine.username.empty() && !authenticate(response, request)) return;
|
||||
|
||||
print_req(request);
|
||||
|
||||
@@ -390,27 +490,33 @@ void savePassword(resp_https_t response, req_https_t request) {
|
||||
try {
|
||||
//TODO: Input Validation
|
||||
pt::read_json(ss, inputTree);
|
||||
auto username = inputTree.get<std::string>("currentUsername");
|
||||
auto username = inputTree.count("currentUsername") > 0 ? inputTree.get<std::string>("currentUsername") : "";
|
||||
auto newUsername = inputTree.get<std::string>("newUsername");
|
||||
auto password = inputTree.get<std::string>("currentPassword");
|
||||
auto newPassword = inputTree.get<std::string>("newPassword");
|
||||
auto confirmPassword = inputTree.get<std::string>("confirmNewPassword");
|
||||
auto password = inputTree.count("currentPassword") > 0 ? inputTree.get<std::string>("currentPassword") : "";
|
||||
auto newPassword = inputTree.count("newPassword") > 0 ? inputTree.get<std::string>("newPassword") : "";
|
||||
auto confirmPassword = inputTree.count("confirmNewPassword") > 0 ? inputTree.get<std::string>("confirmNewPassword") : "";
|
||||
if(newUsername.length() == 0) newUsername = username;
|
||||
|
||||
auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string();
|
||||
if(username == config::sunshine.username && hash == config::sunshine.password) {
|
||||
if(newPassword != confirmPassword) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Password Mismatch");
|
||||
}
|
||||
|
||||
http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword);
|
||||
http::reload_user_creds(config::sunshine.credentials_file);
|
||||
outputTree.put("status", true);
|
||||
if(newUsername.length() == 0) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Invalid Username");
|
||||
}
|
||||
else {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Invalid Current Credentials");
|
||||
auto hash = util::hex(crypto::hash(password + config::sunshine.salt)).to_string();
|
||||
if(config::sunshine.username.empty() || (username == config::sunshine.username && hash == config::sunshine.password)) {
|
||||
if(newPassword.empty() || newPassword != confirmPassword) {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Password Mismatch");
|
||||
}
|
||||
else {
|
||||
http::save_user_creds(config::sunshine.credentials_file, newUsername, newPassword);
|
||||
http::reload_user_creds(config::sunshine.credentials_file);
|
||||
outputTree.put("status", true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
outputTree.put("status", false);
|
||||
outputTree.put("error", "Invalid Current Credentials");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(std::exception &e) {
|
||||
@@ -451,6 +557,39 @@ void savePin(resp_https_t response, req_https_t request) {
|
||||
}
|
||||
}
|
||||
|
||||
void unpairAll(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
print_req(request);
|
||||
|
||||
pt::ptree outputTree;
|
||||
|
||||
auto g = util::fail_guard([&]() {
|
||||
std::ostringstream data;
|
||||
pt::write_json(data, outputTree);
|
||||
response->write(data.str());
|
||||
});
|
||||
nvhttp::erase_all_clients();
|
||||
outputTree.put("status", true);
|
||||
}
|
||||
|
||||
void closeApp(resp_https_t response, req_https_t request) {
|
||||
if(!authenticate(response, request)) return;
|
||||
|
||||
print_req(request);
|
||||
|
||||
pt::ptree outputTree;
|
||||
|
||||
auto g = util::fail_guard([&]() {
|
||||
std::ostringstream data;
|
||||
pt::write_json(data, outputTree);
|
||||
response->write(data.str());
|
||||
});
|
||||
|
||||
proc::proc.terminate();
|
||||
outputTree.put("status", true);
|
||||
}
|
||||
|
||||
void start() {
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
|
||||
@@ -460,23 +599,35 @@ void start() {
|
||||
ctx->use_certificate_chain_file(config::nvhttp.cert);
|
||||
ctx->use_private_key_file(config::nvhttp.pkey, boost::asio::ssl::context::pem);
|
||||
https_server_t server { ctx, 0 };
|
||||
server.default_resource = not_found;
|
||||
server.resource["^/$"]["GET"] = getIndexPage;
|
||||
server.resource["^/pin$"]["GET"] = getPinPage;
|
||||
server.resource["^/apps$"]["GET"] = getAppsPage;
|
||||
server.resource["^/clients$"]["GET"] = getClientsPage;
|
||||
server.resource["^/config$"]["GET"] = getConfigPage;
|
||||
server.resource["^/password$"]["GET"] = getPasswordPage;
|
||||
server.resource["^/api/pin"]["POST"] = savePin;
|
||||
server.resource["^/api/apps$"]["GET"] = getApps;
|
||||
server.resource["^/api/apps$"]["POST"] = saveApp;
|
||||
server.resource["^/api/config$"]["GET"] = getConfig;
|
||||
server.resource["^/api/config$"]["POST"] = saveConfig;
|
||||
server.resource["^/api/password$"]["POST"] = savePassword;
|
||||
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
|
||||
server.config.reuse_address = true;
|
||||
server.config.address = "0.0.0.0"s;
|
||||
server.config.port = port_https;
|
||||
server.default_resource = not_found;
|
||||
server.resource["^/$"]["GET"] = getIndexPage;
|
||||
server.resource["^/pin$"]["GET"] = getPinPage;
|
||||
server.resource["^/apps$"]["GET"] = getAppsPage;
|
||||
server.resource["^/clients$"]["GET"] = getClientsPage;
|
||||
server.resource["^/config$"]["GET"] = getConfigPage;
|
||||
server.resource["^/password$"]["GET"] = getPasswordPage;
|
||||
server.resource["^/welcome$"]["GET"] = getWelcomePage;
|
||||
server.resource["^/troubleshooting$"]["GET"] = getTroubleshootingPage;
|
||||
server.resource["^/api/pin"]["POST"] = savePin;
|
||||
server.resource["^/api/apps$"]["GET"] = getApps;
|
||||
server.resource["^/api/apps$"]["POST"] = saveApp;
|
||||
server.resource["^/api/config$"]["GET"] = getConfig;
|
||||
server.resource["^/api/config$"]["POST"] = saveConfig;
|
||||
server.resource["^/api/password$"]["POST"] = savePassword;
|
||||
server.resource["^/api/apps/([0-9]+)$"]["DELETE"] = deleteApp;
|
||||
server.resource["^/api/clients/unpair$"]["POST"] = unpairAll;
|
||||
server.resource["^/api/apps/close"]["POST"] = closeApp;
|
||||
server.resource["^/images/favicon.ico$"]["GET"] = getFaviconImage;
|
||||
server.resource["^/images/logo-sunshine-45.png$"]["GET"] = getSunshineLogoImage;
|
||||
server.resource["^/third_party/bootstrap.min.css$"]["GET"] = getBootstrapCss;
|
||||
server.resource["^/third_party/bootstrap.bundle.min.js$"]["GET"] = getBootstrapJs;
|
||||
server.resource["^/fontawesome/css/all.min.css$"]["GET"] = getFontAwesomeCss;
|
||||
server.resource["^/fontawesome/webfonts/fa-brands-400.ttf$"]["GET"] = getFontAwesomeBrands;
|
||||
server.resource["^/fontawesome/webfonts/fa-solid-900.ttf$"]["GET"] = getFontAwesomeSolid;
|
||||
server.resource["^/third_party/vue.js$"]["GET"] = getVueJs;
|
||||
server.config.reuse_address = true;
|
||||
server.config.address = "0.0.0.0"s;
|
||||
server.config.port = port_https;
|
||||
|
||||
try {
|
||||
server.bind();
|
||||
@@ -512,4 +663,4 @@ void start() {
|
||||
|
||||
tcp.join();
|
||||
}
|
||||
} // namespace confighttp
|
||||
} // namespace confighttp
|
||||
@@ -52,9 +52,13 @@ const char *cert_chain_t::verify(x509_t::element_type *cert) {
|
||||
X509_STORE_CTX_cleanup(_cert_ctx.get());
|
||||
});
|
||||
|
||||
X509_STORE_CTX_init(_cert_ctx.get(), x509_store.get(), nullptr, nullptr);
|
||||
X509_STORE_CTX_init(_cert_ctx.get(), x509_store.get(), cert, nullptr);
|
||||
X509_STORE_CTX_set_verify_cb(_cert_ctx.get(), openssl_verify_cb);
|
||||
X509_STORE_CTX_set_cert(_cert_ctx.get(), cert);
|
||||
|
||||
// We don't care to validate the entire chain for the purposes of client auth.
|
||||
// Some versions of clients forked from Moonlight Embedded produce client certs
|
||||
// that OpenSSL doesn't detect as self-signed due to some X509v3 extensions.
|
||||
X509_STORE_CTX_set_flags(_cert_ctx.get(), X509_V_FLAG_PARTIAL_CHAIN);
|
||||
|
||||
auto err = X509_verify_cert(_cert_ctx.get());
|
||||
|
||||
@@ -54,15 +54,12 @@ int init() {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(!user_creds_exist(config::sunshine.credentials_file)) {
|
||||
if(save_user_creds(config::sunshine.credentials_file, "sunshine"s, crypto::rand_alphabet(16), true)) {
|
||||
return -1;
|
||||
}
|
||||
if(user_creds_exist(config::sunshine.credentials_file)) {
|
||||
if(reload_user_creds(config::sunshine.credentials_file)) return -1;
|
||||
}
|
||||
if(reload_user_creds(config::sunshine.credentials_file)) {
|
||||
return -1;
|
||||
else {
|
||||
BOOST_LOG(info) << "Open the Web UI to set your new username and password and getting started";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -92,12 +89,6 @@ int save_user_creds(const std::string &file, const std::string &username, const
|
||||
}
|
||||
|
||||
BOOST_LOG(info) << "New credentials have been created"sv;
|
||||
|
||||
if(run_our_mouth) {
|
||||
BOOST_LOG(info) << "Username: "sv << username;
|
||||
BOOST_LOG(info) << "Password: "sv << password;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "config.h"
|
||||
#include "input.h"
|
||||
@@ -17,12 +18,23 @@ extern "C" {
|
||||
#include "thread_pool.h"
|
||||
#include "utility.h"
|
||||
|
||||
using namespace std::literals;
|
||||
namespace input {
|
||||
|
||||
constexpr auto MAX_GAMEPADS = std::min((std::size_t)platf::MAX_GAMEPADS, sizeof(std::int16_t) * 8);
|
||||
#define DISABLE_LEFT_BUTTON_DELAY ((util::ThreadPool::task_id_t)0x01)
|
||||
#define ENABLE_LEFT_BUTTON_DELAY nullptr
|
||||
|
||||
constexpr auto VKEY_SHIFT = 0x10;
|
||||
constexpr auto VKEY_LSHIFT = 0xA0;
|
||||
constexpr auto VKEY_RSHIFT = 0xA1;
|
||||
constexpr auto VKEY_CONTROL = 0x11;
|
||||
constexpr auto VKEY_LCONTROL = 0xA2;
|
||||
constexpr auto VKEY_RCONTROL = 0xA3;
|
||||
constexpr auto VKEY_MENU = 0x12;
|
||||
constexpr auto VKEY_LMENU = 0xA4;
|
||||
constexpr auto VKEY_RMENU = 0xA5;
|
||||
|
||||
enum class button_state_e {
|
||||
NONE,
|
||||
DOWN,
|
||||
@@ -46,7 +58,7 @@ void free_id(std::bitset<N> &gamepad_mask, int id) {
|
||||
gamepad_mask[id] = false;
|
||||
}
|
||||
|
||||
static util::TaskPool::task_id_t task_id {};
|
||||
static util::TaskPool::task_id_t key_press_repeat_id {};
|
||||
static std::unordered_map<short, bool> key_press {};
|
||||
static std::array<std::uint8_t, 5> mouse_press {};
|
||||
|
||||
@@ -84,24 +96,65 @@ struct gamepad_t {
|
||||
};
|
||||
|
||||
struct input_t {
|
||||
input_t(safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event)
|
||||
: active_gamepad_state {},
|
||||
enum shortkey_e {
|
||||
CTRL = 0x1,
|
||||
ALT = 0x2,
|
||||
SHIFT = 0x4,
|
||||
|
||||
SHORTCUT = CTRL | ALT | SHIFT
|
||||
};
|
||||
|
||||
input_t(
|
||||
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event,
|
||||
platf::rumble_queue_t rumble_queue)
|
||||
: shortcutFlags {},
|
||||
active_gamepad_state {},
|
||||
gamepads(MAX_GAMEPADS),
|
||||
touch_port_event { std::move(touch_port_event) },
|
||||
rumble_queue { std::move(rumble_queue) },
|
||||
mouse_left_button_timeout {},
|
||||
touch_port { 0, 0, 0, 0, 0, 0, 1.0f } {}
|
||||
|
||||
// Keep track of alt+ctrl+shift key combo
|
||||
int shortcutFlags;
|
||||
|
||||
std::uint16_t active_gamepad_state;
|
||||
std::vector<gamepad_t> gamepads;
|
||||
|
||||
safe::mail_raw_t::event_t<input::touch_port_t> touch_port_event;
|
||||
platf::rumble_queue_t rumble_queue;
|
||||
|
||||
util::ThreadPool::task_id_t mouse_left_button_timeout;
|
||||
|
||||
input::touch_port_t touch_port;
|
||||
};
|
||||
|
||||
using namespace std::literals;
|
||||
/**
|
||||
* Apply shortcut based on VKEY
|
||||
* On success
|
||||
* return > 0
|
||||
* On nothing
|
||||
* return 0
|
||||
*/
|
||||
inline int apply_shortcut(short keyCode) {
|
||||
constexpr auto VK_F1 = 0x70;
|
||||
constexpr auto VK_F13 = 0x7C;
|
||||
|
||||
BOOST_LOG(debug) << "Apply Shortcut: 0x"sv << util::hex((std::uint8_t)keyCode).to_string_view();
|
||||
|
||||
if(keyCode >= VK_F1 && keyCode <= VK_F13) {
|
||||
mail::man->event<int>(mail::switch_display)->raise(keyCode - VK_F1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch(keyCode) {
|
||||
case 0x4E /* VKEY_N */:
|
||||
display_cursor = !display_cursor;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print(PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
@@ -146,7 +199,8 @@ void print(PNV_KEYBOARD_PACKET packet) {
|
||||
}
|
||||
|
||||
void print(PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||
BOOST_LOG(debug)
|
||||
// Moonlight spams controller packet even when not necessary
|
||||
BOOST_LOG(verbose)
|
||||
<< "--begin controller packet--"sv << std::endl
|
||||
<< "controllerNumber ["sv << packet->controllerNumber << ']' << std::endl
|
||||
<< "activeGamepadMask ["sv << util::hex(packet->activeGamepadMask).to_string_view() << ']' << std::endl
|
||||
@@ -192,15 +246,11 @@ void print(void *input) {
|
||||
}
|
||||
|
||||
void passthrough(std::shared_ptr<input_t> &input, PNV_REL_MOUSE_MOVE_PACKET packet) {
|
||||
display_cursor = true;
|
||||
|
||||
input->mouse_left_button_timeout = DISABLE_LEFT_BUTTON_DELAY;
|
||||
platf::move_mouse(platf_input, util::endian::big(packet->deltaX), util::endian::big(packet->deltaY));
|
||||
}
|
||||
|
||||
void passthrough(std::shared_ptr<input_t> &input, PNV_ABS_MOUSE_MOVE_PACKET packet) {
|
||||
display_cursor = true;
|
||||
|
||||
if(input->mouse_left_button_timeout == DISABLE_LEFT_BUTTON_DELAY) {
|
||||
input->mouse_left_button_timeout = ENABLE_LEFT_BUTTON_DELAY;
|
||||
}
|
||||
@@ -251,8 +301,6 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet
|
||||
auto constexpr BUTTON_LEFT = 0x01;
|
||||
auto constexpr BUTTON_RIGHT = 0x03;
|
||||
|
||||
display_cursor = true;
|
||||
|
||||
auto release = packet->action == BUTTON_RELEASED;
|
||||
|
||||
auto button = util::endian::big(packet->button);
|
||||
@@ -311,46 +359,86 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MOUSE_BUTTON_PACKET packet
|
||||
platf::button_mouse(platf_input, button, release);
|
||||
}
|
||||
|
||||
void repeat_key(short key_code) {
|
||||
// If key no longer pressed, stop repeating
|
||||
if(!key_press[key_code]) {
|
||||
task_id = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
platf::keyboard(platf_input, key_code & 0x00FF, false);
|
||||
|
||||
task_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
||||
}
|
||||
|
||||
short map_keycode(short keycode) {
|
||||
keycode &= 0x00FF;
|
||||
|
||||
switch(keycode) {
|
||||
case 0x10:
|
||||
return 0xA0;
|
||||
case 0x11:
|
||||
return 0xA2;
|
||||
case 0x12:
|
||||
return 0xA4;
|
||||
auto it = config::input.keybindings.find(keycode);
|
||||
if(it != std::end(config::input.keybindings)) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return keycode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update flags for keyboard shortcut combo's
|
||||
*/
|
||||
inline void update_shortcutFlags(int *flags, short keyCode, bool release) {
|
||||
switch(keyCode) {
|
||||
case VKEY_SHIFT:
|
||||
case VKEY_LSHIFT:
|
||||
case VKEY_RSHIFT:
|
||||
if(release) {
|
||||
*flags &= ~input_t::SHIFT;
|
||||
}
|
||||
else {
|
||||
*flags |= input_t::SHIFT;
|
||||
}
|
||||
break;
|
||||
case VKEY_CONTROL:
|
||||
case VKEY_LCONTROL:
|
||||
case VKEY_RCONTROL:
|
||||
if(release) {
|
||||
*flags &= ~input_t::CTRL;
|
||||
}
|
||||
else {
|
||||
*flags |= input_t::CTRL;
|
||||
}
|
||||
break;
|
||||
case VKEY_MENU:
|
||||
case VKEY_LMENU:
|
||||
case VKEY_RMENU:
|
||||
if(release) {
|
||||
*flags &= ~input_t::ALT;
|
||||
}
|
||||
else {
|
||||
*flags |= input_t::ALT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void repeat_key(short key_code) {
|
||||
// If key no longer pressed, stop repeating
|
||||
if(!key_press[key_code]) {
|
||||
key_press_repeat_id = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
platf::keyboard(platf_input, map_keycode(key_code), false);
|
||||
|
||||
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_period, key_code).task_id;
|
||||
}
|
||||
|
||||
void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
||||
auto constexpr BUTTON_RELEASED = 0x04;
|
||||
|
||||
auto release = packet->keyAction == BUTTON_RELEASED;
|
||||
auto keyCode = packet->keyCode & 0x00FF;
|
||||
|
||||
auto &pressed = key_press[packet->keyCode];
|
||||
auto &pressed = key_press[keyCode];
|
||||
if(!pressed) {
|
||||
if(!release) {
|
||||
if(task_id) {
|
||||
task_pool.cancel(task_id);
|
||||
// A new key has been pressed down, we need to check for key combo's
|
||||
// If a keycombo has been pressed down, don't pass it through
|
||||
if(input->shortcutFlags == input_t::SHORTCUT && apply_shortcut(keyCode) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(key_press_repeat_id) {
|
||||
task_pool.cancel(key_press_repeat_id);
|
||||
}
|
||||
|
||||
if(config::input.key_repeat_delay.count() > 0) {
|
||||
task_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, packet->keyCode).task_id;
|
||||
key_press_repeat_id = task_pool.pushDelayed(repeat_key, config::input.key_repeat_delay, keyCode).task_id;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -365,16 +453,15 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_KEYBOARD_PACKET packet) {
|
||||
|
||||
pressed = !release;
|
||||
|
||||
platf::keyboard(platf_input, map_keycode(packet->keyCode), release);
|
||||
update_shortcutFlags(&input->shortcutFlags, map_keycode(keyCode), release);
|
||||
platf::keyboard(platf_input, map_keycode(keyCode), release);
|
||||
}
|
||||
|
||||
void passthrough(PNV_SCROLL_PACKET packet) {
|
||||
display_cursor = true;
|
||||
|
||||
platf::scroll(platf_input, util::endian::big(packet->scrollAmt1));
|
||||
}
|
||||
|
||||
int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state) {
|
||||
int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std::int16_t new_state, const platf::rumble_queue_t &rumble_queue) {
|
||||
auto xorGamepadMask = old_state ^ new_state;
|
||||
if(!xorGamepadMask) {
|
||||
return 0;
|
||||
@@ -400,7 +487,7 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(platf::alloc_gamepad(platf_input, id)) {
|
||||
if(platf::alloc_gamepad(platf_input, id, rumble_queue)) {
|
||||
free_id(gamepadMask, id);
|
||||
// allocating a gamepad failed: solution: ignore gamepads
|
||||
// The implementations of platf::alloc_gamepad already has logging
|
||||
@@ -416,7 +503,7 @@ int updateGamepads(std::vector<gamepad_t> &gamepads, std::int16_t old_state, std
|
||||
}
|
||||
|
||||
void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET packet) {
|
||||
if(updateGamepads(input->gamepads, input->active_gamepad_state, packet->activeGamepadMask)) {
|
||||
if(updateGamepads(input->gamepads, input->active_gamepad_state, packet->activeGamepadMask, input->rumble_queue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -442,8 +529,6 @@ void passthrough(std::shared_ptr<input_t> &input, PNV_MULTI_CONTROLLER_PACKET pa
|
||||
return;
|
||||
}
|
||||
|
||||
display_cursor = false;
|
||||
|
||||
std::uint16_t bf = packet->buttonFlags;
|
||||
platf::gamepad_state_t gamepad_state {
|
||||
bf,
|
||||
@@ -552,7 +637,7 @@ void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&in
|
||||
}
|
||||
|
||||
void reset(std::shared_ptr<input_t> &input) {
|
||||
task_pool.cancel(task_id);
|
||||
task_pool.cancel(key_press_repeat_id);
|
||||
task_pool.cancel(input->mouse_left_button_timeout);
|
||||
|
||||
// Ensure input is synchronous, by using the task_pool
|
||||
@@ -571,12 +656,23 @@ void reset(std::shared_ptr<input_t> &input) {
|
||||
});
|
||||
}
|
||||
|
||||
void init() {
|
||||
class deinit_t : public platf::deinit_t {
|
||||
public:
|
||||
~deinit_t() override {
|
||||
platf_input.reset();
|
||||
}
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> init() {
|
||||
platf_input = platf::input();
|
||||
|
||||
return std::make_unique<deinit_t>();
|
||||
}
|
||||
|
||||
std::shared_ptr<input_t> alloc(safe::mail_t mail) {
|
||||
auto input = std::make_shared<input_t>(mail->event<input::touch_port_t>(mail::touch_port));
|
||||
auto input = std::make_shared<input_t>(
|
||||
mail->event<input::touch_port_t>(mail::touch_port),
|
||||
mail->queue<platf::rumble_t>(mail::rumble));
|
||||
|
||||
// Workaround to ensure new frames will be captured when a client connects
|
||||
task_pool.pushDelayed([]() {
|
||||
@@ -5,11 +5,12 @@
|
||||
#ifndef SUNSHINE_INPUT_H
|
||||
#define SUNSHINE_INPUT_H
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "platform/common.h"
|
||||
#include "thread_safe.h"
|
||||
|
||||
namespace input {
|
||||
|
||||
struct input_t;
|
||||
|
||||
void print(void *input);
|
||||
@@ -17,7 +18,7 @@ void reset(std::shared_ptr<input_t> &input);
|
||||
void passthrough(std::shared_ptr<input_t> &input, std::vector<std::uint8_t> &&input_data);
|
||||
|
||||
|
||||
void init();
|
||||
[[nodiscard]] std::unique_ptr<platf::deinit_t> init();
|
||||
|
||||
std::shared_ptr<input_t> alloc(safe::mail_t mail);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "rtsp.h"
|
||||
#include "thread_pool.h"
|
||||
#include "upnp.h"
|
||||
#include "version.h"
|
||||
#include "video.h"
|
||||
|
||||
#include "platform/common.h"
|
||||
@@ -45,7 +46,7 @@ bl::sources::severity_logger<int> warning(3); // Strange events
|
||||
bl::sources::severity_logger<int> error(4); // Recoverable errors
|
||||
bl::sources::severity_logger<int> fatal(5); // Unrecoverable errors
|
||||
|
||||
bool display_cursor;
|
||||
bool display_cursor = true;
|
||||
|
||||
using text_sink = bl::sinks::asynchronous_sink<bl::sinks::text_ostream_backend>;
|
||||
boost::shared_ptr<text_sink> sink;
|
||||
@@ -56,23 +57,34 @@ struct NoDelete {
|
||||
|
||||
BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
|
||||
|
||||
/** Print the help to stdout.
|
||||
|
||||
This function prints output to stdout.
|
||||
*/
|
||||
void print_help(const char *name) {
|
||||
std::cout
|
||||
<< "Usage: "sv << name << " [options] [/path/to/configuration_file] [--cmd]"sv << std::endl
|
||||
<< " Any configurable option can be overwritten with: \"name=value\""sv << std::endl
|
||||
<< std::endl
|
||||
<< " Note: The configuration will be created if it doesn't exist."sv << std::endl
|
||||
<< std::endl
|
||||
<< " --help | print help"sv << std::endl
|
||||
<< " --creds username password | set user credentials for the Web manager" << std::endl
|
||||
<< " --creds username password | set user credentials for the Web manager"sv << std::endl
|
||||
<< " --version | print the version of sunshine"sv << std::endl
|
||||
<< std::endl
|
||||
<< " flags"sv << std::endl
|
||||
<< " -0 | Read PIN from stdin"sv << std::endl
|
||||
<< " -1 | Do not load previously saved state and do retain any state after shutdown"sv << std::endl
|
||||
<< " | Effectively starting as if for the first time without overwriting any pairings with your devices"sv << std::endl
|
||||
<< " -2 | Force replacement of headers in video stream" << std::endl
|
||||
<< " -p | Enable/Disable UPnP" << std::endl
|
||||
<< " -2 | Force replacement of headers in video stream"sv << std::endl
|
||||
<< " -p | Enable/Disable UPnP"sv << std::endl
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/** Call the print_help function.
|
||||
|
||||
Calls the print_help function and then exits.
|
||||
*/
|
||||
namespace help {
|
||||
int entry(const char *name, int argc, char *argv[]) {
|
||||
print_help(name);
|
||||
@@ -80,6 +92,17 @@ int entry(const char *name, int argc, char *argv[]) {
|
||||
}
|
||||
} // namespace help
|
||||
|
||||
/** Print the version details to stdout.
|
||||
|
||||
This function prints the version details to stdout and then exits.
|
||||
*/
|
||||
namespace version {
|
||||
int entry(const char *name, int argc, char *argv[]) {
|
||||
std::cout << PROJECT_NAME << " version: v" << PROJECT_VER << std::endl;
|
||||
return 0;
|
||||
}
|
||||
} // namespace version
|
||||
|
||||
void log_flush() {
|
||||
sink->flush();
|
||||
}
|
||||
@@ -111,10 +134,28 @@ int entry(const char *name, int argc, char *argv[]) {
|
||||
|
||||
std::map<std::string_view, std::function<int(const char *name, int argc, char **argv)>> cmd_to_func {
|
||||
{ "creds"sv, gen_creds::entry },
|
||||
{ "help"sv, help::entry }
|
||||
{ "help"sv, help::entry },
|
||||
{ "version"sv, version::entry }
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
util::TaskPool::task_id_t force_shutdown = nullptr;
|
||||
|
||||
bool shutdown_by_interrupt = false;
|
||||
|
||||
auto exit_guard = util::fail_guard([&shutdown_by_interrupt, &force_shutdown]() {
|
||||
if(!shutdown_by_interrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
task_pool.cancel(force_shutdown);
|
||||
|
||||
std::cout << "Sunshine exited: Press enter to continue"sv << std::endl;
|
||||
|
||||
std::string _;
|
||||
std::getline(std::cin, _);
|
||||
});
|
||||
|
||||
mail::man = std::make_shared<safe::mail_raw_t>();
|
||||
|
||||
if(config::parse(argc, argv)) {
|
||||
@@ -168,6 +209,10 @@ int main(int argc, char *argv[]) {
|
||||
os << _date << log_type << view.attribute_values()[message].extract<std::string>();
|
||||
});
|
||||
|
||||
// Flush after each log record to ensure log file contents on disk isn't stale.
|
||||
// This is particularly important when running from a Windows service.
|
||||
sink->locked_backend()->auto_flush(true);
|
||||
|
||||
bl::core::get()->add_sink(sink);
|
||||
auto fg = util::fail_guard(log_flush);
|
||||
|
||||
@@ -189,9 +234,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
task_pool.start(1);
|
||||
|
||||
bool shutdown_by_interrupt = false;
|
||||
|
||||
util::TaskPool::task_id_t force_shutdown = nullptr;
|
||||
// Create signal handler after logging has been initialized
|
||||
auto shutdown_event = mail::man->event<bool>(mail::shutdown);
|
||||
on_signal(SIGINT, [&shutdown_by_interrupt, &force_shutdown, shutdown_event]() {
|
||||
@@ -221,19 +263,6 @@ int main(int argc, char *argv[]) {
|
||||
shutdown_event->raise(true);
|
||||
});
|
||||
|
||||
auto exit_guard = util::fail_guard([&shutdown_by_interrupt, &force_shutdown]() {
|
||||
if(!shutdown_by_interrupt) {
|
||||
return;
|
||||
}
|
||||
|
||||
task_pool.cancel(force_shutdown);
|
||||
|
||||
std::cout << "Sunshine exited: Press enter to continue"sv << std::endl;
|
||||
|
||||
std::string _;
|
||||
std::getline(std::cin, _);
|
||||
});
|
||||
|
||||
proc::refresh(config::stream.file_apps);
|
||||
|
||||
auto deinit_guard = platf::init();
|
||||
@@ -242,7 +271,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
reed_solomon_init();
|
||||
input::init();
|
||||
auto input_deinit_guard = input::init();
|
||||
if(video::init()) {
|
||||
return 2;
|
||||
}
|
||||
@@ -311,4 +340,4 @@ int write_file(const char *path, const std::string_view &contents) {
|
||||
|
||||
std::uint16_t map_port(int port) {
|
||||
return (std::uint16_t)((int)config::sunshine.port + port);
|
||||
}
|
||||
}
|
||||
@@ -44,9 +44,12 @@ MAIL(broadcast_shutdown);
|
||||
MAIL(video_packets);
|
||||
MAIL(audio_packets);
|
||||
|
||||
MAIL(switch_display);
|
||||
|
||||
// Local mail
|
||||
MAIL(touch_port);
|
||||
MAIL(idr);
|
||||
MAIL(rumble);
|
||||
#undef MAIL
|
||||
} // namespace mail
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user