mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-11 03:11:33 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69a4f0ea1e | ||
|
|
cc335202a8 | ||
|
|
12eebedf1f | ||
|
|
fbc972b39e | ||
|
|
97dea65a8c | ||
|
|
8c339fd900 | ||
|
|
931e3fcabd | ||
|
|
2e8b001dd9 | ||
|
|
1efcc55bff | ||
|
|
39b75272f3 | ||
|
|
59b05fa034 | ||
|
|
d95fbb2655 | ||
|
|
9c2f39a129 | ||
|
|
2d9f6a916a | ||
|
|
447daab3b2 | ||
|
|
3ceed07cd0 | ||
|
|
d848490295 | ||
|
|
37be83913b | ||
|
|
b5e2956a5a | ||
|
|
cf30bc29bb | ||
|
|
a609b709eb | ||
|
|
83c663e5e9 | ||
|
|
dd8973f1e6 | ||
|
|
f382d8d321 | ||
|
|
5ed53646b9 | ||
|
|
cf3c678de5 | ||
|
|
acd3fa1172 | ||
|
|
72b7f058a3 | ||
|
|
9f9a984b99 | ||
|
|
1be2ba8d20 | ||
|
|
01cc7b3104 | ||
|
|
0a30809931 | ||
|
|
8675fcd79a | ||
|
|
4668afca71 | ||
|
|
81555b9da6 | ||
|
|
0e14bba04c | ||
|
|
85245e5514 | ||
|
|
1e66e9d16b | ||
|
|
b8372337a0 | ||
|
|
b1e10faa01 | ||
|
|
a15217dbaf | ||
|
|
6d5672c669 | ||
|
|
4fd47962c8 | ||
|
|
749bc23ecd | ||
|
|
2a08e0104d | ||
|
|
7fc802698a | ||
|
|
53dfaa1f85 | ||
|
|
3df2dfa095 | ||
|
|
906dbd8cc0 | ||
|
|
28783c657a | ||
|
|
b5e767acaa | ||
|
|
703321e807 | ||
|
|
9a0abbed5d | ||
|
|
9f45a4a4ac | ||
|
|
a6e7ff2fe8 | ||
|
|
40b4503e93 | ||
|
|
5650d91608 | ||
|
|
74c03d26d2 | ||
|
|
6fc1091ff6 | ||
|
|
994a5cda7a | ||
|
|
46c53538c6 | ||
|
|
b5509769c2 | ||
|
|
38dc5d8267 | ||
|
|
c0be192868 | ||
|
|
05175a487c | ||
|
|
36a4c83b88 | ||
|
|
c58528696c | ||
|
|
325393aaa1 | ||
|
|
fdb283845d | ||
|
|
95680d8b3f | ||
|
|
0a253e341f | ||
|
|
59d74a0c8b | ||
|
|
11018c8356 | ||
|
|
6af74f3b55 | ||
|
|
c2d5bd57f7 | ||
|
|
7ad9852bc5 | ||
|
|
2526b375e7 | ||
|
|
16025e51b8 | ||
|
|
cf7824e0fd | ||
|
|
77076ae3c9 | ||
|
|
2827bb5d0d | ||
|
|
5388b0628e | ||
|
|
eb75997cbb | ||
|
|
7a4214d9fc | ||
|
|
a9da1bc664 | ||
|
|
ac6eb4bb08 | ||
|
|
58f4d04bb9 | ||
|
|
f97d6c9d63 | ||
|
|
f01a03c586 | ||
|
|
458a059eb5 | ||
|
|
850cc56196 | ||
|
|
5048003e20 | ||
|
|
09a7ec737d | ||
|
|
cbed0afd39 | ||
|
|
35bb3f869b | ||
|
|
b38369e9ff | ||
|
|
91aedbe24e | ||
|
|
943be3352b | ||
|
|
4979c66d50 | ||
|
|
5acda87142 | ||
|
|
0a2c684849 | ||
|
|
ee59a4e58c | ||
|
|
04e06f7457 | ||
|
|
1f2bf72734 | ||
|
|
7d223f6061 | ||
|
|
b3620f14b4 | ||
|
|
bbe9f3244c | ||
|
|
4b796f3bd9 | ||
|
|
081ced9940 | ||
|
|
c699b28151 | ||
|
|
5ae5641fc2 | ||
|
|
1fb62ff4ac | ||
|
|
ff7b84ba5a | ||
|
|
7b2912b014 | ||
|
|
768c2bf355 | ||
|
|
3c7cd3511c | ||
|
|
ef9dc83041 | ||
|
|
7d5c1b5085 | ||
|
|
a6d765d959 | ||
|
|
a019b92f26 | ||
|
|
ccf0f97e17 | ||
|
|
61e951e367 | ||
|
|
68c5d3c109 | ||
|
|
be43a2464b | ||
|
|
e618d3d932 | ||
|
|
53f90ba5f2 | ||
|
|
357fce853e | ||
|
|
683899e5dc | ||
|
|
4ed05b0d43 | ||
|
|
fcded627b3 | ||
|
|
d18adfd2c0 | ||
|
|
6217684ade | ||
|
|
575754d584 | ||
|
|
044c9f8fa9 | ||
|
|
a74b8d058c | ||
|
|
7e0d99f745 | ||
|
|
1472478af8 | ||
|
|
79a627a172 | ||
|
|
477cb705b2 | ||
|
|
11d4e46e9f | ||
|
|
bfa603828d | ||
|
|
4c7a1a5322 | ||
|
|
63c4a393c0 | ||
|
|
f4e2cea399 | ||
|
|
cbd1c06b1a | ||
|
|
933baca92b | ||
|
|
f189ed5fec | ||
|
|
fc1acf4d6c | ||
|
|
26eb19b31a | ||
|
|
d43a6410c6 | ||
|
|
cd23c32a83 | ||
|
|
82f4f67617 | ||
|
|
b62ee31508 | ||
|
|
fcf0cc7483 | ||
|
|
8c10eaa250 | ||
|
|
ff025a8d6e | ||
|
|
2d1f5070ee | ||
|
|
053ced8d1c | ||
|
|
656ab420d1 | ||
|
|
6bf2950b16 | ||
|
|
9fdd60a6bc | ||
|
|
ba95a1f611 | ||
|
|
08ed87c587 | ||
|
|
d3bbe88450 | ||
|
|
5d066f65fd | ||
|
|
6d1c26a572 | ||
|
|
8d16395de9 | ||
|
|
64ff381f72 | ||
|
|
8036fed21f | ||
|
|
4fe5509c65 | ||
|
|
100c69d4c8 | ||
|
|
b3a2f802b9 | ||
|
|
43abea5661 | ||
|
|
328e4ce825 | ||
|
|
cfcece201c | ||
|
|
2aad8ad8e6 | ||
|
|
8ec8b7c797 | ||
|
|
5fe9836007 | ||
|
|
b9b085de97 | ||
|
|
b300f72905 | ||
|
|
deb9cd35c9 | ||
|
|
8f73291977 | ||
|
|
df1ccb9497 | ||
|
|
ff5fd9d527 | ||
|
|
1cb11b52a4 | ||
|
|
e15bd1dcb9 | ||
|
|
14288e1162 | ||
|
|
5ace54acc4 | ||
|
|
1a01ea7e53 | ||
|
|
03a3fe5963 | ||
|
|
636b98feea | ||
|
|
a9ba292d9e | ||
|
|
87d8866f54 | ||
|
|
cdd98f5ac4 | ||
|
|
3f19b2a107 | ||
|
|
8141b31151 | ||
|
|
6c1b32de42 | ||
|
|
a16d651ba7 | ||
|
|
8de17098d1 | ||
|
|
b73d76445f | ||
|
|
19bbc713ed | ||
|
|
aa89097cc0 | ||
|
|
cfc59dbbd9 | ||
|
|
7c7edb7191 | ||
|
|
f54bcf3ef4 | ||
|
|
1ff174b885 | ||
|
|
9504583ae5 | ||
|
|
4d87f25bf6 | ||
|
|
d2df617ed1 | ||
|
|
6fc0e56f05 | ||
|
|
e416cfb763 | ||
|
|
9c3966eb66 | ||
|
|
3fa2648ff3 | ||
|
|
1d63c4934e | ||
|
|
62a09b5a07 | ||
|
|
db88400ee9 | ||
|
|
d2c6f80f69 | ||
|
|
5aa36630bc | ||
|
|
a650525e6e | ||
|
|
d049191990 | ||
|
|
d11766a205 | ||
|
|
2fe04daaea | ||
|
|
c4b655a583 | ||
|
|
3dfa5cb02d | ||
|
|
21776a2e59 | ||
|
|
79f0b052c7 | ||
|
|
f41f46726e | ||
|
|
b4bf792e24 | ||
|
|
ac8ab50ada | ||
|
|
a0732357ff | ||
|
|
41b144ef38 | ||
|
|
89f15a7b0e | ||
|
|
97f99c5f19 | ||
|
|
fa42321488 | ||
|
|
3d7d6c93b5 | ||
|
|
d95ed2343c | ||
|
|
e69ee5af05 | ||
|
|
5fd3c01325 | ||
|
|
1fbcf87f02 | ||
|
|
4ff2f1de0f | ||
|
|
989417d706 | ||
|
|
a773c506b6 | ||
|
|
4c9357fff0 | ||
|
|
313f057fb7 | ||
|
|
46db791ceb | ||
|
|
4159da6cc9 | ||
|
|
b2ec648a71 | ||
|
|
0b11934691 | ||
|
|
69d4c9ac85 | ||
|
|
8c39c8856b | ||
|
|
6ee880614d | ||
|
|
f91d3d5bfb | ||
|
|
bd56674b51 | ||
|
|
1834795e9b | ||
|
|
7866687476 | ||
|
|
a17bf5ed39 | ||
|
|
30b36c5943 | ||
|
|
3d007f9afc | ||
|
|
098fe99ded | ||
|
|
c32aa80cea | ||
|
|
c93af63186 | ||
|
|
5c981d3f5c | ||
|
|
a684db7b17 | ||
|
|
9c604a2814 | ||
|
|
e2ff006ad7 | ||
|
|
05b24cce09 | ||
|
|
a7f1107631 | ||
|
|
69668a2afc | ||
|
|
a990bb38fa | ||
|
|
f5b63a4bb7 | ||
|
|
601fd41ba5 | ||
|
|
f01b6063a9 | ||
|
|
03c63c581f | ||
|
|
42ccdc0d25 | ||
|
|
3ebc2f7db2 | ||
|
|
ab898468be | ||
|
|
e341333593 | ||
|
|
ec573825b8 | ||
|
|
9b4168deff | ||
|
|
5b6c93a5bc | ||
|
|
7c30935ed6 | ||
|
|
a1d830f7c4 | ||
|
|
699b808b4c | ||
|
|
2494e9af6f | ||
|
|
5a29ee2c8f | ||
|
|
8a86817047 | ||
|
|
aa1988088c | ||
|
|
a1de9d2051 | ||
|
|
a5b06a3885 | ||
|
|
f4dc12e323 | ||
|
|
8a72e2b1a7 | ||
|
|
d3c81605be | ||
|
|
d5c3b1cc1a | ||
|
|
b54b95a04d | ||
|
|
84c5722180 | ||
|
|
d1e36d9f11 | ||
|
|
3f21e88f09 | ||
|
|
6e4924bce6 | ||
|
|
5ac96e8c62 | ||
|
|
6c120d07a8 | ||
|
|
f7877df578 | ||
|
|
853bd62730 | ||
|
|
42b33fd1c4 | ||
|
|
cd6ee1b251 | ||
|
|
adc8739ccb | ||
|
|
1cf24c5afe | ||
|
|
79dbd3f1c0 | ||
|
|
c31727344a | ||
|
|
e6328b5707 | ||
|
|
631eca2ba6 | ||
|
|
07f8777fa5 | ||
|
|
79b5778c7a | ||
|
|
dc782cadb2 | ||
|
|
ac47eb2bce | ||
|
|
3111f62521 | ||
|
|
44746d541b | ||
|
|
f0370a1bfb | ||
|
|
e31f9c2963 | ||
|
|
a35f91d95f | ||
|
|
9c9f5aa8d0 | ||
|
|
887effcb76 | ||
|
|
b00ae41e41 | ||
|
|
7cdb5aefaf | ||
|
|
80319a9918 | ||
|
|
719a643fb2 | ||
|
|
e6514de3a7 | ||
|
|
c404e22a79 | ||
|
|
4bdaf7fd4c | ||
|
|
752de1e2c5 | ||
|
|
282308d800 | ||
|
|
5e6a2984c7 | ||
|
|
07388c5ab2 | ||
|
|
448b6e3aa0 | ||
|
|
23d1e4977a | ||
|
|
9728e5914d | ||
|
|
6775559c25 | ||
|
|
b6c5615c58 | ||
|
|
57cf4011ec | ||
|
|
3aa8db2c08 | ||
|
|
e3a5c5ea46 | ||
|
|
31e54cabfe | ||
|
|
46045a1165 | ||
|
|
e4f1f25d10 | ||
|
|
64c15f545f | ||
|
|
9b6ddfb727 | ||
|
|
fe5ea7ad45 | ||
|
|
7736095525 | ||
|
|
4f70c5aa2a | ||
|
|
b5530658a4 | ||
|
|
8376b06611 | ||
|
|
d5b33d8e29 | ||
|
|
b129c605f6 | ||
|
|
39f840eedc | ||
|
|
3164cdb352 | ||
|
|
02e932e21f | ||
|
|
129616be88 | ||
|
|
9e78ad0c88 | ||
|
|
cf3de275a3 | ||
|
|
50e8308027 | ||
|
|
661e5b55cb | ||
|
|
151d49311d | ||
|
|
6efdb108ae | ||
|
|
98d4d5faec | ||
|
|
8181583298 | ||
|
|
93bd70cd48 | ||
|
|
21773761d7 | ||
|
|
52e6566300 | ||
|
|
d67da2d1b1 | ||
|
|
351fd6a66b | ||
|
|
83c3e589e5 | ||
|
|
27f27c351f | ||
|
|
c8ab73607c | ||
|
|
248af45eaf | ||
|
|
1d4f663506 | ||
|
|
a39ed1a822 | ||
|
|
d59adf7643 | ||
|
|
65d617e378 | ||
|
|
5477ad32f6 | ||
|
|
babd363987 | ||
|
|
44bd3b21d5 | ||
|
|
f39914de4a | ||
|
|
95df52bf6b | ||
|
|
c14708e3ed | ||
|
|
546388a5bd | ||
|
|
274139dff1 | ||
|
|
38fa199f7a | ||
|
|
5fb551ae2e | ||
|
|
85d59c0b65 | ||
|
|
139dd38f9d | ||
|
|
10c6d45850 | ||
|
|
7dabae94c5 | ||
|
|
03dbcc53e7 | ||
|
|
563b687db8 | ||
|
|
8b11aec44d | ||
|
|
e3435221d8 | ||
|
|
d9d951b92e | ||
|
|
917e29c039 | ||
|
|
86e65d10be | ||
|
|
d66dd00078 | ||
|
|
cb9ed749db | ||
|
|
780eac62e6 | ||
|
|
fc98e894a6 | ||
|
|
732f598fd0 | ||
|
|
537712a634 | ||
|
|
1cb78161a6 | ||
|
|
3706c3b22d | ||
|
|
7dc3d1ed9b | ||
|
|
0990e25022 | ||
|
|
51cc74d0e0 | ||
|
|
a30b3ce1e2 | ||
|
|
5eca25067a | ||
|
|
405c3476f5 | ||
|
|
ecbc05de6b | ||
|
|
a018f54559 | ||
|
|
f8e35e5f11 | ||
|
|
a3754306c9 | ||
|
|
0e3c82ecd6 | ||
|
|
84b07468f3 | ||
|
|
e7944cc1a8 | ||
|
|
24eb75dda0 | ||
|
|
d89988f7d7 | ||
|
|
a485bf7f16 | ||
|
|
63a146f0ea | ||
|
|
3e29213d5e | ||
|
|
108bbc3879 | ||
|
|
83cdca400b | ||
|
|
320bb32406 | ||
|
|
88e0a0e8ca | ||
|
|
9567f3cbd9 | ||
|
|
ab47260fca | ||
|
|
34bc60e6d4 | ||
|
|
77185a734d | ||
|
|
dc2bf1226e | ||
|
|
4bcf5dd1a2 | ||
|
|
0f510fad39 | ||
|
|
c6622f5f0a | ||
|
|
5d43932aee | ||
|
|
5fec502174 | ||
|
|
80f2d91ef3 | ||
|
|
ab7a3e9ffa | ||
|
|
ef69296be3 | ||
|
|
318e3ca9c1 | ||
|
|
4d76e042ad | ||
|
|
1e2500f736 | ||
|
|
8f4990e835 | ||
|
|
072d953b01 | ||
|
|
b425abd0bb | ||
|
|
817428b772 | ||
|
|
1191c964b1 | ||
|
|
3acebdac0a | ||
|
|
09b9aec72e | ||
|
|
77f2d8cce5 | ||
|
|
1d17a50a9d | ||
|
|
4a256179ad | ||
|
|
85aa59dc4f | ||
|
|
5e5f047e5b | ||
|
|
58dcecea08 | ||
|
|
0747dc6eb0 | ||
|
|
7280859069 | ||
|
|
2364ef7827 | ||
|
|
590a945cc2 | ||
|
|
3829672dc1 | ||
|
|
a86c031410 | ||
|
|
312550f499 | ||
|
|
d9dba4e376 | ||
|
|
8dfc31461e | ||
|
|
5ba1e7077e | ||
|
|
4c3a88a2f8 | ||
|
|
051c5cff77 | ||
|
|
13c6eb53c9 | ||
|
|
c1862dccc8 | ||
|
|
903501f183 | ||
|
|
a6b7cf459e | ||
|
|
e18b01302d | ||
|
|
9b1d67c03a | ||
|
|
9e31b35f1b | ||
|
|
e453abc71b | ||
|
|
327621938b | ||
|
|
341f6d3df4 | ||
|
|
9e0b21da5e | ||
|
|
af28b06d02 | ||
|
|
d452cb843b | ||
|
|
5afbd5f53d | ||
|
|
26293387c4 | ||
|
|
d3756624c8 | ||
|
|
4b77ad663a | ||
|
|
e24ca9da66 | ||
|
|
f1198c65a3 | ||
|
|
d99d8a8547 | ||
|
|
2153ab55ad | ||
|
|
9ab7cd6a62 | ||
|
|
8e30bbe3e2 | ||
|
|
eb6f0c8dba | ||
|
|
dc9ffcce66 | ||
|
|
99fe15be46 | ||
|
|
7b66dec4f0 | ||
|
|
b0e344a423 | ||
|
|
6182e39938 | ||
|
|
d821ce1062 | ||
|
|
26b806f860 | ||
|
|
fa2ce70c5b | ||
|
|
954d202637 | ||
|
|
02f3f31121 | ||
|
|
974c016241 | ||
|
|
e011e710bd | ||
|
|
ff652ce22d | ||
|
|
f8840774e3 | ||
|
|
99e7a80314 | ||
|
|
4b5b214dea | ||
|
|
8ecb7eefd7 | ||
|
|
c9452d9263 | ||
|
|
c89a44b15b | ||
|
|
e04985162a | ||
|
|
0efe022e9d | ||
|
|
ae8dfc789d | ||
|
|
dd5dc60520 | ||
|
|
d500a3ecc7 | ||
|
|
43cec217b9 | ||
|
|
55a7e07959 | ||
|
|
9308f6650c | ||
|
|
cb2f0ecbd2 | ||
|
|
eff70a32e5 | ||
|
|
59fd200b2c | ||
|
|
d17f6eee1e | ||
|
|
d86c1a89b8 | ||
|
|
9542a71c89 | ||
|
|
fb6f6467e0 | ||
|
|
9187520222 | ||
|
|
58b686f661 | ||
|
|
25546f864a | ||
|
|
b156ce2a42 | ||
|
|
40671b293e | ||
|
|
a018f935d0 | ||
|
|
57a8a731da | ||
|
|
c9931cd936 | ||
|
|
25edbe17d2 | ||
|
|
8bd60af8b7 | ||
|
|
cc408864af | ||
|
|
cd0f159238 | ||
|
|
180b39cd3d | ||
|
|
6019fc863b | ||
|
|
80b3ccebba | ||
|
|
a4535c4eac | ||
|
|
dddc66c797 | ||
|
|
b23cbf0a57 | ||
|
|
2f5d95b0cf | ||
|
|
5ed20207f5 | ||
|
|
9ca8e1c1c1 | ||
|
|
ae2465f0db | ||
|
|
d822cf58a1 | ||
|
|
ab9535c827 | ||
|
|
dd480aac94 | ||
|
|
4c07e26649 | ||
|
|
162d00d73b | ||
|
|
7b093cc55e | ||
|
|
195c19a1c9 | ||
|
|
03573db27c | ||
|
|
f45fd77d68 | ||
|
|
c6d72062e2 | ||
|
|
3f4fd3b086 | ||
|
|
b7479e934b | ||
|
|
efc1f7f8e1 | ||
|
|
807866d799 | ||
|
|
daeb46cf5a | ||
|
|
cc826c4ca6 | ||
|
|
d8725d77bb | ||
|
|
7c05359933 | ||
|
|
1cc76cd64d | ||
|
|
19f6d94a78 | ||
|
|
df808f7663 | ||
|
|
c8cb58f1d2 | ||
|
|
2770470695 | ||
|
|
047f926540 | ||
|
|
d37068cfb8 | ||
|
|
3162b6a438 | ||
|
|
027564a0c9 | ||
|
|
1e0c723ba3 | ||
|
|
14906fc489 | ||
|
|
6010c74559 | ||
|
|
6227156e73 | ||
|
|
46be205b75 | ||
|
|
f73d9dead3 | ||
|
|
6fa73c3431 | ||
|
|
ad5a98f2d3 | ||
|
|
4099b49483 | ||
|
|
6e5e63b6d4 | ||
|
|
1cc0f3273f | ||
|
|
9b6641c951 | ||
|
|
2d632fed54 | ||
|
|
246caaec3f | ||
|
|
27f141a7a5 | ||
|
|
3eb8589550 | ||
|
|
9cfcc5ec8e | ||
|
|
215219dc51 | ||
|
|
9c82213d19 | ||
|
|
b7db9a65af | ||
|
|
6010a53fec | ||
|
|
435849d00f | ||
|
|
de298b18c4 | ||
|
|
3226361c1d | ||
|
|
86b55c14ec | ||
|
|
2f9b0181dd | ||
|
|
f6da101330 | ||
|
|
43031d2154 | ||
|
|
de76511ee7 | ||
|
|
228f4b346d | ||
|
|
dabf543cde | ||
|
|
55bada6bda | ||
|
|
311a64a413 | ||
|
|
e683017f45 | ||
|
|
4973e47cac | ||
|
|
04af1a1e98 | ||
|
|
72ff77347f | ||
|
|
31014e99c0 | ||
|
|
4a7b00f43e | ||
|
|
0d854fef31 | ||
|
|
cb02d1ffcf | ||
|
|
743e0406bd | ||
|
|
419007c1ca | ||
|
|
1808a38deb | ||
|
|
4bdb68b9d9 | ||
|
|
2dbb9f62d8 | ||
|
|
bca5cafaa6 | ||
|
|
b2ca569521 | ||
|
|
40e3b56d04 | ||
|
|
3885f4f8a5 | ||
|
|
d5a5681612 | ||
|
|
47bc1188ae | ||
|
|
d4fe2055f9 | ||
|
|
ac959fef26 | ||
|
|
48f5677417 | ||
|
|
f10818b243 | ||
|
|
3e3f989d45 | ||
|
|
90f2c1f456 | ||
|
|
d316c2cbc9 | ||
|
|
0a2c1b2272 | ||
|
|
1dea6dfbf0 | ||
|
|
7d09e380f4 | ||
|
|
fd7f561fb6 | ||
|
|
0ca114701b | ||
|
|
0ba251b7f2 | ||
|
|
4704961eb9 | ||
|
|
6046e29919 | ||
|
|
f1d95f2deb | ||
|
|
d165787296 | ||
|
|
68d8f98d47 | ||
|
|
5367d3ab63 | ||
|
|
71dc58d20a | ||
|
|
d8012c901b | ||
|
|
c61845895e | ||
|
|
135da9597b | ||
|
|
1389c15280 | ||
|
|
d40625b87c | ||
|
|
371ddf5889 | ||
|
|
9ff5aaa679 | ||
|
|
70a39217c1 | ||
|
|
6c2a2a1b2c | ||
|
|
eea37466fc | ||
|
|
1e109e2927 | ||
|
|
4161099ddb | ||
|
|
b365ab02a6 | ||
|
|
f5e81aa01d | ||
|
|
6dcb727c62 | ||
|
|
f4bba523ab | ||
|
|
e13140ba04 | ||
|
|
a8caac7142 | ||
|
|
46fd8f6532 | ||
|
|
bc3f1c6487 | ||
|
|
b0294736ed | ||
|
|
c680a72a18 | ||
|
|
c30d790854 | ||
|
|
2590cc9120 | ||
|
|
f1289f60ef | ||
|
|
69b82e1fc2 | ||
|
|
0fbce9680a | ||
|
|
5e578f9fc4 | ||
|
|
6056a0e602 | ||
|
|
6e1597970b | ||
|
|
243ed9d171 | ||
|
|
2553927119 | ||
|
|
69a9e05067 | ||
|
|
185971182d | ||
|
|
c27e815808 | ||
|
|
0575ee99c6 | ||
|
|
12599993c0 | ||
|
|
8c6744145e | ||
|
|
f30947840e | ||
|
|
ece640fd87 | ||
|
|
75719b2177 | ||
|
|
b3b8b1e340 | ||
|
|
ac46d10e4a | ||
|
|
c16840444e | ||
|
|
d9d874712c | ||
|
|
cc4373d7a4 | ||
|
|
dea40e01bc | ||
|
|
883d93f04c | ||
|
|
3b7bea875e | ||
|
|
cc2440fe7f | ||
|
|
d3635843c9 | ||
|
|
e92be2a89d | ||
|
|
9e5f6f4d8a | ||
|
|
21c00e79f9 | ||
|
|
6126413e92 | ||
|
|
1f5804cb59 | ||
|
|
f85b738258 | ||
|
|
26f6f7200a | ||
|
|
ceb99a0644 | ||
|
|
9b9788873c | ||
|
|
5907714842 | ||
|
|
8ba7a585cc | ||
|
|
ab543fb8bd | ||
|
|
0e4136537b | ||
|
|
d471cbce8a | ||
|
|
42704b9311 | ||
|
|
383daa31cb | ||
|
|
db5c4d2758 | ||
|
|
b490195e0b | ||
|
|
9595904af1 | ||
|
|
2329cd10d0 | ||
|
|
3e3e4e6ce5 | ||
|
|
293ca23197 | ||
|
|
bb0551bf1e | ||
|
|
3faf744b0f | ||
|
|
0785dd7548 | ||
|
|
fae1c6bcf6 | ||
|
|
b774a26bae | ||
|
|
0fc847a176 | ||
|
|
fc6b1b9fab | ||
|
|
c9eb36d4db | ||
|
|
a7c195901f | ||
|
|
a034e9b61b | ||
|
|
f86ae06c10 | ||
|
|
771fc523b2 | ||
|
|
45c3f93e8b | ||
|
|
2e4c29264e | ||
|
|
f9c99288da | ||
|
|
75a8193e62 | ||
|
|
5cfb0a3e42 | ||
|
|
9d09ec3478 | ||
|
|
366bf083e4 | ||
|
|
9c7203bd6f | ||
|
|
b65737f923 | ||
|
|
a8de4dbe49 | ||
|
|
57fe5598b7 | ||
|
|
68ffc370a9 | ||
|
|
8fd0d552ca | ||
|
|
aebfff2166 | ||
|
|
46b7026978 | ||
|
|
c5851487cc | ||
|
|
0b001e46c0 | ||
|
|
4abd8fa816 | ||
|
|
3344af01d7 | ||
|
|
97ab384c00 | ||
|
|
166c394cf2 | ||
|
|
5f606b9df0 | ||
|
|
a78826ee9e | ||
|
|
9795fd2daa | ||
|
|
fec832a03c | ||
|
|
0c279b9dbc | ||
|
|
8d579bba30 | ||
|
|
cc408b7ad5 | ||
|
|
c1f7982ec0 | ||
|
|
bb6a0c5772 | ||
|
|
52bfb2a7c3 | ||
|
|
631f318e28 | ||
|
|
4e4855b44c | ||
|
|
e8da8f8d29 | ||
|
|
a21643b7fa | ||
|
|
8b82cccb7a | ||
|
|
3f59af3f99 | ||
|
|
30b0b39df1 | ||
|
|
3543080194 | ||
|
|
84a5ded33c | ||
|
|
1fba899657 | ||
|
|
663f318d5f | ||
|
|
ba156cee4d | ||
|
|
446a847aab | ||
|
|
2561737403 | ||
|
|
4389c611ef | ||
|
|
d6c9698353 | ||
|
|
e613e2c08e | ||
|
|
67a46ae077 | ||
|
|
c9360262ec | ||
|
|
5aefb761eb | ||
|
|
28300fc606 | ||
|
|
b353e8d972 | ||
|
|
20c932e236 | ||
|
|
5dfd11257e | ||
|
|
434f41b935 | ||
|
|
ca405929ad | ||
|
|
a0263db217 | ||
|
|
720f5bca59 | ||
|
|
49d4a580d9 | ||
|
|
67b5da6a50 | ||
|
|
3315e96b2d | ||
|
|
1ca2e08590 | ||
|
|
76b515cd38 | ||
|
|
824182a54a | ||
|
|
6cae1c91cb | ||
|
|
a6aa14208b | ||
|
|
d236ecfa28 | ||
|
|
390f1d3760 | ||
|
|
2d16bbd5a2 | ||
|
|
19df62e737 | ||
|
|
9bc3d5e656 | ||
|
|
5531f743ea | ||
|
|
b63e982712 | ||
|
|
59442128a6 | ||
|
|
01a3203a3a | ||
|
|
274f253e75 | ||
|
|
3cbe9fa5c2 | ||
|
|
c74164c6d0 | ||
|
|
dcf4286d06 | ||
|
|
482b8241b8 | ||
|
|
9c7347c509 | ||
|
|
b2f86fa45f | ||
|
|
04eb45b413 | ||
|
|
2899bd183a | ||
|
|
01a3511445 | ||
|
|
86f63e1f59 | ||
|
|
9aac188d2c | ||
|
|
a44c65f44c | ||
|
|
bdd80921b5 | ||
|
|
98852bd427 | ||
|
|
4b7806afe7 | ||
|
|
83130f47b5 | ||
|
|
9be49b9390 | ||
|
|
38a3b924ae | ||
|
|
19398209ed | ||
|
|
ca19b79960 | ||
|
|
0a4ff8187a | ||
|
|
15f4f1e63c | ||
|
|
b7a29bd17c | ||
|
|
6c54b2183b | ||
|
|
dd8fff113b | ||
|
|
15819612f7 | ||
|
|
18ca0e671d | ||
|
|
82dde53f7d | ||
|
|
f1f50bf7f7 | ||
|
|
1ff8346eb5 | ||
|
|
bd04f9154b | ||
|
|
c372dfad8b | ||
|
|
b1ad554a14 | ||
|
|
2e91214404 | ||
|
|
dc4dd657f9 | ||
|
|
f9db98194b | ||
|
|
7ad10258f0 | ||
|
|
fd7f8a3ea1 | ||
|
|
8894d551e7 | ||
|
|
686c7997bc | ||
|
|
c9bc941830 | ||
|
|
bd9561d93c | ||
|
|
08c0221c27 | ||
|
|
13790a0fad | ||
|
|
4e30df6392 | ||
|
|
74599fd776 | ||
|
|
cfa839f5b6 | ||
|
|
a1a50afc9e | ||
|
|
b3fd3e15ed | ||
|
|
03be66836e | ||
|
|
7426251263 | ||
|
|
49ee835c82 | ||
|
|
0f664c739b | ||
|
|
4529d06a5a | ||
|
|
5cb15e1cd7 | ||
|
|
f877adb5d9 | ||
|
|
7d3740d4c0 | ||
|
|
3b44efe122 | ||
|
|
1c0f945c21 | ||
|
|
d2a824c1a7 | ||
|
|
158ad0c4bc | ||
|
|
cd4894d627 | ||
|
|
d8cd500316 | ||
|
|
0514f203eb | ||
|
|
86308ef670 | ||
|
|
65f76bd514 | ||
|
|
a4f73c622d | ||
|
|
990cc9b0b2 | ||
|
|
e5d86c0ffb | ||
|
|
3f2021249b | ||
|
|
df42b13bbc | ||
|
|
1956b6e01f | ||
|
|
dd45f8cb0c | ||
|
|
d5699457ca | ||
|
|
4ba004a1e8 | ||
|
|
766f895948 | ||
|
|
5514f71a00 | ||
|
|
99b4b66174 | ||
|
|
65435d1703 | ||
|
|
7e52201fb6 | ||
|
|
0c872e7c94 | ||
|
|
91608d6bd0 | ||
|
|
0a6db1088a | ||
|
|
c2d7366ea1 | ||
|
|
ca190dbe0a | ||
|
|
79a05ef286 | ||
|
|
610a6d0026 | ||
|
|
5afbca8904 | ||
|
|
8cfdfebb03 | ||
|
|
14c5956ff8 | ||
|
|
e2b725b5a3 | ||
|
|
f5280fe526 | ||
|
|
0e4cf00d1f | ||
|
|
7d98987f9d | ||
|
|
072142b5af | ||
|
|
5568a1e25d | ||
|
|
531a8d75a7 | ||
|
|
ac3c83eca1 | ||
|
|
f0dcd6810c | ||
|
|
48f77a948f | ||
|
|
b632a1373e | ||
|
|
97bc2da36c | ||
|
|
537bc2dbe9 | ||
|
|
f1538b1326 | ||
|
|
a77049b022 | ||
|
|
19239287bf | ||
|
|
13616bafe0 | ||
|
|
b5cbe6eaed | ||
|
|
cc57bbc06e | ||
|
|
45764673c7 | ||
|
|
667b16964b | ||
|
|
9c9d68ae20 | ||
|
|
5b0fb96443 | ||
|
|
f260d3edab | ||
|
|
ce406353cc | ||
|
|
b1da352de6 | ||
|
|
bd5f47afbb | ||
|
|
1886f76bba | ||
|
|
7bc992437c | ||
|
|
4f22a04436 | ||
|
|
cd78050c79 | ||
|
|
0f65f2f0f3 | ||
|
|
ee11b79738 | ||
|
|
30ffb042c6 | ||
|
|
57acb067b8 | ||
|
|
0900cd7540 | ||
|
|
c794376223 | ||
|
|
906c0be946 | ||
|
|
2f1ae73dd4 | ||
|
|
6ade319137 | ||
|
|
1b61b88274 | ||
|
|
5e03ef57ec | ||
|
|
874cc00c2e | ||
|
|
1be64020f5 | ||
|
|
45e13e3f2d | ||
|
|
84a52677b5 | ||
|
|
b590d843bc | ||
|
|
0818feb131 | ||
|
|
c90804c2ad | ||
|
|
759104acd4 | ||
|
|
79d78a6860 | ||
|
|
73426f823d | ||
|
|
8e154e0df6 | ||
|
|
df1c342cb2 | ||
|
|
cacff13799 | ||
|
|
ae9e8ba75c | ||
|
|
6be300b07c | ||
|
|
7264709776 | ||
|
|
f9bdd7bc87 | ||
|
|
7b37f85a99 | ||
|
|
c3cb4a8b5d | ||
|
|
2d3c18e48d | ||
|
|
9cf03289ec | ||
|
|
c4ee58a81a | ||
|
|
6c7b648570 | ||
|
|
7cffc6bb60 | ||
|
|
a8d65325a7 | ||
|
|
10738f532c | ||
|
|
0b547bdd49 | ||
|
|
d3cf9aa651 | ||
|
|
eb35401e1a | ||
|
|
67a2793ab4 | ||
|
|
3bfed628ff | ||
|
|
2ddd9330fe | ||
|
|
ba8b97041e | ||
|
|
0670d6d87e | ||
|
|
5ba3fa6fd4 | ||
|
|
28f81e8e71 | ||
|
|
463770c3c2 | ||
|
|
3637f49ddc | ||
|
|
19257e2190 | ||
|
|
e78898f379 | ||
|
|
015e515e9e | ||
|
|
583687081c | ||
|
|
e3583cbcbb | ||
|
|
2a225a20dc | ||
|
|
34e68a44ab | ||
|
|
0c1402d92a | ||
|
|
2e868fc00b | ||
|
|
63487e8ed8 | ||
|
|
4c30e94aa2 | ||
|
|
6bfb7862e7 | ||
|
|
14c78b6c32 | ||
|
|
4b6d315ad6 | ||
|
|
28a300d00f | ||
|
|
811a32b982 | ||
|
|
baee906ef3 | ||
|
|
c968c1a51d | ||
|
|
fe5defea71 | ||
|
|
fb94043d48 | ||
|
|
6235f3138b | ||
|
|
05f94af415 | ||
|
|
48f842f307 | ||
|
|
0c838c14e9 | ||
|
|
54af661d95 | ||
|
|
a7fab4a394 | ||
|
|
633ee296e7 | ||
|
|
ebd79bfa72 | ||
|
|
3036fecc7c | ||
|
|
fdcd4e78e8 | ||
|
|
57845fd3cf | ||
|
|
30aad19fae | ||
|
|
8af10c25a1 | ||
|
|
3ee6dd6481 | ||
|
|
55f9f92eaf | ||
|
|
92fecf68b1 | ||
|
|
1a5eb6e8b9 | ||
|
|
b2a5e97923 | ||
|
|
ab515cd22d | ||
|
|
03525ffd5f | ||
|
|
547d739db4 | ||
|
|
a2e512a094 | ||
|
|
76e7c9a3d9 | ||
|
|
056153ca5b | ||
|
|
309c67a205 | ||
|
|
21c5c5db36 | ||
|
|
60c8a34039 | ||
|
|
6160b71ecc | ||
|
|
0d66d4b1b3 | ||
|
|
0fef644219 | ||
|
|
597405ba89 | ||
|
|
c14016d6a2 | ||
|
|
ce36ea176a | ||
|
|
3eaa9f15a9 | ||
|
|
453348afad | ||
|
|
94149644f9 | ||
|
|
a5ddb4b007 | ||
|
|
93b1d2c8d7 | ||
|
|
f6cd9469ed | ||
|
|
d3b2c08e8b | ||
|
|
1736184f15 | ||
|
|
b9bee801fd | ||
|
|
4032fb47e8 | ||
|
|
fc15fce531 | ||
|
|
203fff1a11 | ||
|
|
d14bf2f40d | ||
|
|
fd54639965 | ||
|
|
7b99a7ce85 | ||
|
|
011469d7ef | ||
|
|
f9d79b6afd | ||
|
|
7a1c9bd0b1 | ||
|
|
d36bbb6b91 | ||
|
|
1678e25af0 | ||
|
|
69f319d16e | ||
|
|
4e35a3749e | ||
|
|
6d2e7e4ec9 | ||
|
|
cc842fd4b2 | ||
|
|
89218d5640 | ||
|
|
2ab308765d | ||
|
|
41d33e631b | ||
|
|
274d8732ab | ||
|
|
c6995c0b1d | ||
|
|
a3ba931113 | ||
|
|
ca850d09fe | ||
|
|
570290893b | ||
|
|
d6cc1847bf | ||
|
|
66aa1424f0 | ||
|
|
ea9b86c9e7 | ||
|
|
57726895dd | ||
|
|
ab3b321c66 | ||
|
|
05adec60da | ||
|
|
c63bab4c02 | ||
|
|
7998511c41 | ||
|
|
34a1b824b6 | ||
|
|
de280cad9a | ||
|
|
c93a050465 | ||
|
|
eb6305136d | ||
|
|
308593693c | ||
|
|
25a1f1bb41 | ||
|
|
e08ecd6f94 | ||
|
|
192ca4179b | ||
|
|
7f3f0106de | ||
|
|
4b2196af6c | ||
|
|
6e68e2f0da | ||
|
|
f9de17b7ed | ||
|
|
eb53b4174f | ||
|
|
e907399419 | ||
|
|
edbe0f032c | ||
|
|
58dc568c24 | ||
|
|
29072a3ac8 | ||
|
|
d631a5b632 | ||
|
|
e7c5eef862 | ||
|
|
941173c0df | ||
|
|
d373adc873 | ||
|
|
d25aaac625 | ||
|
|
cc75358335 | ||
|
|
685b937e2f | ||
|
|
41bbbc55db | ||
|
|
6a8338efe9 | ||
|
|
ddcf5285d1 | ||
|
|
fbf97b2326 | ||
|
|
ab2e577c66 | ||
|
|
4c0744b644 | ||
|
|
d76c015e9a | ||
|
|
ccc68a98bb | ||
|
|
c048a21aa4 | ||
|
|
6a302d0602 | ||
|
|
b25cb6ea63 | ||
|
|
317c80a257 | ||
|
|
5710a7f6e5 | ||
|
|
b5a4a0da79 | ||
|
|
620e440ab1 | ||
|
|
bcdb644bce | ||
|
|
4f9e86d24b | ||
|
|
4d6c012009 | ||
|
|
187673fb2a | ||
|
|
bcc3ae448f | ||
|
|
fbb093255a | ||
|
|
4f3ae82ed3 | ||
|
|
7a17ed09ee | ||
|
|
82d8b9630a | ||
|
|
aec5d1addd | ||
|
|
af50c2fccb | ||
|
|
6f95b974ba | ||
|
|
7dce21c7d5 | ||
|
|
d65c17f6b8 | ||
|
|
e8d43b3d99 | ||
|
|
b28a805f9c | ||
|
|
4bf8855fda | ||
|
|
17ac0529c2 | ||
|
|
634a0a9654 | ||
|
|
b98a730413 | ||
|
|
036df1e9b1 | ||
|
|
a10dbbc1d0 | ||
|
|
3b3065f736 | ||
|
|
0533debeab | ||
|
|
3fb20b49c8 | ||
|
|
4ceea9d6ca | ||
|
|
de775c501c | ||
|
|
b5424e7448 | ||
|
|
973cb76c1c | ||
|
|
bbafb16ea4 | ||
|
|
afc32f02dc | ||
|
|
fbd05aa185 | ||
|
|
e523a6c0be | ||
|
|
59c71b8db4 | ||
|
|
dc67ff6418 | ||
|
|
7ff7e49f56 | ||
|
|
aca2d3a544 | ||
|
|
55df20c845 | ||
|
|
334519167b | ||
|
|
000c5dcd76 | ||
|
|
1f26793fde | ||
|
|
4354fc331c | ||
|
|
70aaa0a55c | ||
|
|
c9998dfb32 | ||
|
|
d15c7f5669 | ||
|
|
af8765cb3b | ||
|
|
3130717626 | ||
|
|
a33542719f | ||
|
|
b3f1152049 | ||
|
|
39fd1176dd | ||
|
|
3c9d9373d2 | ||
|
|
44666bae9a | ||
|
|
eca7fdcc99 | ||
|
|
9c4efa9af0 | ||
|
|
d50825e5c7 | ||
|
|
3888bfd453 | ||
|
|
b8b11a6187 | ||
|
|
873ed01b7d | ||
|
|
9de225ed45 | ||
|
|
f5a056b086 | ||
|
|
327ee894f4 | ||
|
|
7a5fcd460d | ||
|
|
a3eb6afe8d | ||
|
|
71ddadfcfb | ||
|
|
fb9aad1a3e | ||
|
|
d1a53e7d05 | ||
|
|
3bbbeca957 | ||
|
|
454dedf034 | ||
|
|
029469b3d9 | ||
|
|
665d930823 | ||
|
|
4d95024bd6 | ||
|
|
031a315329 | ||
|
|
97725bfac3 | ||
|
|
d7c00869fb | ||
|
|
06eabf2d13 | ||
|
|
393e1b4b98 | ||
|
|
1b3973edbc | ||
|
|
57b1d5880f | ||
|
|
b9beaa8564 | ||
|
|
736e1b30f3 | ||
|
|
76598f1016 | ||
|
|
a3c144d6ca | ||
|
|
05cefc9a4d | ||
|
|
c23e6ff017 | ||
|
|
bf1ff07fd0 | ||
|
|
80a74cca68 | ||
|
|
83e974077f | ||
|
|
59a0665a20 | ||
|
|
df6e3dbda8 | ||
|
|
b59b038a3e | ||
|
|
a25a4d29a8 | ||
|
|
2daad9f89f | ||
|
|
3bf6635ec6 | ||
|
|
cb69d250b0 | ||
|
|
aa94f571e2 | ||
|
|
5ef2b5a442 | ||
|
|
c6fb0871e9 | ||
|
|
626ef6ce4b | ||
|
|
5b2904930b | ||
|
|
a3b690ec58 | ||
|
|
999de04ace | ||
|
|
f0aeeb7732 | ||
|
|
fbed58ff08 | ||
|
|
0d39aa3d88 | ||
|
|
eb8819867b | ||
|
|
870d57445a | ||
|
|
052acd4e38 | ||
|
|
ac38cfe8da | ||
|
|
50ecf3877c | ||
|
|
a4bfd84cc7 | ||
|
|
281dff8956 | ||
|
|
39495ced67 | ||
|
|
962afed9dd | ||
|
|
873c467240 | ||
|
|
2406935a58 | ||
|
|
f6076a4203 | ||
|
|
b995db627b | ||
|
|
b0109b5829 | ||
|
|
d5ba7902a4 | ||
|
|
99af19b6fe | ||
|
|
a1ce57f11f | ||
|
|
8ae97ac91e | ||
|
|
b0507c0235 | ||
|
|
d14801d65b | ||
|
|
e05dc9837b | ||
|
|
59d1b94b65 | ||
|
|
5adaaf7851 | ||
|
|
3be0cfe09c | ||
|
|
c3dfc7ec63 | ||
|
|
a28b79215f | ||
|
|
a58ac85dbc | ||
|
|
3fb7d190bf | ||
|
|
b85bcb8e48 | ||
|
|
ce6cd0000c | ||
|
|
c978717b61 | ||
|
|
29639b98b3 | ||
|
|
ee881cfd67 | ||
|
|
e6887be45c | ||
|
|
f7b4af89e9 | ||
|
|
9fe9cb0939 | ||
|
|
17a05ea939 | ||
|
|
f7285ff405 | ||
|
|
a27d49b6f2 | ||
|
|
3dca8dbf66 | ||
|
|
5c093a7211 | ||
|
|
86fddd5326 | ||
|
|
5365639a36 | ||
|
|
6ce2a12c4d | ||
|
|
81b74decb3 | ||
|
|
fbcd3a77fb | ||
|
|
bad0e58372 | ||
|
|
485b055d48 | ||
|
|
bf3752ed61 | ||
|
|
98b1601fcb | ||
|
|
040cbe00d6 | ||
|
|
c2ffa044f9 | ||
|
|
fc9f0b04be | ||
|
|
b9de670da0 | ||
|
|
ba5489128f | ||
|
|
62ccd05e36 | ||
|
|
b8a340641a | ||
|
|
a186bdba06 | ||
|
|
ea592051c7 | ||
|
|
4923c2e70b | ||
|
|
e64d52740b | ||
|
|
ee2cf436d4 | ||
|
|
113ff2f009 | ||
|
|
51b13fc58c | ||
|
|
ee8a641275 | ||
|
|
0b2b933388 | ||
|
|
bfad782acc | ||
|
|
c0348de3db | ||
|
|
7e1c036fc0 | ||
|
|
faae5b1519 | ||
|
|
a52a63c381 | ||
|
|
525e1cff49 | ||
|
|
52e2ee9272 | ||
|
|
d4d3aee457 | ||
|
|
919868aa0a | ||
|
|
a36e380337 | ||
|
|
5cf14cc14c | ||
|
|
c94e4cff85 | ||
|
|
809e5d78be | ||
|
|
37b349432f | ||
|
|
1761aa0814 | ||
|
|
9e64cce10f | ||
|
|
e7132c1c59 | ||
|
|
3943f5b6b0 | ||
|
|
4c5cf5a8e5 | ||
|
|
675909333d | ||
|
|
4b368ae008 | ||
|
|
86800ed493 | ||
|
|
9cad6dd993 | ||
|
|
644fd891d7 | ||
|
|
0868c16564 | ||
|
|
c672730259 | ||
|
|
176247d3bc | ||
|
|
a6316465a3 | ||
|
|
7f1a348d03 | ||
|
|
f6eb1ed5c5 | ||
|
|
733bae3b3a | ||
|
|
96a72e834a | ||
|
|
978c84ee1e | ||
|
|
27b67c1340 | ||
|
|
eafd46d84e | ||
|
|
9d4a4e29fc | ||
|
|
80b62db04e | ||
|
|
9a8035bad1 | ||
|
|
c2933b91c2 | ||
|
|
fe11b3ffb1 | ||
|
|
8c729fd029 | ||
|
|
6c7b16df3c | ||
|
|
c1806ff994 | ||
|
|
6dcb0b22f2 | ||
|
|
58752d0755 | ||
|
|
6df846dc61 | ||
|
|
647bba1125 | ||
|
|
fd5543cc2d | ||
|
|
d862f87c28 | ||
|
|
e9e12eed66 | ||
|
|
80044dd282 | ||
|
|
6294854990 | ||
|
|
962cc9b033 | ||
|
|
f2a86f34d1 | ||
|
|
23170b82ec | ||
|
|
7cb27c965d | ||
|
|
5c92055aef | ||
|
|
6bfe3fcb43 | ||
|
|
6a717fd44c | ||
|
|
b3e2d5213d | ||
|
|
c29cd046d0 | ||
|
|
aaa7b272aa | ||
|
|
31de40b32a | ||
|
|
b62cc87e84 | ||
|
|
7a7c208c85 | ||
|
|
9970d45367 | ||
|
|
fa6d622031 | ||
|
|
8396d8e626 | ||
|
|
e9dd1731ee | ||
|
|
62f32e5f63 | ||
|
|
e16953b9af | ||
|
|
c413bcc626 | ||
|
|
55b59262b9 | ||
|
|
e7142903ea | ||
|
|
b725de086e | ||
|
|
b3376716f2 | ||
|
|
c9ed5df025 | ||
|
|
84eb4f32e0 | ||
|
|
4de34208ed | ||
|
|
b5fd91972c | ||
|
|
3c1a1a44ae | ||
|
|
f7d235f2d6 | ||
|
|
bc1bc2431d | ||
|
|
e26b3bca4e | ||
|
|
273eb7bd7b | ||
|
|
9005e1b9fe | ||
|
|
527b977587 | ||
|
|
dd49f8fa0d | ||
|
|
61de3a3260 | ||
|
|
63d965753f | ||
|
|
fce67c1fab | ||
|
|
b5756a1b20 | ||
|
|
09a59edd6b | ||
|
|
56014a27d6 | ||
|
|
6ec4ffb2fa | ||
|
|
6c08bf003b | ||
|
|
8f3347d9ab | ||
|
|
b5e01422e1 | ||
|
|
8bf7e76f45 | ||
|
|
d818cb8fe1 | ||
|
|
0ed66a79f1 | ||
|
|
e4fe551924 | ||
|
|
087d11b750 | ||
|
|
fe3e1b56b7 | ||
|
|
9438d70ed9 | ||
|
|
73abaddd9c | ||
|
|
cd85a4dbf2 | ||
|
|
754dbe37cc | ||
|
|
cf867395f8 | ||
|
|
660cf1f449 | ||
|
|
d58394b4e6 | ||
|
|
73bc4092a1 | ||
|
|
eb2928eb0c | ||
|
|
83c0c1fc43 | ||
|
|
b4c15668bd | ||
|
|
01a2da47a6 | ||
|
|
65e1436a23 | ||
|
|
a6ea47df15 | ||
|
|
8a22b87101 | ||
|
|
106dc5d8b7 | ||
|
|
135a228ac1 | ||
|
|
c864c50c9f | ||
|
|
ebd9abb5f6 | ||
|
|
824209178c | ||
|
|
8e2e2cdbac | ||
|
|
64c7faf11b | ||
|
|
a167fb1c2f | ||
|
|
d2d0e7a17d | ||
|
|
f6006ae6ca | ||
|
|
bdf2e9407d | ||
|
|
0d57b59cd3 | ||
|
|
6556edd18e | ||
|
|
49e625e750 | ||
|
|
366612fb82 | ||
|
|
2073b8abfc | ||
|
|
65b9ea4e76 | ||
|
|
9f5bc9c318 | ||
|
|
c62de90430 | ||
|
|
064372d787 | ||
|
|
422a4310f3 | ||
|
|
5372f3fe84 | ||
|
|
b0999db885 | ||
|
|
71a4ff07e3 | ||
|
|
76233f8959 | ||
|
|
653c6ed1e6 | ||
|
|
aadb290cc4 | ||
|
|
6c7522fef8 | ||
|
|
0f5a990141 | ||
|
|
98681ace4a | ||
|
|
6559f4499c | ||
|
|
316077a135 | ||
|
|
77c0950a1b | ||
|
|
a9a9075f5f | ||
|
|
cc9ff9870f | ||
|
|
9489dd05bc | ||
|
|
56d3042efd | ||
|
|
7a7c4df2a1 | ||
|
|
ef7b9830db | ||
|
|
d766a5b71e | ||
|
|
afd290e289 | ||
|
|
1a561ea0c2 | ||
|
|
ddd7ff2d33 | ||
|
|
50a0e17539 | ||
|
|
1a5e255c1b | ||
|
|
1300dc4ef4 | ||
|
|
c57c4fbd1a | ||
|
|
1170373494 | ||
|
|
87b3032139 | ||
|
|
c1077a5ef5 | ||
|
|
5d3ff55b86 | ||
|
|
372396d5b6 | ||
|
|
ad72af9d40 | ||
|
|
d34cfcdfef | ||
|
|
c4a9a3d3a2 | ||
|
|
4d9af08881 | ||
|
|
584ea45837 | ||
|
|
72efcab3e7 | ||
|
|
63704efd59 | ||
|
|
afd73998e6 | ||
|
|
9267771422 | ||
|
|
4faed7a84f | ||
|
|
f9fa557a95 | ||
|
|
f71181d1c1 | ||
|
|
db99fe098d | ||
|
|
91aa8034b1 | ||
|
|
0be8fe8e3f | ||
|
|
376e4b307c | ||
|
|
0d46073bb9 | ||
|
|
81df9b0491 | ||
|
|
3bf04c6034 | ||
|
|
2c06049a2f | ||
|
|
58d7879e1d | ||
|
|
677e627278 | ||
|
|
5471a9ebfe | ||
|
|
4cbfa3ad47 | ||
|
|
17bc1eba3f | ||
|
|
4232700de5 | ||
|
|
3f70ac54a5 | ||
|
|
4c8da979a5 | ||
|
|
bb9f07569c | ||
|
|
92c3800731 | ||
|
|
5b9d5a9086 | ||
|
|
187463d355 | ||
|
|
998200793d | ||
|
|
94d5223880 | ||
|
|
ea22c7c16c | ||
|
|
b18a6b644b | ||
|
|
f73df57a1a | ||
|
|
359258a1b5 | ||
|
|
65014a46b4 | ||
|
|
45586e83da | ||
|
|
9b3b75aa93 | ||
|
|
05f75b83c1 | ||
|
|
089a51f674 | ||
|
|
212ae55cfe | ||
|
|
7ba205ba34 | ||
|
|
355b277c11 | ||
|
|
2870a0a8ad | ||
|
|
cacd5a9a23 | ||
|
|
4b5f782fe4 | ||
|
|
fd8ba559d7 | ||
|
|
97803f5627 | ||
|
|
ed1810de86 | ||
|
|
104561e7aa | ||
|
|
12f66bebb7 | ||
|
|
d00ee5a70b | ||
|
|
b982ff64c2 | ||
|
|
c11d9bee2e | ||
|
|
8814eb3eb6 | ||
|
|
120465d676 | ||
|
|
04cdf0aa4d | ||
|
|
81e443c4cf | ||
|
|
72df261ed0 | ||
|
|
d2eb49ccbc | ||
|
|
14a28b81af | ||
|
|
aa49c05524 | ||
|
|
0903eead06 | ||
|
|
c276577b52 | ||
|
|
5c53570446 | ||
|
|
f1e3b83d26 | ||
|
|
66e23fca79 | ||
|
|
3797d4deb6 | ||
|
|
a49196ee30 | ||
|
|
e9afd53351 | ||
|
|
f84f829957 | ||
|
|
1c724f5355 | ||
|
|
54debca4a3 | ||
|
|
b443d9974a | ||
|
|
1ecd83b0ab | ||
|
|
f55d028ae5 | ||
|
|
565e1c7d2d | ||
|
|
ef4512dd02 | ||
|
|
6fda41900d | ||
|
|
d3a879638d | ||
|
|
66921e8549 | ||
|
|
391ba55b81 | ||
|
|
52320dfaa8 | ||
|
|
4020326f58 | ||
|
|
350e4faf79 | ||
|
|
1f2b299e00 | ||
|
|
a6c8c6c7ef | ||
|
|
3549d8378c | ||
|
|
13bc41facc | ||
|
|
cde82f532c | ||
|
|
274cd419fa | ||
|
|
5db9b7f8c9 | ||
|
|
976cb288c3 | ||
|
|
68b3e5d8e0 | ||
|
|
445547f00a | ||
|
|
9bff7168e8 | ||
|
|
aefadc04c7 | ||
|
|
984d591573 | ||
|
|
cf0ec85c35 | ||
|
|
90d3e0be17 | ||
|
|
48d903e811 | ||
|
|
8aa445dfe2 | ||
|
|
fce755127c | ||
|
|
69ceb95ddc | ||
|
|
b211adaaca | ||
|
|
ec54cdfcf0 | ||
|
|
2471082ced | ||
|
|
dda78a4fc8 | ||
|
|
b47e09534c | ||
|
|
1e83bfb971 | ||
|
|
16209a0936 | ||
|
|
e2c8e98be0 | ||
|
|
31b7812720 | ||
|
|
9b5007aefd | ||
|
|
a9b0e45013 | ||
|
|
1975235fd7 | ||
|
|
e4d7684246 | ||
|
|
e982905eb4 | ||
|
|
0b329018ee | ||
|
|
86c9a43b08 | ||
|
|
7e00668181 | ||
|
|
0113226936 | ||
|
|
beceb88cd7 | ||
|
|
a5c9d9520f | ||
|
|
e0f09f609f | ||
|
|
de3acd9017 | ||
|
|
b2072dd3be | ||
|
|
9da7af46c3 | ||
|
|
076c2bca3b | ||
|
|
7456711eaa | ||
|
|
047e04ed3e | ||
|
|
47d199297a | ||
|
|
2533bbdc0b | ||
|
|
f7447d2e0d | ||
|
|
5069b693a1 | ||
|
|
13bd14747a | ||
|
|
2fdd8434df | ||
|
|
31534438bc | ||
|
|
0bb0077358 | ||
|
|
47d888364d | ||
|
|
e081bde064 | ||
|
|
bd413de842 | ||
|
|
3c3611af6f | ||
|
|
1d6badb1f1 | ||
|
|
41290bb1a8 | ||
|
|
7e7224196a | ||
|
|
598764b860 | ||
|
|
fb338b90bf | ||
|
|
955eeed31a | ||
|
|
e84ea6082c | ||
|
|
e30fcb6da6 | ||
|
|
203c6218e4 | ||
|
|
f7678abe8d | ||
|
|
e71a1620b0 | ||
|
|
1039db7bf8 | ||
|
|
f309266422 | ||
|
|
62a85ae737 | ||
|
|
8ef798ea51 | ||
|
|
fcda24be29 | ||
|
|
9e048d8d77 | ||
|
|
857dc8be5a | ||
|
|
1e32a1e5e9 | ||
|
|
17e9aabd25 | ||
|
|
95dd1d8449 | ||
|
|
4b45499b97 | ||
|
|
2c57a35055 | ||
|
|
6f495dea04 | ||
|
|
74e7a62e91 | ||
|
|
941806698e | ||
|
|
9886944f32 | ||
|
|
65b9b1cd25 | ||
|
|
839b7654db | ||
|
|
fc48ecaa1d | ||
|
|
e40f405b97 | ||
|
|
a98ab483cb | ||
|
|
69e8be6dc1 | ||
|
|
8a3f25311b | ||
|
|
3ba7d88cea | ||
|
|
43a2e1003e | ||
|
|
5399faaa9d | ||
|
|
9c6e772497 | ||
|
|
3cdb95a602 | ||
|
|
b68a588ede | ||
|
|
9ee56da6b0 | ||
|
|
4beb80c290 | ||
|
|
4aac4d5b9e | ||
|
|
7586ae7dbe | ||
|
|
88b6342bb5 | ||
|
|
7b21ed5f93 | ||
|
|
ce1f31af8d | ||
|
|
3c73b36cca | ||
|
|
7d31c65af1 | ||
|
|
47e0a163f3 | ||
|
|
c63a8d6705 | ||
|
|
33b574198c | ||
|
|
024fd873ec | ||
|
|
2bd45eeb6f | ||
|
|
391be66361 | ||
|
|
2d2e9d840c | ||
|
|
0e347391e8 | ||
|
|
716be2bb22 | ||
|
|
0bdf616836 | ||
|
|
22301bd3d5 | ||
|
|
b1eb37b394 | ||
|
|
af1c4a3e7f | ||
|
|
1d618bf232 | ||
|
|
4f88c4eb09 | ||
|
|
29f31b3457 | ||
|
|
de3abdb556 | ||
|
|
ed04e1060a | ||
|
|
9c82e9304b | ||
|
|
d9207c924e | ||
|
|
3e10389106 |
No files matched your search
@@ -0,0 +1,16 @@
|
||||
;;; Directory Local Variables
|
||||
;;; See Info node `(emacs) Directory Variables' for more information.
|
||||
|
||||
(
|
||||
(c-mode . ((standard-indent . 3)
|
||||
(c-basic-offset . 3)
|
||||
(c-file-offsets . ((arglist-intro . ++)
|
||||
(arglist-cont-nonempty . ++)
|
||||
(block-close . 0)
|
||||
(block-open . 0)))
|
||||
(eval . (setq-local c-cleanup-list
|
||||
(cl-set-difference c-cleanup-list
|
||||
'(brace-else-brace
|
||||
brace-elseif-brace))))))
|
||||
(objc-mode . ((c-basic-offset . 3)))
|
||||
)
|
||||
@@ -42,7 +42,7 @@ body:
|
||||
attributes:
|
||||
label: Version/Commit
|
||||
description: You can find this information under Information/System Information
|
||||
placeholder: 1.19.1 (Git 0792144fe3)
|
||||
placeholder: 1.20.0 (Git ab3b175)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -56,8 +56,8 @@ body:
|
||||
- type: dropdown
|
||||
id: nigthly
|
||||
attributes:
|
||||
label: Check in the nightly version
|
||||
description: This issue is reproducible with [nightly builds](https://buildbot.libretro.com/nightly/)?
|
||||
label: Present in the nightly version
|
||||
description: Is the issue reproducible with current [nightly builds](https://buildbot.libretro.com/nightly/)?
|
||||
options:
|
||||
- I don't know
|
||||
- Yes, this is reproduced in the nightly build
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.ctr -j$(getconf _NPROCESSORS_ONLN) USE_CTRULIB_2=1 clean
|
||||
make -f Makefile.ctr -j$(getconf _NPROCESSORS_ONLN) USE_CTRULIB_2=1 HAVE_STATIC_DUMMY=1
|
||||
make -f Makefile.ctr -j$(getconf _NPROCESSORS_ONLN) USE_CTRULIB_2=1 HAVE_STATIC_DUMMY=1 info all
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: retroarch-android-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -25,13 +25,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.dos -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.dos -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1
|
||||
make -f Makefile.dos -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-DOS-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1
|
||||
make -f Makefile.ngc -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1 info all
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -j$(getconf _NPROCESSORS_ONLN)
|
||||
make -j$(getconf _NPROCESSORS_ONLN) info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
name: CI Windows (MSYS2)
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
repository_dispatch:
|
||||
types: [run_build]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
msys2-build-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
sys: [MINGW64, UCRT64,CLANG64]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: ${{ matrix.sys }}
|
||||
update: true
|
||||
install: base-devel git
|
||||
pacboy: >-
|
||||
gettext:p
|
||||
gobject-introspection:p
|
||||
graphite2:p
|
||||
p11-kit:p
|
||||
qt6:p
|
||||
qt6-3d:p
|
||||
qt6-charts:p
|
||||
qt6-datavis3d:p
|
||||
qt6-imageformats:p
|
||||
qt6-location:p
|
||||
qt6-lottie:p
|
||||
qt6-networkauth:p
|
||||
qt6-quick3dphysics:p
|
||||
qt6-quicktimeline:p
|
||||
qt6-remoteobjects:p
|
||||
qt6-scxml:p
|
||||
qt6-sensors:p
|
||||
qt6-serialbus:p
|
||||
qt6-speech:p
|
||||
qt6-tools:p
|
||||
qt6-translations:p
|
||||
qt6-virtualkeyboard:p
|
||||
qt6-webchannel:p
|
||||
qt6-websockets:p
|
||||
x264:p
|
||||
cc:p
|
||||
|
||||
- name: Configure and build RetroArch
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
echo "Building RetroArch in ${{ matrix.sys }} environment"
|
||||
./configure
|
||||
make -j$(nproc) info all
|
||||
|
||||
- name: Collect DLLs and binaries
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
echo "Collecting DLLs and binaries"
|
||||
mkdir -p dist
|
||||
cp retroarch.exe dist/
|
||||
ldd retroarch.exe|grep $MINGW_PREFIX |awk '{print $3}'|xargs -I {} cp {} dist/
|
||||
|
||||
- name: Archive build artifacts
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: retroarch-${{ matrix.sys }}
|
||||
path: dist/
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
id: slug
|
||||
run: echo "sha8=$(echo ${GITHUB_SHA} | cut -c1-8)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RetroArch-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -25,13 +25,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.miyoo clean
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.miyoo
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.miyoo info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: retroarch_miyoo_arm32${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -30,13 +30,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.ps2 -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.ps2 -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 release
|
||||
make -f Makefile.ps2 -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info release
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-PS2-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
name: CI PS3/PSL1GHT
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
repository_dispatch:
|
||||
types: [run_build]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: git.libretro.com:5050/libretro-infrastructure/libretro-build-psl1ght:latest
|
||||
options: --user root
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Compile Salamander
|
||||
run: |
|
||||
make -f Makefile.psl1ght.salamander -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.psl1ght.salamander -j$(getconf _NPROCESSORS_ONLN)
|
||||
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.psl1ght -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.psl1ght -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-psl1ght-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
retroarch_psl1ght_salamander.elf
|
||||
retroarch_psl1ght.elf
|
||||
@@ -31,13 +31,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
export PATH=~/cli:$PATH # .net cli
|
||||
make -f Makefile.orbis -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1
|
||||
make -f Makefile.orbis -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: bin-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-PSP-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -30,12 +30,12 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.vita -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.vita -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 HAVE_VITAGLES=1
|
||||
make -f Makefile.vita -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 HAVE_VITAGLES=1 info all
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-PSVita-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -25,13 +25,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.rs90 clean
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.rs90
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.rs90 info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: retroarch_rs90_mips32${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -25,13 +25,13 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.retrofw clean
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.retrofw
|
||||
make -j$(getconf _NPROCESSORS_ONLN) -f Makefile.retrofw info all
|
||||
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: retroarch_retrofw_mips32${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RA-libnx-dummy-${{ steps.slug.outputs.sha8 }}
|
||||
path: |
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1
|
||||
make -f Makefile.wii -j$(getconf _NPROCESSORS_ONLN) EXTERNAL_LIBOGC=1 GX_PTHREAD_LEGACY=0 HAVE_STATIC_DUMMY=1 info all
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
|
||||
@@ -25,12 +25,12 @@ jobs:
|
||||
- name: Compile Salamander
|
||||
run: |
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 clean
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1 V=1
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) SALAMANDER_BUILD=1
|
||||
|
||||
- name: Compile RA
|
||||
run: |
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) clean
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 V=1
|
||||
make -f Makefile.wiiu -j$(getconf _NPROCESSORS_ONLN) HAVE_STATIC_DUMMY=1 info all
|
||||
- name: Get short SHA
|
||||
id: slug
|
||||
run: echo "::set-output name=sha8::$(echo ${GITHUB_SHA} | cut -c1-8)"
|
||||
@@ -33,4 +33,4 @@ jobs:
|
||||
- name: Build Debug
|
||||
run: |
|
||||
make clean # making sure we don't have leftovers from previous build
|
||||
make DEBUG=1 GL_DEBUG=1 C89_BUILD=1
|
||||
make DEBUG=1 GL_DEBUG=1 C89_BUILD=1 info all
|
||||
@@ -2,14 +2,18 @@ name: CI webOS
|
||||
|
||||
on:
|
||||
push:
|
||||
tags-ignore:
|
||||
- '*'
|
||||
branches:
|
||||
- '*'
|
||||
pull_request:
|
||||
release:
|
||||
types: [ published ]
|
||||
repository_dispatch:
|
||||
types: [run_build]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
types: [ run_build ]
|
||||
|
||||
env:
|
||||
PACKAGE_NAME: com.retroarch.webos
|
||||
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
|
||||
|
||||
jobs:
|
||||
@@ -28,6 +32,14 @@ jobs:
|
||||
fileName: "ares-package_*.deb"
|
||||
out-file-path: "temp"
|
||||
|
||||
- name: Download Manifest Generator
|
||||
uses: robinraju/[email protected]
|
||||
with:
|
||||
repository: "webosbrew/dev-toolbox-cli"
|
||||
latest: true
|
||||
fileName: "webosbrew-toolbox-gen-manifest_*.deb"
|
||||
out-file-path: "temp"
|
||||
|
||||
- name: Update packages
|
||||
run: sudo apt-get -yq update
|
||||
|
||||
@@ -39,17 +51,75 @@ jobs:
|
||||
with:
|
||||
repository: "openlgtv/buildroot-nc4"
|
||||
latest: true
|
||||
fileName: "arm-webos-linux-gnueabi_sdk-buildroot.tar.gz"
|
||||
fileName: "arm-webos-linux-gnueabi_sdk-buildroot-x86_64.tar.gz"
|
||||
out-file-path: "/tmp"
|
||||
|
||||
- name: Extract webOS NDK
|
||||
shell: bash
|
||||
working-directory: /tmp
|
||||
run: |
|
||||
tar xzf arm-webos-linux-gnueabi_sdk-buildroot.tar.gz
|
||||
tar xzf arm-webos-linux-gnueabi_sdk-buildroot-x86_64.tar.gz
|
||||
./arm-webos-linux-gnueabi_sdk-buildroot/relocate-sdk.sh
|
||||
|
||||
- name: Compile RA
|
||||
- name: Load RARCH_VERSION from version.all
|
||||
id: version
|
||||
shell: bash
|
||||
run: |
|
||||
RARCH_VERSION=$(grep -Po '(?<=#define PACKAGE_VERSION ")[^"]+' version.all)
|
||||
echo "RARCH_VERSION=$RARCH_VERSION" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Compile RA (GLES3 variant)
|
||||
shell: bash
|
||||
run: |
|
||||
. /tmp/arm-webos-linux-gnueabi_sdk-buildroot/environment-setup
|
||||
make -f Makefile.webos ADD_SDL2_LIB=1 -j$(getconf _NPROCESSORS_ONLN)
|
||||
make -f Makefile.webos clean
|
||||
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} ADD_SDL2_LIB=1 \
|
||||
HAVE_OPENGLES3=1 HAVE_OPENGLES3_1=1 HAVE_OPENGLES3_2=1 -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
mv webos/com.retroarch.webos_${RARCH_VERSION}_arm.ipk \
|
||||
webos/com.retroarch.webos.gles3_${RARCH_VERSION}_arm.ipk
|
||||
env:
|
||||
DEBUG: ${{ github.event_name == 'release' && '0' || '1' }}
|
||||
|
||||
- name: Upload GLES3 artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: com.retroarch.webos.gles3_${{ env.RARCH_VERSION }}_${{ github.sha }}_arm.ipk
|
||||
path: webos/com.retroarch.webos.gles3_${{ env.RARCH_VERSION }}_arm.ipk
|
||||
|
||||
- name: Compile RA (default)
|
||||
shell: bash
|
||||
run: |
|
||||
. /tmp/arm-webos-linux-gnueabi_sdk-buildroot/environment-setup
|
||||
make -f Makefile.webos ipk PACKAGE_NAME=${PACKAGE_NAME} ADD_SDL2_LIB=1 -j"$(getconf _NPROCESSORS_ONLN)"
|
||||
env:
|
||||
DEBUG: ${{ github.event_name == 'release' && '0' || '1' }}
|
||||
|
||||
- name: Upload default artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: com.retroarch.webos_${{ env.RARCH_VERSION }}_${{ github.sha }}_arm.ipk
|
||||
path: webos/com.retroarch.webos_${{ env.RARCH_VERSION }}_arm.ipk
|
||||
|
||||
- name: Generate Manifest (default only)
|
||||
if: github.repository == 'webosbrew/Retroarch'
|
||||
shell: bash
|
||||
run: |
|
||||
webosbrew-gen-manifest -o webos/${PACKAGE_NAME}.manifest.json \
|
||||
-p webos/${PACKAGE_NAME}_${RARCH_VERSION}_arm.ipk \
|
||||
-i https://github.com/webosbrew/RetroArch/raw/webos/webos/icon160.png \
|
||||
-l https://github.com/webosbrew/RetroArch
|
||||
|
||||
- name: Release
|
||||
if: github.event_name == 'release' && github.repository == 'webosbrew/Retroarch'
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: ${{ github.event.release.tag_name }}
|
||||
allowUpdates: true
|
||||
omitNameDuringUpdate: true
|
||||
omitBody: true
|
||||
omitPrereleaseDuringUpdate: true
|
||||
artifacts: |
|
||||
webos/com.retroarch.webos_${{ env.RARCH_VERSION }}_arm.ipk
|
||||
webos/com.retroarch.webos.gles3_${{ env.RARCH_VERSION }}_arm.ipk
|
||||
webos/${{ env.PACKAGE_NAME }}.manifest.json
|
||||
+19
-1
@@ -148,7 +148,6 @@ wiiu/wut/elf2rpl/elf2rpl
|
||||
/pkg/android/phoenix/bin/
|
||||
/pkg/android/phoenix/gen/
|
||||
/pkg/android/phoenix/local.properties
|
||||
/pkg/android/phoenix/gradle.properties
|
||||
/pkg/android/phoenix/.gradle
|
||||
/pkg/android/phoenix/.externalNativeBuild
|
||||
/pkg/android/phoenix/build
|
||||
@@ -196,6 +195,8 @@ retroarch.js
|
||||
retroarch.js.mem
|
||||
*.bc
|
||||
*.wasm
|
||||
*.wasm.map
|
||||
obj-emscripten/
|
||||
|
||||
# only ignore .js files in the repo root
|
||||
/*.js
|
||||
@@ -239,6 +240,8 @@ gfx/common/wayland/content-type-v1.h
|
||||
gfx/common/wayland/content-type-v1.c
|
||||
gfx/common/wayland/single-pixel-buffer-v1.h
|
||||
gfx/common/wayland/single-pixel-buffer-v1.c
|
||||
gfx/common/wayland/xdg-toplevel-icon-v1.h
|
||||
gfx/common/wayland/xdg-toplevel-icon-v1.c
|
||||
|
||||
# libretro-common samples
|
||||
libretro-common/samples/streams/rzip/rzip
|
||||
@@ -260,3 +263,18 @@ param.sfo
|
||||
|
||||
# Clazy
|
||||
*.clazy.yaml
|
||||
|
||||
# PSL1GHT
|
||||
*.SELF
|
||||
EBOOT.BIN
|
||||
pkg/psl1ght/*.pkg
|
||||
modern_alpha_blend_fpo.h
|
||||
modern_alpha_blend_vpo.h
|
||||
modern_opaque_fpo.h
|
||||
modern_opaque_vpo.h
|
||||
gfx/drivers/rsx_shaders/modern_alpha_blend.fpo
|
||||
gfx/drivers/rsx_shaders/modern_alpha_blend.vpo
|
||||
gfx/drivers/rsx_shaders/modern_opaque.fpo
|
||||
gfx/drivers/rsx_shaders/modern_opaque.vpo
|
||||
pkg/psl1ght/pkg/USRDIR/shaders_cg/
|
||||
!pkg/psl1ght/pkg/USRDIR/system/
|
||||
+5
-3
@@ -331,7 +331,7 @@ build-retroarch-linux-i686:
|
||||
.build-retroarch-macos-xcode:
|
||||
# Metal/Universal x86_64 arm64 is default
|
||||
tags:
|
||||
- macosx-packaging
|
||||
- mac-apple-silicon
|
||||
stage: build
|
||||
variables:
|
||||
XCARCHIVE_PATH: pkg/apple/build/RetroArchUniversal
|
||||
@@ -358,6 +358,8 @@ build-retroarch-osx-universal-metal:
|
||||
|
||||
build-retroarch-osx-opengl-x64:
|
||||
extends: .build-retroarch-macos-xcode
|
||||
tags:
|
||||
- macosx-packaging
|
||||
variables:
|
||||
XCARCHIVE_PATH: pkg/apple/build/RetroArchOpenGL
|
||||
XCPROJECT_NAME: RetroArch
|
||||
@@ -388,8 +390,6 @@ build-retroarch-osx-opengl-x64:
|
||||
|
||||
build-retroarch-ios-arm64:
|
||||
extends: .build-retroarch-macos-xcode
|
||||
tags:
|
||||
- mac-apple-silicon
|
||||
variables:
|
||||
XCPROJECT_NAME: RetroArch_iOS13
|
||||
XCCONFIG: GitLabCI.xcconfig
|
||||
@@ -408,6 +408,8 @@ build-retroarch-ios-arm64:
|
||||
|
||||
build-retroarch-ios9:
|
||||
extends: .build-retroarch-macos-xcode
|
||||
tags:
|
||||
- macosx-packaging
|
||||
variables:
|
||||
XCPROJECT_NAME: RetroArch_iOS9
|
||||
XCCONFIG: GitLabCI.xcconfig
|
||||
|
||||
Vendored
-191
@@ -1,191 +0,0 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Mac",
|
||||
"includePath": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceRoot}/libretro-common/include"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"macFrameworkPath": [
|
||||
"/System/Library/Frameworks",
|
||||
"/Library/Frameworks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceFolder}/libretro-common/include",
|
||||
"${workspaceRoot}/libretro-common/include"
|
||||
],
|
||||
"defines": [],
|
||||
"intelliSenseMode": "clang-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"/usr/include",
|
||||
"/usr/local/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Win32",
|
||||
"includePath": [
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
|
||||
"${workspaceRoot}",
|
||||
"${workspaceFolder}/libretro-common/include"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/ucrt",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/shared",
|
||||
"C:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/winrt",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
},
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++17",
|
||||
"configurationProvider": "ms-vscode.makefile-tools"
|
||||
},
|
||||
{
|
||||
"name": "msys2-mingw32",
|
||||
"includePath": [
|
||||
"C:/msys64/mingw32/include",
|
||||
"C:/msys64/mingw32/i686-w64-mingw32/include",
|
||||
"${workspaceRoot}/libretro-common/include",
|
||||
"${workspaceRoot}/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/msys64/mingw32/include",
|
||||
"C:/msys64/mingw32/i686-w64-mingw32/include",
|
||||
"${workspaceRoot}/libretro-common/include",
|
||||
"${workspaceRoot}/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "msys2-mingw64",
|
||||
"includePath": [
|
||||
"C:/msys64/mingw64/include",
|
||||
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
|
||||
"${workspaceRoot}/libretro-common/include",
|
||||
"${workspaceRoot}/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
"path": [
|
||||
"C:/msys64/mingw64/include",
|
||||
"C:/msys64/mingw64/x86_64-w64-mingw32/include",
|
||||
"${workspaceRoot}/libretro-common/include",
|
||||
"${workspaceRoot}/include",
|
||||
"${workspaceRoot}"
|
||||
],
|
||||
"limitSymbolsToIncludedHeaders": true,
|
||||
"databaseFilename": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Switch",
|
||||
"includePath": [
|
||||
"/opt/devkitpro/devkitA64/aarch64-none-elf/include",
|
||||
"/opt/devkitpro/devkitA64/lib/gcc/aarch64-none-elf/8.3.0/include",
|
||||
"/opt/devkitpro/libnx/include",
|
||||
"/opt/devkitpro/portlibs/switch/include",
|
||||
"/opt/devkitpro/portlibs/switch/include/freetype2",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"__aarch64__",
|
||||
"__SWITCH__",
|
||||
"HAVE_LIBNX"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.17763.0",
|
||||
"compilerPath": "/opt/devkitpro/devkitA64/bin/aarch64-none-elf-gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"intelliSenseMode": "gcc-x64"
|
||||
},
|
||||
{
|
||||
"name": "WiiU",
|
||||
"includePath": [
|
||||
"/opt/devkitpro/devkitPPC/powerpc-eabi/include",
|
||||
"/opt/devkitpro/devkitPPC/lib/gcc/powerpc-eabi/6.3.0/include",
|
||||
"/opt/devkitpro/portlibs/ppc/include",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"WIIU",
|
||||
"WIIU_HID"
|
||||
],
|
||||
"windowsSdkVersion": "10.0.17763.0",
|
||||
"compilerPath": "/opt/devkitpro/devkitPPC/bin/powerpc-eabi-gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"intelliSenseMode": "gcc-x64"
|
||||
},
|
||||
{
|
||||
"name": "ps2sdk-ee",
|
||||
"includePath": [
|
||||
"${env:PS2DEV}/ps2sdk/common/include",
|
||||
"${env:PS2DEV}/ps2sdk/ee/include",
|
||||
"${env:PS2DEV}/gsKit/include",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [
|
||||
"PS2",
|
||||
"_EE"
|
||||
],
|
||||
"compilerPath": "${env:PS2DEV}/ee/bin/mips64r5900el-ps2-elf-gcc",
|
||||
"cStandard": "c11",
|
||||
"cppStandard": "c++11",
|
||||
"intelliSenseMode": "gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
Vendored
-70
@@ -1,70 +0,0 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/retroarch.exe",
|
||||
"args": ["-v"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": true,
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "c:\\msys64\\mingw64\\bin\\gdb.exe",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "(gdb) Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${workspaceFolder}/retroarch.exe",
|
||||
"processId": "${command:pickProcess}",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "c:\\msys64\\mingw64\\bin\\gdb.exe",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PSP-GDB Debugger",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/retroarchpsp.elf",
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"setupCommands": [
|
||||
{
|
||||
"text": "symbol-file ${workspaceFolder}/retroarchpsp.elf",
|
||||
"description": "read symbols for elf file",
|
||||
"ignoreFailures": true
|
||||
},
|
||||
{
|
||||
"description": "Enable all-exceptions",
|
||||
"text": "-exec \"catch throw\"",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"showDisplayString": true,
|
||||
"targetArchitecture": "mips",
|
||||
"MIMode": "gdb",
|
||||
"miDebuggerPath": "/usr/local/pspdev/bin/psp-gdb",
|
||||
"miDebuggerServerAddress": "127.0.0.1:10001",
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
-43
@@ -1,43 +0,0 @@
|
||||
{
|
||||
/*"terminal.integrated.shell.windows": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"terminal.integrated.env.windows": {
|
||||
"PATH": "/mingw64/lib/ccache/bin:/mingw64/lib/ccache/bin:/mingw64/lib/ccache/bin:/mingw64/bin:/usr/local/bin:/usr/bin:/bin:$PATH",
|
||||
"MSYSTEM": "MINGW64",
|
||||
},*/
|
||||
"terminal.integrated.cursorBlinking": true,
|
||||
"editor.tabSize": 3,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.renderWhitespace": "all",
|
||||
"editor.insertSpaces": true,
|
||||
"editor.formatOnSave": false,
|
||||
"editor.ruler": [80],
|
||||
"files.associations": {
|
||||
"*.h": "c",
|
||||
"*.in": "c",
|
||||
"*.rh": "c",
|
||||
"array": "c",
|
||||
"iosfwd": "c",
|
||||
"xlocbuf": "c",
|
||||
"xmemory0": "c",
|
||||
"ios": "c",
|
||||
"list": "c",
|
||||
"unordered_map": "c",
|
||||
"unordered_set": "c",
|
||||
"sstream": "cpp",
|
||||
"hash_map": "c",
|
||||
"hash_set": "c",
|
||||
"initializer_list": "c",
|
||||
"string_view": "c",
|
||||
"utility": "c",
|
||||
"thread": "c",
|
||||
"xlocale": "c",
|
||||
"deque": "c",
|
||||
"vector": "c",
|
||||
"xhash": "c",
|
||||
"xiosbase": "c",
|
||||
"xstring": "c",
|
||||
"xtree": "c",
|
||||
"xutility": "c"
|
||||
},
|
||||
"C_Cpp.dimInactiveRegions": false,
|
||||
}
|
||||
Vendored
-128
@@ -1,128 +0,0 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "linux clean build",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "make clean && ./configure && make -j12"
|
||||
},
|
||||
{
|
||||
"label": "linux clean",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "make clean"
|
||||
},
|
||||
{
|
||||
"label": "linux build with debug symbols",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "DEBUG=1 make -j12"
|
||||
},
|
||||
{
|
||||
"label": "linux build",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "make -j12"
|
||||
},
|
||||
{
|
||||
"label": "linux build and run",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "make -j12 && ./retroarch -v"
|
||||
},
|
||||
{
|
||||
"label": "linux build and run with debug symbols",
|
||||
"type": "shell",
|
||||
"group": "build",
|
||||
"command": "DEBUG=1 make -j12 && ./retroarch -v"
|
||||
},
|
||||
{
|
||||
"label": "msys2-mingw64 build",
|
||||
"type": "shell",
|
||||
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
|
||||
"command": "./configure; make -j2",
|
||||
"options": {
|
||||
"shell": {
|
||||
"executable": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "msys2-mingw64 build with debug symbols",
|
||||
"type": "shell",
|
||||
|
||||
"group": "build",
|
||||
|
||||
"command": "./configure; DEBUG=1 make -j2",
|
||||
"options": {
|
||||
"shell": {
|
||||
"executable": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "msys2-mingw64 rebuild",
|
||||
"type": "shell",
|
||||
|
||||
"group": "build",
|
||||
|
||||
"command": "make -j2",
|
||||
"options": {
|
||||
"shell": {
|
||||
"executable": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "msys2-mingw64 clean",
|
||||
"type": "shell",
|
||||
|
||||
"group": "build",
|
||||
|
||||
"command": "make clean",
|
||||
"options": {
|
||||
"shell": {
|
||||
"executable": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "msys2-mingw64 run",
|
||||
"type": "shell",
|
||||
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true },
|
||||
|
||||
"command": "./retroarch -v",
|
||||
"options": {
|
||||
"shell": {
|
||||
"executable": "C:\\msys64\\usr\\bin\\bash.exe",
|
||||
"args": [
|
||||
"-c"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -315,7 +315,7 @@ Mike Swanson (chungy)
|
||||
mikeOSX
|
||||
minucce
|
||||
misson20000
|
||||
Mohmoud (esoptron) (Hedonium)
|
||||
esoptron
|
||||
Monroe88
|
||||
Morgane (MorganeAD)
|
||||
mprobinson
|
||||
|
||||
+255
-1
@@ -1,5 +1,258 @@
|
||||
# Future
|
||||
|
||||
# 1.22.1
|
||||
- ANDROID: OnNewIntent handler to allow launchers start new content without closing first
|
||||
- ANDROID: Use app-specific storage for Google Play builds of RetroArch
|
||||
- ANDROID: Implement support for the Storage Access Framework, to allow the user to mount most directories1 from internal storage, the SD card, other removable storage devices and any document providers provided by other Android apps on the current device.
|
||||
- 3DS: Add 800px mode for New 3DS models
|
||||
- APPLE: Include sameduck, gearcoleco, geargrafx cores in App Store builds
|
||||
- APPLE: Include reminiscence, virtualjaguar, vitaquake2 cores in App Store builds
|
||||
- APPLE: Include gam4980 core in App Store builds
|
||||
- APPLE: Bundle identifier added to Information menu
|
||||
- APPLE: Option to control the usage of Metal argument buffers
|
||||
- APPLE: Don't force fullscreen, allow multitasking on iPad
|
||||
- APPLE: AppIntents for Siri, Shortcuts
|
||||
- APPLE: Fix ffmpeg camera driver
|
||||
- APPLE/MFI: Try harder to own the home button
|
||||
- AUDIO: Microphone CoreAudio driver for iOS and macOS
|
||||
- AUTOCONF: Autoconfig match extended with a physical identifier
|
||||
- CAMERA: Use ffmpeg libavfilter virtual input device as default
|
||||
- CHEEVOS: Show additional message for unsupported achievements
|
||||
- CHEEVOS: Upgrade to rcheevos 12.1
|
||||
- CHEEVOS: Change expired token message from info to error
|
||||
- CHEEVOS: Hashing of RVZ files is now supported
|
||||
- CLOUDSYNC: Enable icloud_drive cloud sync backend on MacOS / iOS
|
||||
- CLOUDSYNC: Don't always trust the server hash
|
||||
- CLOUDSYNC: Enable WebDAV support for Android
|
||||
- CLOUDSYNC: Speed up cloudsync on Apple
|
||||
- DATABASE: Improve multidisk game scanning
|
||||
- DATABASE: Filter in Database Manager now works for genre and region
|
||||
- EMSCRIPTEN: Support core switching
|
||||
- EMSCRIPTEN: Support suspend screensaver
|
||||
- EMSCRIPTEN/RWEBCAM: Fix camera driver
|
||||
- EMSCRIPTEN/RWEBINPUT: Add accelerometer/gyroscope support
|
||||
- EMSCRIPTEN/RWEBPAD: Add rumble support
|
||||
- EMSCRIPTEN/RWEBAUDIO: Rewrite driver, set as default audio driver
|
||||
- INPUT: Default key and mouse binds for lightgun Start and Select buttons
|
||||
- INPUT: Turbo mode corrections
|
||||
- INPUT: Turbo fire settings are now saved to remaps, not to overrides
|
||||
- INPUT: Fix menu usage when OK/Cancel has mouse binds
|
||||
- INPUT: Ignore menu mouse startup position before moving
|
||||
- INPUT: Fix heavy slowdown when using Bluetooth XInput controllers with rumble
|
||||
- INPUT: Reset and close content hotkeys now require confirmation, similar to quit
|
||||
- INPUT: Menu toggle and hotkey enable can now be assigned to the same key
|
||||
- INPUT: Option to have hotkeys follow the port mapped first to the core
|
||||
- INPUT/ANDROID: Favor mouse coordinates for lightgun
|
||||
- INPUT/UDEV: Fix lost terminal settings after restart from menu
|
||||
- INPUT/BSV/REPLAY: Bumped replay format version to 2. Old replays will still play back fine.
|
||||
- INPUT/BSV/REPLAY: Add option to skip deserializing checkpoints from replay files (it introduces jank in some emulators).
|
||||
- INPUT/BSV/REPLAY: Add checkpoint and initial savestate compression, following the `savestate_file_compression` config boolean. Use zstd if available, or fall back to zlib.
|
||||
- INPUT/BSV/REPLAY: Add incremental checkpoints based on statestreams (depending on `HAVE_STATESTREAM` compile time flag). As an example, 60 `pcsx_rearmed` savestates would take 267MB uncompressed; with incremental encoding this is reduced to 77MB. Compressing the result can reduce the size to just 4MB.
|
||||
- INPUT/BSV/REPLAY: Checkpoint compression and encoding can be combined. For example, 60 `pcsx_rearmed` checkpoints can take up just 15MB if each state is incremental and compressed. This is not as optimal as using incremental states without save state compression followed by offline compression, but is a good compromise in many use cases.
|
||||
- INPUT/BSV/REPLAY: Add hotkeys and text commands to force a checkpoint insertion into the currently recording replay, and to seek backwards to the previous checkpoint and forwards to the next checkpoint.
|
||||
- INPUT/BSV/REPLAY: Add a text command to seek to a specific frame of the currently playing/recording replay; it will return via the command replier the actual seeked-to frame (right now it only supports seeking to checkpoints).
|
||||
- INTL: Add Irish Gaelic to selectable languages
|
||||
- IOS: Use native keyboard in search
|
||||
- IOS: Fix crash on iOS9 when fetching refresh rate
|
||||
- IOS: Stronger haptics, controllable by setting
|
||||
- IOS: Down arrow menu is removed, all 3 options are available by other means now
|
||||
- IOS/MACOS: Fix display server resolution and refresh rates
|
||||
- IOS/TVOS: Use native keyboard
|
||||
- JPEG: Fix clamping bug in JPEG decode
|
||||
- LIBRETRO: Deprecate intfstream_open_writable_memory
|
||||
- LIBRETRO: New environment function RETRO_ENVIRONMENT_GET_TARGET_SAMPLE_RATE
|
||||
- LINUX: Add full complement of key/value pairs to desktop entry
|
||||
- MACOS: Fix coreaudio microphone handling
|
||||
- MACOS: Fix window size calculation
|
||||
- MENU: Common Thumbnail Background option for all menu drivers
|
||||
- MENU: Move core options reset from Settings/Configuration to Main Menu / Configuration Files
|
||||
- MENU: Use right analog stick for thumbnail cycling in playlists
|
||||
- MENU: Option to always suggest cores, even when a core is already loaded
|
||||
- MENU: Option to show Favorites before History
|
||||
- MENU: Media history playlists are now visible in playlist manager
|
||||
- MENU: Import Content visibility defaults reverted
|
||||
- MENU: Update CRTSwitchRes menu options for future use
|
||||
- MENU: Debug builds are indicated in Information menu
|
||||
- MENU: Save As / Save Main options for configuration file
|
||||
- MENU: Unwanted input is prevented when menu is triggered by toggle combo
|
||||
- MENU: 32-bit values in cheats and rumble are not presented as huge lists
|
||||
- MENU: Less important widgets are now sized like task notifications
|
||||
- MENU: Play count is added to runtime log
|
||||
- MENU: Configurable startup page (several options beside default Main Menu)
|
||||
- MENU: Shader menu rework, combined save/remove menus, save current, Y and Start hotkeys for shader parameters and background opacity toggle
|
||||
- MENU: Single-click start option from playlists and Explore view
|
||||
- MENU: Allow kiosk mode and hiding of Settings menu also in GLUI and RGUI
|
||||
- MENU: Task widget improvements
|
||||
- MENU/GLUI: Show thumbnails in Explore view
|
||||
- MENU/XMB: Improvements for mobile/touch. More natural horizontal/vertical scrolling
|
||||
- MENU/XMB: Select button toggles thumbnails in playlists
|
||||
- MENU/XMB,OZONE: Fix content icons when playlist tabs are hidden
|
||||
- MENU/OZONE: Horizontal padding factor option
|
||||
- MENU/OZONE: Custom font selection and scaling factor
|
||||
- MENU/RGUI: Clock format is now configurable and moved to top header
|
||||
- NETPLAY: Push room info to lobby
|
||||
- NETWORK: Fixes for nmcli wifi driver
|
||||
- NETWORK: Network command interface enabled for Android, iOS, TVOS
|
||||
- OTHER: ZStandard support and libchdr update for support of chd files converted with createdvd option
|
||||
- OVERLAY: Speed limit on touch pointer tracking
|
||||
- OVERLAY: Dedicate each touch pointer to hitboxes or pointing devices
|
||||
- OVERLAY: Fix overlay turbo fire
|
||||
- PLAYLIST: Built-in playlists are now stored under playlists/builtin
|
||||
- PLAYLIST: Fix subsystem information in playlists
|
||||
- PS3: Fix psl1ght target of dist-cores.sh
|
||||
- REPLAY: Bugs fixed regarding rewind
|
||||
- REPLAY: Same timeline check and future state check for replays vs. savestates
|
||||
- SAVESTATES: Savestate thumbnails are default enabled for x86_64 builds
|
||||
- SAVESTATES: Slot is now remembered using the runtime log file
|
||||
- SAVESTATES: Slot hotkey widget shows save state thumbnail
|
||||
- SCAN: Fix crash with Sega CD
|
||||
- SCAN: Log files without database match
|
||||
- SCAN: Optimization of database queries by content file size
|
||||
- VIDEO: Fix auto swap interval setup
|
||||
- VIDEO: Improvements for integer scale half scaling
|
||||
- VIDEO: Adjustments to smart integer scaling, considering title safe area
|
||||
- VIDEO: Frame delay improvements for the automatic setting
|
||||
- VIDEO: Auto-enable GPU recording with HW context cores
|
||||
- VIDEO: Fix viewport bias when using custom aspect ratio
|
||||
- VIDEO/D3D11/D3D12: snappy extra vsync presentation mode
|
||||
- VIDEO/GL: Fallback OpenGL symbol loader for Linux devices with EGL < 1.5
|
||||
- VIDEO/GL: Support for Cg and GLSL shaders in the GLCore video driver
|
||||
- VIDEO/GL: Improve GLES version detection
|
||||
- VIDEO/SHADER: Shader hold function, useful for some lightguns and shader comparison
|
||||
- VIDEO/SWITCHRES: Horizontal and vertical geometry adjustment options added
|
||||
- VIDEO/SWITCHRES: Game overrides
|
||||
- VIDEO/VULKAN: Add VK_EXT_full_screen_exclusive extension support for Windows
|
||||
- VIDEO/WAYLAND: Support for xdg-toplevel-icon-v1
|
||||
- VIDEO/WAYLAND: Fix deadlock when using Wayland Vulkan driver
|
||||
- VIDEO/WAYLAND: Fix fullscreen on auto monitor index (partial)
|
||||
- VITA: Touchscreen support for PS Vita
|
||||
- VITA: Set RGUI framebuffer to 272 lines to remove blurriness
|
||||
- WEBOS: Various fixes and tunings
|
||||
- WEBOS: Disable core dumps
|
||||
- WEBOS: Debug builds enabled
|
||||
- WEBOS: Fix GLES 3/3.1/3.2 option, enable 64-bit option
|
||||
|
||||
# 1.21.0
|
||||
- 3DS: Fix unique IDs for newer cores
|
||||
- 3DS: Enable TLS (SSL)
|
||||
- 3DS: Fix UI freeze when threaded rendering is enabled
|
||||
- 3DS: Fix crash on load content
|
||||
- 3DS: Other minor fixes
|
||||
- APPLE: Enable Vulkan emulated mailbox
|
||||
- APPLE: Include b2 core in App Store builds
|
||||
- APPLE: CoreMIDI driver for IOS/MacOS
|
||||
- APPLE: CoreLocation driver for IOS/MacOS
|
||||
- AUTOCONF: Enable alternative display name in autoconfig files
|
||||
- AUTOCONF: Make autoconfig failure messages optional
|
||||
- AUDIO: Option to mute on rewind
|
||||
- AUDIO/PIPEWIRE: Fix app launch when pipewire service is stopped
|
||||
- AUDIO/PIPEWIRE: Fix speedup with threaded video mode
|
||||
- AUDIO/PIPEWIRE: Fix latency setting and microphone handling
|
||||
- AUDIO/PIPEWIRE: Pass the new rate to the audio driver
|
||||
- CAMERA: Add PipeWire camera driver
|
||||
- CAMERA: Add ffmpeg camera driver
|
||||
- CHEAT: Rewrite part of cheat_manager_load_cb_second_pass()
|
||||
- CHEEVOS: Include achievement state in netplay states
|
||||
- CHEEVOS: Fix crash when entering achievements in quick menu while client is not present
|
||||
- CHEEVOS: Restore cheevos_badges_enable for HAVE_GFX_WIDGETS builds
|
||||
- CLI: Allow --entryslot to fall back to normal states
|
||||
- CLOUDSYNC: Fix Windows path issues
|
||||
- CLOUDSYNC: Workaround for duplicated requests bug
|
||||
- CLOUDSYNC: Workaround for 301 redirects
|
||||
- CLOUDSYNC: Handle ignored directories properly
|
||||
- EMSCRIPTEN: Added new AudioWorklet driver, a fast callback-based audio driver
|
||||
- EMSCRIPTEN: Scale window to correct size
|
||||
- EMSCRIPTEN: Additional platform functions
|
||||
- EMSCRIPTEN: Add new default video context driver: emscriptenwebgl_ctx
|
||||
- EMSCRIPTEN: Add new audio driver: AudioWorklet
|
||||
- EMSCRIPTEN: Add new modernized web player which will eventually replace the existing one
|
||||
- EMSCRIPTEN/RWEBINPUT: Add touch input support
|
||||
- GAMECUBE: Fixes
|
||||
- GENERAL: Fix save state auto increment
|
||||
- GENERAL: Fix softpatching with periods/dots in the file name
|
||||
- GENERAL: Fix compilation with --enable-videocore
|
||||
- GENERAL: Allow asset directory redefinition and other directory overrides via environment variables
|
||||
- GENERAL: Allow override of player 1/2 input with machine learning models (needs recompilation and external library)
|
||||
- GENERAL: Fix performance counter option not remembered between sessions
|
||||
- GENERAL: Create security statement
|
||||
- GENERAL: Fix crash when core is not selected
|
||||
- GENERAL: Use core fps instead of screen refresh for calculating dropped frames
|
||||
- INPUT: Fix a crash when initializing illuminance sensor on Linux
|
||||
- INPUT: Analog-to-digital refactor, fixing behavior when analogs are assigned to keys
|
||||
- INPUT: Turbo fire overhaul. See https://github.com/libretro/RetroArch/pull/17633
|
||||
- INPUT/ANDROID: Fix game focus and pause handling
|
||||
- INPUT/COCOA: Include gravity in acceleration sensor values
|
||||
- INPUT/COCOA: Fix relative mouse input
|
||||
- INPUT/COCOA: Allow mouse input while mouse overlay is active
|
||||
- INPUT/WINRAW: Invert mouse index order
|
||||
- IOS: Ensure webserver notice can be dismissed
|
||||
- IOS: Fix rescanning manual playlists after app update
|
||||
- IOS: Fix clean playlist function
|
||||
- IOS: Fix crash when scanning
|
||||
- IOS: Fix jump back to selected item when closing content
|
||||
- IOS: Fix shared GL context setup
|
||||
- IOS: Update Launch Screen
|
||||
- IOS: Screen orientation lock through display server
|
||||
- IOS: Fix rescanning manual playlists after app update
|
||||
- LAKKA: Remove bluetooth device after disconnection
|
||||
- LINUX/X11: Extend X11 input driver with XInput2 extensions for multi-mouse
|
||||
- MACOS: Fix some sandbox handling in App Store builds
|
||||
- MACOS: Reset keyboard state when focus is lost
|
||||
- MENU: Add SSL support to the information list
|
||||
- MENU: Add warning to BFI and related menu items
|
||||
- MENU: Fix latency statistics when using runahead
|
||||
- MENU: Fix opening file inside archive with core selection
|
||||
- MENU: Main menu unified between different menu drivers
|
||||
- MENU: Visibility toggle for playlist tabs
|
||||
- MENU: Color the notification icon by message category
|
||||
- MENU: Gray Dark+Light theme adjustments
|
||||
- MENU/GLUI: Menu back button switches tabs like in other menu drivers
|
||||
- MENU/GLUI: Tab selection option is honored
|
||||
- MENU/GLUI: Fix CD icon appearing when no icon is specified
|
||||
- MENU/GLUI: Allow fullscreen thumbnail browsing
|
||||
- MENU/GLUI: Save state thumbnails
|
||||
- MENU/PLAYLISTS: Random selection/shuffle function
|
||||
- MENU/QT: Fix desktop menu crash with Cheevos disabled
|
||||
- MENU/RGUI: Cleanups of certain menu items
|
||||
- MENU/RGUI: Thumbnail fixes
|
||||
- MENU/OZONE: Fix messagebox background
|
||||
- MENU/XMB: Fix Light theme, font shadow
|
||||
- MENU/XMB: Appearance menu cleanup
|
||||
- MENU/XMB: Icon thumbnail can be any of the existing types
|
||||
- MISC: Guard nanosleep prototype behind _POSIX_TIMERS
|
||||
- MISC: Use fabsf and intended threshold for refresh rate check
|
||||
- MISC: Use platform-specific checks for invalid descriptors
|
||||
- MIDI: Add dropdown items for midi device selection
|
||||
- NETWORK: Refactor of net_http, improvements for task blocking and performance
|
||||
- NETWORK: Follow http redirects in net_http
|
||||
- NETWORK: Expire failed DNS lookups much faster
|
||||
- NETWORK: Fix netplay when using netpacket interface with recent cheevos
|
||||
- NETWORK/HTTP: Fix crash in net_http_resolve() in single-thread mode
|
||||
- OVERLAY: Fix overlay lightgun, mouse & pointer
|
||||
- OVERLAY: Preferred overlay loading is now default only on mobile platforms
|
||||
- OVERLAY: Improve analog recentering when touching the area just outside the recentering zone
|
||||
- QT: Enable non-png thumbnails also for Qt interface
|
||||
- REPLAY: Fix issue when replaying old format input recordings in newer RetroArch
|
||||
- TTS: Fix initial text-to-speech on Windows
|
||||
- TVOS: Fix 720p display
|
||||
- TVOS: Fix refresh rate fetching on tvOS 13/14
|
||||
- TVOS: Update Top Shelf art
|
||||
- SAVESTATES: Reset state index when loading new content
|
||||
- UWP: Fix slang shader compilation
|
||||
- VIDEO: Enable BFI setting for mobile platforms (mind the warnings)
|
||||
- VIDEO/OpenGLES: Fix FP/sRGB FBO support
|
||||
- VIDEO/SHADERS: Allow exact refresh rate sync with shader subframes
|
||||
- VIDEO/SHADERS: FIX shader wildcards
|
||||
- VIDEO/VULKAN: Enable adaptive vsync
|
||||
- VIDEO/V4L2: Added resolution picker/forcing.
|
||||
- VIDEO/V4L2: Rewrote logic for finding ALSA audio devices in enumerate_audio_devices function
|
||||
- VIDEO/V4L2: Added a skip for some of the interface queries that fail and aren't required for magewell usb.
|
||||
- VITA: Fixes
|
||||
- WINDOWS: Win32 socket improvements
|
||||
- WII: Fixes
|
||||
- WIIU: Fixes
|
||||
- WEBPLAYER: Update core list for 1.20.0
|
||||
|
||||
# 1.20.0
|
||||
- AUDIO: Fix audio handling in case of RARCH_NETPLAY_CTL_USE_CORE_PACKET_INTERFACE
|
||||
- AUDIO: Include missing audio filters on some platforms
|
||||
@@ -46,7 +299,7 @@
|
||||
- INPUT/UDEV: Enable mouse buttons 4 and 5
|
||||
- INPUT/WAYLAND: Enable horizontal scroll and mouse buttons 4 and 5
|
||||
- INPUT/WAYLAND: Simulate lightgun input for cores
|
||||
- INPUT/WAYLAND: Support for cursor-shape-v1 and content-type-v1 protocol
|
||||
- INPUT/WAYLAND: Support for cursor-shape-v1 protocol
|
||||
- INPUT/X11: Enable mouse buttons 4 and 5
|
||||
- iOS: Enable vibration by default
|
||||
- iOS: Better handling of physical mice/magic keyboard trackpad
|
||||
@@ -114,6 +367,7 @@
|
||||
- VIDEO/VULKAN: Fix Vulkan window freezes when swapchain becomes suboptimal
|
||||
- VIDEO/VULKAN: Prefer IMMEDIATE mode without vsync
|
||||
- VIDEO/X11: Support inhibit of Xss screensaver
|
||||
- VIDEO/WAYLAND: Support for content-type-v1 protocol
|
||||
- VITA: Enable analog L2/R2 triggers when a DS3 controller is used with PS Vita
|
||||
- WAYLAND: Fix segfault when relative pointer is not supported
|
||||
- WAYLAND: Use reverse DNS name for desktop file and icon
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
HAVE_FILE_LOGGER=1
|
||||
HAVE_STATESTREAM?=1
|
||||
NEED_CXX_LINKER?=0
|
||||
NEED_GOLD_LINKER?=0
|
||||
MISSING_DECLS =0
|
||||
@@ -45,7 +46,6 @@ else
|
||||
OBJDIR := $(OBJDIR_BASE)/release
|
||||
CFLAGS ?= -O3
|
||||
CXXFLAGS ?= -O3
|
||||
DEF_FLAGS += -ffast-math
|
||||
endif
|
||||
|
||||
DEF_FLAGS += -Wall -Wsign-compare
|
||||
@@ -113,7 +113,7 @@ endif
|
||||
|
||||
ifneq ($(CXX_BUILD), 1)
|
||||
ifneq ($(C89_BUILD),)
|
||||
CFLAGS += -std=c89 -ansi -pedantic -Werror=pedantic -Wno-long-long -Werror=declaration-after-statement
|
||||
CFLAGS += -std=c89 -ansi -pedantic -Werror=pedantic -Wno-long-long -Werror=declaration-after-statement -Wno-variadic-macros
|
||||
else ifeq ($(HAVE_C99), 1)
|
||||
CFLAGS += $(C99_CFLAGS)
|
||||
endif
|
||||
@@ -173,6 +173,33 @@ endif
|
||||
|
||||
all: $(TARGET) config.mk
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CPPFLAGS: $(CPPFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBRARY_DIRS: $(LIBRARY_DIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
MD: $(MD)
|
||||
MOC: $(MOC)
|
||||
MOC_TMP: $(MOC_TMP)
|
||||
OBJCFLAGS: $(OBJCFLAGS)
|
||||
QT_VERSION: $(QT_VERSION)
|
||||
RARCH_OBJ: $(RARCH_OBJ)
|
||||
WINDRES: $(WINDRES)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
$(MOC_SRC):
|
||||
@$(if $(Q), $(shell echo echo MOC $<),)
|
||||
$(eval MOC_TMP := $(patsubst %.h,%_moc.cpp,$@))
|
||||
@@ -285,9 +312,10 @@ uninstall:
|
||||
rm -rf $(DESTDIR)$(ASSETS_DIR)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR_BASE)
|
||||
rm -f $(TARGET)
|
||||
rm -f *.d
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -rf $(OBJDIR_BASE)
|
||||
$(Q)rm -f $(TARGET)
|
||||
$(Q)rm -f *.d
|
||||
|
||||
.PHONY: all install uninstall clean
|
||||
|
||||
|
||||
+195
-38
@@ -302,6 +302,10 @@ OBJ += \
|
||||
$(LIBRETRO_COMM_DIR)/streams/network_stream.o \
|
||||
$(LIBRETRO_COMM_DIR)/vfs/vfs_implementation.o
|
||||
|
||||
ifeq ($(ANDROID), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/vfs/vfs_implementation_saf.o
|
||||
endif
|
||||
|
||||
OBJ += \
|
||||
$(LIBRETRO_COMM_DIR)/lists/string_list.o \
|
||||
$(LIBRETRO_COMM_DIR)/string/stdstring.o \
|
||||
@@ -351,7 +355,6 @@ endif
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
DEFINES += -DHAVE_MICROPHONE
|
||||
OBJ += audio/microphone_driver.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_REWIND), 1)
|
||||
@@ -452,6 +455,12 @@ endif
|
||||
|
||||
ifeq ($(HAVE_BSV_MOVIE), 1)
|
||||
DEFINES += -DHAVE_BSV_MOVIE
|
||||
OBJ += input/bsv/bsvmovie.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_STATESTREAM), 1)
|
||||
DEFINES += -DHAVE_STATESTREAM
|
||||
OBJ += input/bsv/uint32s_index.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RUNAHEAD), 1)
|
||||
@@ -790,6 +799,9 @@ ifeq ($(HAVE_EMSCRIPTEN), 1)
|
||||
ifeq ($(HAVE_RWEBAUDIO), 1)
|
||||
OBJ += audio/drivers/rwebaudio.o
|
||||
endif
|
||||
ifeq ($(HAVE_AUDIOWORKLET), 1)
|
||||
OBJ += audio/drivers/audioworklet.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_BLUETOOTH), 1)
|
||||
@@ -858,10 +870,6 @@ ifeq ($(HAVE_ALSA), 1)
|
||||
OBJ += audio/drivers/alsa.o \
|
||||
audio/common/alsa.o
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
OBJ += audio/drivers_microphone/alsa.o
|
||||
endif
|
||||
|
||||
ifneq ($(HAVE_HAKCHI), 1)
|
||||
ifneq ($(HAVE_SEGAM), 1)
|
||||
ifneq ($(DINGUX), 1)
|
||||
@@ -872,12 +880,7 @@ ifeq ($(HAVE_ALSA), 1)
|
||||
|
||||
ifneq ($(MIYOO), 1)
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
OBJ += audio/drivers/alsathread.o \
|
||||
audio/common/alsathread.o
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
OBJ += audio/drivers_microphone/alsathread.o
|
||||
endif
|
||||
OBJ += audio/drivers/alsathread.o
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -925,8 +928,8 @@ ifeq ($(HAVE_PIPEWIRE), 1)
|
||||
OBJ += audio/drivers/pipewire.o \
|
||||
audio/common/pipewire.o
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
OBJ += audio/drivers_microphone/pipewire.o
|
||||
ifeq ($(HAVE_PIPEWIRE_STABLE), 1)
|
||||
OBJ += camera/drivers/pipewire.o
|
||||
endif
|
||||
|
||||
LIBS += $(PIPEWIRE_LIBS)
|
||||
@@ -952,14 +955,9 @@ endif
|
||||
|
||||
ifeq ($(HAVE_WASAPI), 1)
|
||||
HAVE_MMDEVAPI = 1
|
||||
OBJ += audio/drivers/wasapi.o \
|
||||
audio/common/wasapi.o
|
||||
OBJ += audio/drivers/wasapi.o
|
||||
DEFINES += -DHAVE_WASAPI
|
||||
LIBS += -lole32 -lksuser
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
OBJ += audio/drivers_microphone/wasapi.o
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_XAUDIO), 1)
|
||||
@@ -978,6 +976,12 @@ ifeq ($(HAVE_WINMM), 1)
|
||||
LIBS += -lwinmm
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_COREMIDI), 1)
|
||||
OBJ += midi/drivers/coremidi.o
|
||||
DEFINES += -DHAVE_COREMIDI
|
||||
LIBS += -framework CoreMIDI
|
||||
endif
|
||||
|
||||
# Audio Resamplers
|
||||
|
||||
ifeq ($(HAVE_NEON),1)
|
||||
@@ -1271,6 +1275,7 @@ ifeq ($(HAVE_WAYLAND), 1)
|
||||
gfx/common/wayland_common.o \
|
||||
gfx/common/wayland/fractional-scale-v1.o \
|
||||
gfx/common/wayland/viewporter.o \
|
||||
gfx/common/wayland/xdg-toplevel-icon-v1.o \
|
||||
gfx/common/wayland/xdg-shell.o \
|
||||
gfx/common/wayland/idle-inhibit-unstable-v1.o \
|
||||
gfx/common/wayland/xdg-decoration-unstable-v1.o \
|
||||
@@ -1337,6 +1342,10 @@ ifeq ($(HAVE_X11), 1)
|
||||
ifeq ($(HAVE_XCB),1)
|
||||
LIBS += -lX11-xcb
|
||||
endif
|
||||
ifeq ($(HAVE_XI2),1)
|
||||
LIBS += -lXi
|
||||
DEFINES += -DHAVE_XI2
|
||||
endif
|
||||
ifeq ($(HAVE_XSCRNSAVER),1)
|
||||
LIBS += -lXss
|
||||
endif
|
||||
@@ -1494,6 +1503,7 @@ ifeq ($(HAVE_PLAIN_DRM), 1)
|
||||
INCLUDE_DIRS += -I/usr/include/libdrm
|
||||
endif
|
||||
LIBS += -ldrm
|
||||
HAVE_AND_WILL_USE_DRM = 1
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_VITAGL), 1)
|
||||
@@ -1526,7 +1536,10 @@ ifeq ($(HAVE_GL_CONTEXT), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_EMSCRIPTEN), 1)
|
||||
OBJ += gfx/drivers_context/emscriptenegl_ctx.o
|
||||
ifeq ($(HAVE_EGL), 1)
|
||||
OBJ += gfx/drivers_context/emscriptenegl_ctx.o
|
||||
endif
|
||||
OBJ += gfx/drivers_context/emscriptenwebgl_ctx.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MALI_FBDEV), 1)
|
||||
@@ -1570,10 +1583,11 @@ ifeq ($(HAVE_GL_CONTEXT), 1)
|
||||
DEF_FLAGS += $(OPENGLES_CFLAGS)
|
||||
ifeq ($(HAVE_OPENGLES3), 1)
|
||||
DEFINES += -DHAVE_OPENGLES3
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es3.o
|
||||
else
|
||||
DEFINES += -DHAVE_OPENGLES2
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o
|
||||
endif
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_es2.o
|
||||
else
|
||||
DEFINES += -DHAVE_GL_SYNC
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/glsym/glsym_gl.o
|
||||
@@ -1615,14 +1629,9 @@ endif
|
||||
ifeq ($(HAVE_SDL2), 1)
|
||||
HAVE_SDL_COMMON = 1
|
||||
OBJ += gfx/drivers/sdl2_gfx.o \
|
||||
gfx/common/sdl2_common.o
|
||||
gfx/common/sdl2_common.o
|
||||
DEF_FLAGS += $(SDL2_CFLAGS)
|
||||
LIBS += $(SDL2_LIBS)
|
||||
|
||||
ifeq ($(HAVE_MICROPHONE), 1)
|
||||
OBJ += audio/drivers_microphone/sdl_microphone.o
|
||||
# Microphones are not supported by SDL 1.x
|
||||
endif
|
||||
else ifeq ($(HAVE_SDL), 1)
|
||||
HAVE_SDL_COMMON = 1
|
||||
OBJ += gfx/drivers/sdl_gfx.o
|
||||
@@ -1688,11 +1697,15 @@ ifeq ($(HAVE_VULKAN), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OPENGL_CORE), 1)
|
||||
OBJ += gfx/drivers/gl3.o \
|
||||
gfx/drivers_shader/shader_gl3.o
|
||||
OBJ += gfx/drivers/gl3.o
|
||||
|
||||
DEFINES += -DHAVE_OPENGL_CORE
|
||||
NEED_CXX_LINKER = 1
|
||||
|
||||
ifeq ($(HAVE_SLANG), 1)
|
||||
OBJ += gfx/drivers_shader/shader_gl3.o
|
||||
|
||||
NEED_CXX_LINKER = 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OMAP), 1)
|
||||
@@ -1754,22 +1767,19 @@ endif
|
||||
|
||||
ifeq ($(HAVE_D3D10), 1)
|
||||
HAVE_D3D_COMMON = 1
|
||||
OBJ += gfx/drivers/d3d10.o \
|
||||
gfx/common/d3d10_common.o
|
||||
OBJ += gfx/drivers/d3d10.o
|
||||
DEFINES += -DHAVE_D3D10
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_D3D11), 1)
|
||||
HAVE_D3D_COMMON = 1
|
||||
OBJ += gfx/drivers/d3d11.o \
|
||||
gfx/common/d3d11_common.o
|
||||
OBJ += gfx/drivers/d3d11.o
|
||||
DEFINES += -DHAVE_D3D11
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_D3D12), 1)
|
||||
HAVE_D3D_COMMON = 1
|
||||
OBJ += gfx/drivers/d3d12.o \
|
||||
gfx/common/d3d12_common.o
|
||||
OBJ += gfx/drivers/d3d12.o
|
||||
DEFINES += -DHAVE_D3D12
|
||||
endif
|
||||
|
||||
@@ -1949,6 +1959,34 @@ ifeq ($(HAVE_7ZIP),1)
|
||||
$(7ZOBJ)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_ZSTD),1)
|
||||
INCLUDE_DIRS += -I$(DEPS_DIR)/zstd/lib
|
||||
DEFINES += -DHAVE_ZSTD -DZSTD_DISABLE_ASM
|
||||
ZSOBJ = $(DEPS_DIR)/zstd/lib/common/entropy_common.o \
|
||||
$(DEPS_DIR)/zstd/lib/common/error_private.o \
|
||||
$(DEPS_DIR)/zstd/lib/common/fse_decompress.o \
|
||||
$(DEPS_DIR)/zstd/lib/common/zstd_common.o \
|
||||
$(DEPS_DIR)/zstd/lib/common/xxhash.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/fse_compress.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/hist.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/huf_compress.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_compress.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_compress_literals.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_compress_sequences.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_compress_superblock.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_double_fast.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_fast.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_lazy.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_ldm.o \
|
||||
$(DEPS_DIR)/zstd/lib/compress/zstd_opt.o \
|
||||
$(DEPS_DIR)/zstd/lib/decompress/huf_decompress.o \
|
||||
$(DEPS_DIR)/zstd/lib/decompress/zstd_ddict.o \
|
||||
$(DEPS_DIR)/zstd/lib/decompress/zstd_decompress.o \
|
||||
$(DEPS_DIR)/zstd/lib/decompress/zstd_decompress_block.o
|
||||
|
||||
OBJ += $(ZSOBJ)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_IBXM), 1)
|
||||
DEFINES += -DHAVE_IBXM
|
||||
OBJ += $(DEPS_DIR)/ibxm/ibxm.o
|
||||
@@ -1990,6 +2028,7 @@ ifeq ($(HAVE_BUILTINZLIB), 1)
|
||||
HAVE_ZLIB_COMMON = 1
|
||||
OBJ += $(DEPS_DIR)/libz/adler32.o \
|
||||
$(DEPS_DIR)/libz/libz-crc32.o \
|
||||
$(DEPS_DIR)/libz/compress.o \
|
||||
$(DEPS_DIR)/libz/deflate.o \
|
||||
$(DEPS_DIR)/libz/gzclose.o \
|
||||
$(DEPS_DIR)/libz/gzlib.o \
|
||||
@@ -1999,6 +2038,7 @@ ifeq ($(HAVE_BUILTINZLIB), 1)
|
||||
$(DEPS_DIR)/libz/inflate.o \
|
||||
$(DEPS_DIR)/libz/inftrees.o \
|
||||
$(DEPS_DIR)/libz/trees.o \
|
||||
$(DEPS_DIR)/libz/uncompr.o \
|
||||
$(DEPS_DIR)/libz/zutil.o
|
||||
INCLUDE_DIRS += -I$(LIBRETRO_COMM_DIR)/include/compat/zlib
|
||||
else ifeq ($(HAVE_ZLIB),1)
|
||||
@@ -2099,6 +2139,13 @@ ifeq ($(HAVE_ZLIB_COMMON), 1)
|
||||
DEFINES += -Dcdlz_codec_init=retroarch_internal_cdlz_codec_init
|
||||
DEFINES += -Dcdlz_codec_free=retroarch_internal_cdlz_codec_free
|
||||
DEFINES += -Dcdlz_codec_decompress=retroarch_internal_cdlz_codec_decompress
|
||||
|
||||
DEFINES += -Dzstd_codec_init=retroarch_internal_zstd_codec_init
|
||||
DEFINES += -Dzstd_codec_free=retroarch_internal_zstd_codec_free
|
||||
DEFINES += -Dzstd_codec_decompress=retroarch_internal_zstd_codec_decompress
|
||||
DEFINES += -Dcdzs_codec_init=retroarch_internal_cdzs_codec_init
|
||||
DEFINES += -Dcdzs_codec_free=retroarch_internal_cdzs_codec_free
|
||||
DEFINES += -Dcdzs_codec_decompress=retroarch_internal_cdzs_codec_decompress
|
||||
endif
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_bitstream.o \
|
||||
$(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_cdrom.o \
|
||||
@@ -2115,6 +2162,10 @@ ifeq ($(HAVE_ZLIB_COMMON), 1)
|
||||
ifeq ($(HAVE_7ZIP), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_lzma.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_ZSTD), 1)
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/libchdr_zstd.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -2168,6 +2219,65 @@ ifeq ($(HAVE_V4L2),1)
|
||||
LIBS += $(V4L2_LIBS)
|
||||
endif
|
||||
|
||||
# FFmpeg
|
||||
|
||||
ifeq ($(HAVE_FFMPEG), 1)
|
||||
DEFINES += -DHAVE_FFMPEG
|
||||
INCLUDE_DIRS += -Iffmpeg
|
||||
DEF_FLAGS += $(FFMPEG_CFLAGS) -Wno-deprecated-declarations
|
||||
LIBS += $(FFMPEG_LIBS)
|
||||
|
||||
ifeq ($(HAVE_AVCODEC), 1)
|
||||
DEFINES += -DHAVE_AVCODEC
|
||||
DEF_FLAGS += $(AVCODEC_CFLAGS)
|
||||
LIBS += $(AVCODEC_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_AVDEVICE), 1)
|
||||
DEFINES += -DHAVE_AVDEVICE
|
||||
DEF_FLAGS += $(AVDEVICE_CFLAGS)
|
||||
LIBS += $(AVDEVICE_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_AVFORMAT), 1)
|
||||
DEFINES += -DHAVE_AVFORMAT
|
||||
DEF_FLAGS += $(AVFORMAT_CFLAGS)
|
||||
LIBS += $(AVFORMAT_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_AVUTIL), 1)
|
||||
DEFINES += -DHAVE_AVUTIL
|
||||
DEF_FLAGS += $(AVUTIL_CFLAGS)
|
||||
LIBS += $(AVUTIL_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SWSCALE), 1)
|
||||
DEFINES += -DHAVE_SWSCALE
|
||||
DEF_FLAGS += $(SWSCALE_CFLAGS)
|
||||
LIBS += $(SWSCALE_LIBS)
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SWRESAMPLE), 1)
|
||||
DEFINES += -DHAVE_SWRESAMPLE
|
||||
DEF_FLAGS += $(SWRESAMPLE_CFLAGS)
|
||||
LIBS += $(SWRESAMPLE_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_FFMPEG), 1)
|
||||
ifeq ($(HAVE_AVFORMAT), 1)
|
||||
ifeq ($(HAVE_AVDEVICE), 1)
|
||||
ifeq ($(HAVE_AVCODEC), 1)
|
||||
ifeq ($(HAVE_AVUTIL), 1)
|
||||
ifeq ($(HAVE_SWSCALE), 1)
|
||||
OBJ += camera/drivers/ffmpeg.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Accessibility
|
||||
ifeq ($(HAVE_ACCESSIBILITY), 1)
|
||||
DEFINES += -DHAVE_ACCESSIBILITY
|
||||
@@ -2192,11 +2302,16 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
$(LIBRETRO_COMM_DIR)/net/net_socket.o \
|
||||
core_updater_list.o \
|
||||
network/natt.o \
|
||||
tasks/task_http.o \
|
||||
tasks/task_netplay_lan_scan.o \
|
||||
tasks/task_netplay_nat_traversal.o \
|
||||
tasks/task_netplay_find_content.o
|
||||
|
||||
ifeq ($(HAVE_EMSCRIPTEN), 1)
|
||||
OBJ += tasks/task_http_emscripten.o
|
||||
else
|
||||
OBJ += tasks/task_http.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_MENU), 1)
|
||||
OBJ += tasks/task_pl_thumbnail_download.o
|
||||
endif
|
||||
@@ -2284,11 +2399,21 @@ ifeq ($(HAVE_NETWORKING), 1)
|
||||
deps/rcheevos/src/rhash/aes.o \
|
||||
deps/rcheevos/src/rhash/cdreader.o \
|
||||
deps/rcheevos/src/rhash/hash.o \
|
||||
deps/rcheevos/src/rhash/hash_disc.o \
|
||||
deps/rcheevos/src/rhash/hash_encrypted.o \
|
||||
deps/rcheevos/src/rhash/hash_rom.o \
|
||||
deps/rcheevos/src/rhash/hash_zip.o \
|
||||
deps/rcheevos/src/rapi/rc_api_common.o \
|
||||
deps/rcheevos/src/rapi/rc_api_info.o \
|
||||
deps/rcheevos/src/rapi/rc_api_runtime.o \
|
||||
deps/rcheevos/src/rapi/rc_api_user.o \
|
||||
|
||||
# RVZ/WIA disc image support for RetroAchievements
|
||||
ifeq ($(HAVE_ZSTD), 1)
|
||||
DEFINES += -DHAVE_CHEEVOS_RVZ
|
||||
OBJ += cheevos/cheevos_rvz.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_LUA), 1)
|
||||
DEFINES += -DHAVE_LUA \
|
||||
-DLUA_32BITS
|
||||
@@ -2403,7 +2528,7 @@ ifeq ($(HAVE_FFMPEG), 1)
|
||||
cores/libretro-ffmpeg/video_buffer.o \
|
||||
$(LIBRETRO_COMM_DIR)/rthreads/tpool.o
|
||||
|
||||
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS)
|
||||
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS) $(AVDEVICE_LIBS)
|
||||
DEFINES += -DHAVE_FFMPEG
|
||||
DEF_FLAGS += $(AVCODEC_CFLAGS) $(AVFORMAT_CFLAGS) $(AVUTIL_CFLAGS) $(SWSCALE_CFLAGS) $(SWRESAMPLE_CFLAGS) \
|
||||
-Wno-deprecated-declarations
|
||||
@@ -2648,4 +2773,36 @@ ifeq ($(HAVE_ODROIDGO2), 1)
|
||||
gfx/drivers/oga_gfx.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GAME_AI),1)
|
||||
DEFINES += -DHAVE_GAME_AI
|
||||
OBJ += ai/game_ai.o
|
||||
endif
|
||||
|
||||
# Detect the operating system
|
||||
UNAME := $(shell uname -s)
|
||||
|
||||
# Check if the system is MSYS2 (MINGW64 or MINGW32)
|
||||
ifneq ($(findstring MINGW,$(UNAME)),)
|
||||
$(info Detected MSYS2 environment)
|
||||
|
||||
NT_VERSION := $(shell \
|
||||
echo '#include <windows.h>' > temp.c; \
|
||||
echo '#ifdef _WIN32_WINNT' >> temp.c; \
|
||||
echo '#define GET_MACRO_VALUE(x) #x' >> temp.c; \
|
||||
echo '#define EXPAND_MACRO_VALUE(x) GET_MACRO_VALUE(x)' >> temp.c; \
|
||||
echo '#pragma message("_WIN32_WINNT=" EXPAND_MACRO_VALUE(_WIN32_WINNT))' >> temp.c; \
|
||||
echo '#endif' >> temp.c; \
|
||||
$(CC) -c temp.c 2>&1 | sed -n 's/^.*_WIN32_WINNT=\(0x[0-9A-Fa-f]\+\).*/\1/p'; \
|
||||
rm -f temp.c temp.o)
|
||||
|
||||
ifneq ($(NT_VERSION),)
|
||||
ifeq ($(shell [ $$(( $(NT_VERSION) )) -gt $$(( 0x602 )) ] && echo true),true)
|
||||
LIBS += -lxaudio2_9
|
||||
endif
|
||||
else
|
||||
$(warning Windows NT version macro (_WIN32_WINNT) is not defined.)
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
##################################
|
||||
+84
-56
@@ -3,8 +3,8 @@ LIBRETRO =
|
||||
|
||||
DEBUG = 0
|
||||
CONSOLE_LOG = 0
|
||||
GRIFFIN_BUILD = 1
|
||||
HAVE_STATIC_DUMMY ?= 0
|
||||
GRIFFIN_BUILD = 0
|
||||
HAVE_STATIC_DUMMY ?= 0
|
||||
WHOLE_ARCHIVE_LINK = 0
|
||||
BUILD_3DSX = 1
|
||||
BUILD_3DS = 0
|
||||
@@ -68,6 +68,14 @@ ifeq ($(GRIFFIN_BUILD), 1)
|
||||
#DEFINES += -DHAVE_SOCKET_LEGACY
|
||||
#-DHAVE_SSL -DHAVE_BUILTINMBEDTLS -DMBEDTLS_SSL_DEBUG_ALL
|
||||
#ssl is currently incompatible with griffin due to use of the "static" flag on repeating functions that will conflict when included in one file
|
||||
CFLAGS += -I. \
|
||||
-Ideps \
|
||||
-Ideps/7zip \
|
||||
-Ideps/stb \
|
||||
-Ideps/mbedtls \
|
||||
-Ideps/rcheevos/include \
|
||||
-Ilibretro-common/include \
|
||||
-Ilibretro-common/include/compat/zlib
|
||||
else
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
@@ -89,21 +97,22 @@ else
|
||||
HAVE_REWIND = 1
|
||||
HAVE_AUDIOMIXER = 1
|
||||
HAVE_RWAV = 1
|
||||
#HAVE_NETWORKING = 1
|
||||
#HAVE_IFINFO = 1
|
||||
#HAVE_CHEEVOS = 1
|
||||
#HAVE_SOCKET_LEGACY = 1
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_VIDEO_FILTER = 1
|
||||
HAVE_DSP_FILTER = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_OVERLAY = 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_NETWORKING = 1
|
||||
HAVE_IFINFO = 1
|
||||
HAVE_CHEEVOS = 1
|
||||
HAVE_THREADS = 1
|
||||
#HAVE_SSL = 1
|
||||
#HAVE_BUILTINMBEDTLS = 1
|
||||
HAVE_BUILTINMBEDTLS = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
HAVE_CLOUDSYNC = 1
|
||||
|
||||
include Makefile.common
|
||||
CFLAGS += $(DEF_FLAGS)
|
||||
BLACKLIST :=
|
||||
BLACKLIST += input/input_overlay.o
|
||||
BLACKLIST += tasks/task_overlay.o
|
||||
OBJ := $(filter-out $(BLACKLIST),$(OBJ))
|
||||
CFLAGS += $(DEF_FLAGS) -I. $(INCLUDE_DIRS)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
@@ -153,12 +162,7 @@ LIBDIRS := -L. -L$(CTRULIB)/lib
|
||||
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=soft
|
||||
|
||||
CFLAGS += -mword-relocations \
|
||||
-fomit-frame-pointer -ffast-math \
|
||||
-Werror=implicit-function-declaration \
|
||||
$(ARCH)
|
||||
|
||||
#CFLAGS += -Wall
|
||||
CFLAGS += -mword-relocations $(ARCH)
|
||||
CFLAGS += -DARM11 -D_3DS
|
||||
|
||||
ifeq ($(strip $(USE_CTRULIB_2)),1)
|
||||
@@ -168,7 +172,7 @@ endif
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3
|
||||
CFLAGS += -fomit-frame-pointer -O3
|
||||
endif
|
||||
|
||||
ifeq ($(CONSOLE_LOG), 1)
|
||||
@@ -184,25 +188,17 @@ ifeq ($(WHOLE_ARCHIVE_LINK), 1)
|
||||
WHOLE_END := -Wl,--no-whole-archive
|
||||
endif
|
||||
|
||||
CFLAGS += -I. \
|
||||
-Ideps \
|
||||
-Ideps/7zip \
|
||||
-Ideps/stb \
|
||||
-Ideps/rcheevos/include \
|
||||
-Ilibretro-common/include \
|
||||
-Ilibretro-common/include/compat/zlib
|
||||
|
||||
CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE
|
||||
CFLAGS += -DHAVE_DSP_FILTER
|
||||
CFLAGS += -DHAVE_VIDEO_FILTER
|
||||
CFLAGS += -DHAVE_FILTERS_BUILTIN $(DEFINES)
|
||||
CFLAGS += -DHAVE_CHEATS
|
||||
CFLAGS += -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
CFLAGS += -Werror=implicit-function-declaration
|
||||
|
||||
ASFLAGS := -g $(ARCH) -O3
|
||||
LDFLAGS += -specs=ctr/3dsx_custom.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
CFLAGS += -std=gnu99 -ffast-math
|
||||
CFLAGS += -std=gnu99
|
||||
|
||||
LIB_CORE :=
|
||||
LIB_CORE_FULL :=
|
||||
@@ -222,6 +218,10 @@ else
|
||||
LIBS += -lctru
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_3DSX), 1)
|
||||
TARGET_3DSX := $(TARGET).3dsx $(TARGET).smdh
|
||||
endif
|
||||
@@ -234,16 +234,7 @@ ifeq ($(BUILD_CIA), 1)
|
||||
TARGET_CIA := $(TARGET).cia
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA)
|
||||
$(TARGET).3dsx: $(TARGET).elf
|
||||
$(TARGET).elf: $(OBJ) $(LIB_CORE_FULL)
|
||||
|
||||
PREFIX := $(DEVKITARM)/bin/arm-none-eabi-
|
||||
|
||||
CC := $(PREFIX)gcc
|
||||
CXX := $(PREFIX)g++
|
||||
AS := $(PREFIX)as
|
||||
@@ -277,6 +268,36 @@ else
|
||||
MAKEROM = $(CTRMAKEROM)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
define INFO
|
||||
AR: $(AR)
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
INCDIRS: $(INCDIRS)
|
||||
LD: $(LD)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
OBJ: $(OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
|
||||
$(TARGET): $(TARGET_3DSX) $(TARGET_3DS) $(TARGET_CIA)
|
||||
$(TARGET).3dsx: $(TARGET).elf
|
||||
$(TARGET).elf: $(OBJ) $(LIB_CORE_FULL)
|
||||
|
||||
%.o: %.vsh %.gsh
|
||||
$(DEVKITTOOLS)/bin/picasso $^ -o $*.shbin
|
||||
$(DEVKITTOOLS)/bin/bin2s $*.shbin | $(PREFIX)as -o $@
|
||||
@@ -288,19 +309,24 @@ endif
|
||||
rm $*.shbin
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS)
|
||||
|
||||
%.o: %.s
|
||||
$(CC) -c -o $@ $< $(ASFLAGS)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(ASFLAGS)
|
||||
|
||||
%.o: %.S
|
||||
$(CC) -c -o $@ $< $(ASFLAGS)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(ASFLAGS)
|
||||
|
||||
%.a:
|
||||
$(AR) -rc $@ $^
|
||||
@$(if $(Q), $(shell echo echo AR $<),)
|
||||
$(Q)$(AR) -rc $@ $^
|
||||
|
||||
%.vsh:
|
||||
|
||||
@@ -316,7 +342,8 @@ endif
|
||||
$(DEVKITTOOLS)/bin/3dsxtool $< $@ $(_3DSXFLAGS)
|
||||
|
||||
$(TARGET).elf: ctr/3dsx_custom_crt0.o
|
||||
$(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LD) $(LDFLAGS) $(OBJ) $(LIBDIRS) $(LIBS) -o $@
|
||||
$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
$(TARGET).bnr: $(TARGET).elf $(APP_BANNER) $(APP_AUDIO)
|
||||
@@ -332,15 +359,16 @@ $(TARGET).cia: $(TARGET).elf $(TARGET).bnr $(TARGET).icn $(APP_RSF)
|
||||
$(MAKEROM) -f cia -o $@ $(MAKEROM_ARGS_COMMON) -DAPP_ENCRYPTED=false
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ)
|
||||
rm -f $(TARGET).3dsx
|
||||
rm -f $(TARGET).elf
|
||||
rm -f $(TARGET).3ds
|
||||
rm -f $(TARGET).cia
|
||||
rm -f $(TARGET).smdh
|
||||
rm -f $(TARGET).bnr
|
||||
rm -f $(TARGET).icn
|
||||
rm -f ctr/ctr_config_*.o
|
||||
rm -f ctr/3dsx_custom_crt0.o
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -f $(OBJ)
|
||||
$(Q)rm -f $(TARGET).3dsx
|
||||
$(Q)rm -f $(TARGET).elf
|
||||
$(Q)rm -f $(TARGET).3ds
|
||||
$(Q)rm -f $(TARGET).cia
|
||||
$(Q)rm -f $(TARGET).smdh
|
||||
$(Q)rm -f $(TARGET).bnr
|
||||
$(Q)rm -f $(TARGET).icn
|
||||
$(Q)rm -f ctr/ctr_config_*.o
|
||||
$(Q)rm -f ctr/3dsx_custom_crt0.o
|
||||
|
||||
.PHONY: clean
|
||||
@@ -83,12 +83,7 @@ LIBDIRS := -L. -L$(CTRULIB)/lib
|
||||
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -marm -mfpu=vfp -mtp=soft
|
||||
|
||||
CFLAGS += -mword-relocations \
|
||||
-fomit-frame-pointer -ffast-math \
|
||||
-Werror=implicit-function-declaration \
|
||||
$(ARCH)
|
||||
|
||||
#CFLAGS += -Wall
|
||||
CFLAGS += -mword-relocations -fomit-frame-pointer $(ARCH)
|
||||
CFLAGS += -DARM11 -D_3DS
|
||||
|
||||
ifeq ($(strip $(USE_CTRULIB_2)),1)
|
||||
@@ -111,11 +106,12 @@ CFLAGS += -I. -Ideps/7zip -Ideps/stb -Ilibretro-common/include -Ilibretro-common
|
||||
CFLAGS += -DRARCH_CONSOLE -DIS_SALAMANDER
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
CFLAGS += -Werror=implicit-function-declaration
|
||||
|
||||
ASFLAGS := -g $(ARCH) -O3
|
||||
LDFLAGS += -specs=ctr/3dsx_custom.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
CFLAGS += -std=gnu99 -ffast-math
|
||||
CFLAGS += -std=gnu99
|
||||
|
||||
LIBS := -lctru -lm
|
||||
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ OPK_NAME = retroarch.opk
|
||||
|
||||
OBJ :=
|
||||
LINK := $(CXX)
|
||||
DEF_FLAGS := -march=mips32 -mtune=mips32r2 -mhard-float -ffast-math -fomit-frame-pointer
|
||||
DEF_FLAGS := -march=mips32 -mtune=mips32r2 -mhard-float -fomit-frame-pointer
|
||||
DEF_FLAGS += -mplt -mno-shared
|
||||
DEF_FLAGS += -ffunction-sections -fdata-sections
|
||||
DEF_FLAGS += -I. -Ideps -Ideps/stb -DDINGUX=1 -MMD
|
||||
|
||||
+34
-6
@@ -120,7 +120,7 @@ APP_ICON := pkg/libnx/retroarch.jpg
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH :=
|
||||
|
||||
CFLAGS := -g -Wall -O3 -fcommon -ffast-math -ffunction-sections \
|
||||
CFLAGS := -g -Wall -O3 -fcommon -ffunction-sections \
|
||||
$(ARCH) $(DEFINES) $(INCLUDE_DIRS)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
@@ -195,6 +195,10 @@ else
|
||||
LIB_CORE += -lretro_dos
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
DEPENDS_TMP := $(OFILES:.o=.d)
|
||||
DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP))
|
||||
|
||||
@@ -203,19 +207,43 @@ DEPENDS := $(filter-out libretro_libnx.a,$(DEPENDS_TMP))
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT)
|
||||
all: $(OUTPUT)
|
||||
|
||||
define INFO
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
DEPENDS: $(DEPENDS)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
LIB_CORE: $(LIB_CORE)
|
||||
OBJ: $(OBJ)
|
||||
OUTPUT: $(OUTPUT)
|
||||
PLATEXTRA: $(PLATEXTRA)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
$(OUTPUT): $(OBJ)
|
||||
$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) -L. $(LIB_CORE) $(LIBS)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) -L. $(LIB_CORE) $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) -c -o $@ $(CFLAGS) $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $(CFLAGS) $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c -o $@ $(CFLAGS) $<
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) -c -o $@ $(CFLAGS) $<
|
||||
|
||||
clean:
|
||||
rm -f $(DEPENDS) $(OBJ) $(OUTPUT)
|
||||
@$(if $(Q), $(shell echo echo RM),)
|
||||
$(Q)rm -f $(DEPENDS) $(OBJ) $(OUTPUT)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
|
||||
+227
-80
@@ -7,29 +7,34 @@ else
|
||||
TARGET := $(LIBRETRO)_libretro.js
|
||||
endif
|
||||
endif
|
||||
|
||||
EOPT = USE_ZLIB=1 # Emscripten specific options
|
||||
EOPTS = $(addprefix -s $(EMPTY), $(EOPT)) # Add '-s ' to each option
|
||||
TARGET_BASE := $(subst .js,,$(TARGET))
|
||||
|
||||
OS = Emscripten
|
||||
OBJ :=
|
||||
DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN
|
||||
DEFINES += -DHAVE_FILTERS_BUILTIN
|
||||
DEFINES := -DRARCH_INTERNAL -DHAVE_MAIN -DEMSCRIPTEN
|
||||
DEFINES += -DHAVE_FILTERS_BUILTIN -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORE_INFO
|
||||
|
||||
HAVE_STATESTREAM ?= 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_DSP_FILTER = 1
|
||||
HAVE_VIDEO_FILTER = 1
|
||||
HAVE_OVERLAY = 1
|
||||
HAVE_NETWORKING ?= 1
|
||||
HAVE_LIBRETRODB = 1
|
||||
HAVE_COMPRESSION = 1
|
||||
HAVE_UPDATE_ASSETS = 1
|
||||
HAVE_ONLINE_UPDATER = 1
|
||||
HAVE_GLSL = 1
|
||||
HAVE_SCREENSHOTS = 1
|
||||
HAVE_REWIND = 1
|
||||
HAVE_AUDIOMIXER = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_EGL = 1
|
||||
HAVE_CC_RESAMPLER ?= 1
|
||||
HAVE_EGL ?= 0
|
||||
HAVE_OPENGLES = 1
|
||||
HAVE_RJPEG = 0
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RJPEG = 0
|
||||
HAVE_RPNG = 1
|
||||
HAVE_EMSCRIPTEN = 1
|
||||
HAVE_MENU = 1
|
||||
HAVE_MENU ?= 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_RGUI = 1
|
||||
HAVE_SDL = 0
|
||||
@@ -41,91 +46,234 @@ HAVE_STATIC_AUDIO_FILTERS = 1
|
||||
HAVE_STB_FONT = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_COMMAND = 1
|
||||
HAVE_STDIN_CMD = 1
|
||||
HAVE_STDIN_CMD ?= 1
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_IBXM = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
HAVE_7ZIP = 1
|
||||
HAVE_BSV_MOVIE = 1
|
||||
HAVE_AL = 1
|
||||
HAVE_CHD ?= 0
|
||||
HAVE_NETPLAYDISCOVERY ?= 0
|
||||
|
||||
# WARNING -- READ BEFORE ENABLING
|
||||
# The rwebaudio driver is known to have several audio bugs, such as
|
||||
# minor crackling, or the entire page freezing/crashing.
|
||||
# It works perfectly on chrome, but even firefox has really bad audio quality.
|
||||
# I should also note, the driver on iOS is completely broken (crashes the page).
|
||||
# You have been warned.
|
||||
HAVE_RWEBAUDIO = 0
|
||||
# enables pthreads, requires special headers on the web server:
|
||||
# see https://web.dev/articles/coop-coep
|
||||
HAVE_THREADS ?= 0
|
||||
|
||||
# requires HAVE_THREADS
|
||||
HAVE_AUDIOWORKLET ?= 0
|
||||
|
||||
# doesn't work on PROXY_TO_PTHREAD
|
||||
HAVE_RWEBAUDIO ?= 1
|
||||
|
||||
# requires ASYNC or PROXY_TO_PTHREAD
|
||||
HAVE_AL ?= 0
|
||||
|
||||
# whether the browser thread is allowed to block to wait for audio to play, not CPU usage-friendly!
|
||||
# currently this variable is only used by rwebaudio and audioworklet; openal will never busywait.
|
||||
ALLOW_AUDIO_BUSYWAIT ?= 0
|
||||
|
||||
# minimal asyncify; better performance than full asyncify,
|
||||
# but sleeping on the main thread is only possible in some places.
|
||||
MIN_ASYNC ?= 0
|
||||
|
||||
# runs RetroArch on a pthread instead of the browser thread; requires HAVE_THREADS
|
||||
PROXY_TO_PTHREAD ?= 0
|
||||
|
||||
# recommended FS when using HAVE_THREADS
|
||||
HAVE_WASMFS ?= 0
|
||||
|
||||
# enables OPFS (origin private file system) and FETCHFS, requires PROXY_TO_PTHREAD
|
||||
HAVE_EXTRA_WASMFS ?= 0
|
||||
|
||||
# enable javascript filesystem tracking, incompatible with HAVE_WASMFS
|
||||
FS_DEBUG ?= 0
|
||||
|
||||
# help diagnose GL problems (can cause issues in normal operation)
|
||||
GL_DEBUG ?= 0
|
||||
|
||||
# does nothing on its own, but automatically selected by some other options
|
||||
WASM_WORKERS = 0
|
||||
|
||||
HAVE_OPENGLES ?= 1
|
||||
HAVE_OPENGLES3 ?= 0
|
||||
|
||||
ASYNC ?= 0
|
||||
ifeq ($(LIBRETRO), mupen64plus)
|
||||
ASYNC = 1
|
||||
endif
|
||||
|
||||
LTO ?= 0
|
||||
ifeq ($(LIBRETRO), tyrquake)
|
||||
LTO = 0
|
||||
endif
|
||||
PTHREAD_POOL_SIZE ?= 4
|
||||
|
||||
PTHREAD ?= 0
|
||||
ASYNCIFY_ADD ?= dynCall_*,emscripten_mainloop
|
||||
ASYNCIFY_REMOVE ?= threaded_worker
|
||||
|
||||
MEMORY ?= 134217728
|
||||
STACK_SIZE ?= 4194304
|
||||
INITIAL_HEAP ?= 134217728
|
||||
|
||||
PRECISE_F32 = 1
|
||||
# 4194304 ----- 4 MiB (Stack: recommended)
|
||||
# 8388608 ----- 8 MiB
|
||||
# 16777216 ---- 16 MiB
|
||||
# 33554432 ---- 32 MiB
|
||||
# 67108864 ---- 64 MiB
|
||||
# 134217728 --- 128 MiB (Heap: recommended) (Stack: recommended for some cores [mupen64plus_next])
|
||||
# 268435456 --- 256 MiB (Heap: recommended for some cores [mupen64plus_next])
|
||||
# 536870912 --- 512 MiB (Heap: needed for some cores [mednafen_psx(_hw)])
|
||||
# 1073741824 -- 1 GiB
|
||||
# 1610612736 -- 1.5 GiB
|
||||
# 2147483648 -- 2 GiB
|
||||
|
||||
OBJDIR := obj-emscripten
|
||||
|
||||
#if you compile with SDL2 flag add this Emscripten flag "-s USE_SDL=2" to LDFLAGS:
|
||||
EXPORTED_FUNCTIONS = _main,_malloc,_free,_cmd_savefiles,_cmd_save_state,_cmd_load_state,_cmd_undo_save_state,_cmd_undo_load_state,_cmd_toggle_fullscreen,_cmd_take_screenshot,\
|
||||
_cmd_toggle_menu,_cmd_reload_config,_cmd_toggle_grab_mouse,_cmd_toggle_game_focus,_cmd_reset,_cmd_toggle_pause,_cmd_pause,_cmd_unpause,\
|
||||
_cmd_set_volume,_cmd_set_shader,_cmd_cheat_set_code,_cmd_cheat_get_code,_cmd_cheat_toggle_index,_cmd_cheat_get_code_state,_cmd_cheat_realloc,\
|
||||
_cmd_cheat_get_size,_cmd_cheat_apply_cheats,EmscriptenSendCommand,EmscriptenReceiveCommandReply
|
||||
|
||||
LIBS := -s USE_ZLIB=1
|
||||
LDFLAGS := -L. --no-heap-copy -s $(LIBS) -s TOTAL_MEMORY=$(MEMORY) -s NO_EXIT_RUNTIME=0 -s FULL_ES2=1 \
|
||||
-s "EXPORTED_RUNTIME_METHODS=['callMain', 'FS', 'PATH', 'ERRNO_CODES']" \
|
||||
-s ALLOW_MEMORY_GROWTH=1 -s "EXPORTED_FUNCTIONS=['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_load_state', '_cmd_take_screenshot']" \
|
||||
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
|
||||
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1 \
|
||||
--js-library emscripten/library_errno_codes.js \
|
||||
--js-library emscripten/library_rwebcam.js
|
||||
EXPORTS := callMain,FS,PATH,ERRNO_CODES,ENV,stringToNewUTF8,UTF8ToString,Browser,EmscriptenSendCommand,EmscriptenReceiveCommandReply
|
||||
|
||||
ifeq ($(HAVE_RWEBAUDIO), 1)
|
||||
LDFLAGS += --js-library emscripten/library_rwebaudio.js
|
||||
DEFINES += -DHAVE_RWEBAUDIO
|
||||
endif
|
||||
ifeq ($(HAVE_AL), 1)
|
||||
LDFLAGS += -lopenal
|
||||
DEFINES += -DHAVE_AL
|
||||
ASYNC = 1
|
||||
endif
|
||||
LIBS := -s USE_ZLIB=1
|
||||
CFLAGS := -s USE_ZLIB=1
|
||||
|
||||
ifneq ($(PTHREAD), 0)
|
||||
LDFLAGS += -s WASM_MEM_MAX=1073741824 -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD)
|
||||
CFLAGS += -pthread
|
||||
HAVE_THREADS=1
|
||||
else
|
||||
HAVE_THREADS=0
|
||||
endif
|
||||
|
||||
ifeq ($(ASYNC), 1)
|
||||
LDFLAGS += -s ASYNCIFY=$(ASYNC) -s ASYNCIFY_STACK_SIZE=8192
|
||||
ifeq ($(DEBUG), 1)
|
||||
LDFLAGS += -s ASYNCIFY_DEBUG=1 # -s ASYNCIFY_ADVISE
|
||||
ifeq ($(HAVE_EXTRA_WASMFS), 1)
|
||||
LIBS += -lfetchfs.js -lopfs.js
|
||||
DEFINES += -DHAVE_EXTRA_WASMFS
|
||||
override HAVE_WASMFS = 1
|
||||
ifeq ($(PROXY_TO_PTHREAD), 0)
|
||||
$(error ERROR: HAVE_EXTRA_WASMFS requires PROXY_TO_PTHREAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_WASMFS), 1)
|
||||
LIBS += -s WASMFS -s FORCE_FILESYSTEM=1
|
||||
endif
|
||||
|
||||
# note: real PROXY_TO_PTHREAD is not used here; we do the pthread management ourselves
|
||||
ifeq ($(PROXY_TO_PTHREAD), 1)
|
||||
LIBS += -s OFFSCREENCANVAS_SUPPORT
|
||||
DEFINES += -DPROXY_TO_PTHREAD -DEMSCRIPTEN_STACK_SIZE=$(STACK_SIZE)
|
||||
override HAVE_THREADS = 1
|
||||
override WASM_WORKERS = 1
|
||||
# use the default stack size for the browser thread; the RetroArch thread will be created with the specified stack size
|
||||
override STACK_SIZE = 4194304
|
||||
else ifeq ($(HAVE_AL), 1)
|
||||
override ASYNC = 1
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SDL2), 1)
|
||||
LIBS += -s USE_SDL=2
|
||||
DEFINES += -DHAVE_SDL2
|
||||
endif
|
||||
|
||||
LDFLAGS := -L. --no-heap-copy -s STACK_SIZE=$(STACK_SIZE) -s INITIAL_MEMORY=$(INITIAL_HEAP) \
|
||||
-s EXPORTED_RUNTIME_METHODS=$(EXPORTS) -s EXIT_RUNTIME=1 \
|
||||
-s ALLOW_MEMORY_GROWTH=1 -s EXPORTED_FUNCTIONS="$(EXPORTED_FUNCTIONS)" \
|
||||
-s MODULARIZE=1 -s EXPORT_ES6=1 -s EXPORT_NAME="libretro_$(subst -,_,$(LIBRETRO))" \
|
||||
-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=0 \
|
||||
-s ENVIRONMENT=web,worker -s WASM_BIGINT=1 \
|
||||
--extern-pre-js emscripten/pre.js \
|
||||
--js-library emscripten/library_rwebcam.js \
|
||||
--js-library emscripten/library_platform_emscripten.js
|
||||
|
||||
ifeq ($(HAVE_OPENGLES), 1)
|
||||
ifeq ($(HAVE_OPENGLES3), 1)
|
||||
LDFLAGS += -s FULL_ES3=1 -s MIN_WEBGL_VERSION=2 -s MAX_WEBGL_VERSION=2
|
||||
else
|
||||
LDFLAGS += -s FULL_ES2=1 -s MIN_WEBGL_VERSION=1 -s MAX_WEBGL_VERSION=2
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(GL_DEBUG), 1)
|
||||
LDFLAGS += -s GL_ASSERTIONS=1 -s GL_DEBUG=1
|
||||
DEFINES += -DHAVE_GL_DEBUG_ES=1
|
||||
endif
|
||||
|
||||
ifeq ($(FS_DEBUG), 1)
|
||||
LDFLAGS += -s FS_DEBUG=1
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_RWEBAUDIO), 1)
|
||||
LDFLAGS += --js-library emscripten/library_rwebaudio.js
|
||||
DEFINES += -DHAVE_RWEBAUDIO
|
||||
ifeq ($(PROXY_TO_PTHREAD), 1)
|
||||
$(error ERROR: RWEBAUDIO is incompatible with PROXY_TO_PTHREAD)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_AUDIOWORKLET), 1)
|
||||
LDFLAGS += -s AUDIO_WORKLET=1
|
||||
DEFINES += -DHAVE_AUDIOWORKLET
|
||||
override WASM_WORKERS = 1
|
||||
ifeq ($(HAVE_THREADS), 0)
|
||||
$(error ERROR: AUDIOWORKLET requires HAVE_THREADS)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_AL), 1)
|
||||
LDFLAGS += -lopenal
|
||||
DEFINES += -DHAVE_AL
|
||||
endif
|
||||
|
||||
ifeq ($(PROXY_TO_PTHREAD), 1)
|
||||
else ifeq ($(ASYNC), 1)
|
||||
else
|
||||
DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_BLOCK
|
||||
ifeq ($(MIN_ASYNC), 1)
|
||||
DEFINES += -DEMSCRIPTEN_AUDIO_ASYNC_BLOCK
|
||||
else
|
||||
DEFINES += -DEMSCRIPTEN_AUDIO_FAKE_BLOCK
|
||||
endif
|
||||
ifneq ($(ALLOW_AUDIO_BUSYWAIT), 1)
|
||||
DEFINES += -DEMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(ALLOW_AUDIO_BUSYWAIT), 1)
|
||||
DEFINES += -DEMSCRIPTEN_AUDIO_BUSYWAIT
|
||||
endif
|
||||
|
||||
# explanation of some of these defines:
|
||||
# EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK: audio blocking occurs in the main loop instead of in the audio driver functions.
|
||||
# EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK: along with above, enables external blocking in the write function.
|
||||
# EMSCRIPTEN_AUDIO_BUSYWAIT: write function will busywait. init function may still use an external block.
|
||||
# EMSCRIPTEN_AUDIO_ASYNC_BLOCK: external block uses emscripten_sleep (requires MIN_ASYNC).
|
||||
# EMSCRIPTEN_AUDIO_FAKE_BLOCK: external block uses main loop timing (doesn't require asyncify).
|
||||
# when building with either PROXY_TO_PTHREAD or ASYNC (full asyncify), none of the above are required.
|
||||
|
||||
ifeq ($(HAVE_THREADS), 1)
|
||||
LDFLAGS += -pthread -s PTHREAD_POOL_SIZE=$(PTHREAD_POOL_SIZE)
|
||||
CFLAGS += -pthread -s SHARED_MEMORY
|
||||
endif
|
||||
|
||||
ifeq ($(WASM_WORKERS), 1)
|
||||
LDFLAGS += -s WASM_WORKERS=1
|
||||
endif
|
||||
|
||||
ifeq ($(ASYNC), 1)
|
||||
DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_FULL_ASYNCIFY
|
||||
LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192
|
||||
ifeq ($(DEBUG), 1)
|
||||
#LDFLAGS += -s ASYNCIFY_DEBUG=1 # broken?
|
||||
endif
|
||||
else ifeq ($(MIN_ASYNC), 1)
|
||||
DEFINES += -DEMSCRIPTEN_ASYNCIFY -DEMSCRIPTEN_MIN_ASYNCIFY
|
||||
LDFLAGS += -s ASYNCIFY=1 -s ASYNCIFY_STACK_SIZE=8192 -s ASYNCIFY_IGNORE_INDIRECT=1 -s ASYNCIFY_ADD='$(ASYNCIFY_ADD)' -s ASYNCIFY_REMOVE='$(ASYNCIFY_REMOVE)'
|
||||
ifeq ($(DEBUG), 1)
|
||||
LDFLAGS += -s ASYNCIFY_ADVISE #-s ASYNCIFY_DEBUG=1
|
||||
endif
|
||||
endif
|
||||
|
||||
include Makefile.common
|
||||
|
||||
CFLAGS += $(DEF_FLAGS) -Ideps -Ideps/stb
|
||||
DEF_FLAGS += $(INCLUDE_DIRS) -Ideps -Ideps/stb
|
||||
|
||||
libretro :=
|
||||
CFLAGS += $(DEF_FLAGS)
|
||||
CXXFLAGS += $(DEF_FLAGS) -D__STDC_CONSTANT_MACROS
|
||||
|
||||
libretro =
|
||||
libretro_new =
|
||||
|
||||
ifeq ($(HAVE_STATIC_DUMMY),1)
|
||||
DEFINES += -DHAVE_STATIC_DUMMY
|
||||
else
|
||||
libretro += libretro_emscripten.bc
|
||||
libretro = libretro_emscripten.bc
|
||||
libretro_new = libretro_emscripten.a
|
||||
endif
|
||||
|
||||
ifneq ($(V), 1)
|
||||
@@ -133,46 +281,45 @@ ifneq ($(V), 1)
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
||||
CFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=1 -s SAFE_HEAP_LOG=1 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
||||
LDFLAGS += -O0 -g -gsource-map -s SAFE_HEAP=2 -s STACK_OVERFLOW_CHECK=2 -s ASSERTIONS=1
|
||||
# -O0 in cflags gives "too many locals" errors
|
||||
CFLAGS += -O1 -g -gsource-map
|
||||
else
|
||||
LDFLAGS += -O3 -s WASM=1
|
||||
LDFLAGS += -O3
|
||||
# WARNING: some optimizations can break some cores (ex: LTO breaks tyrquake)
|
||||
LDFLAGS += -s PRECISE_F32=$(PRECISE_F32)
|
||||
ifeq ($(LTO), 1)
|
||||
LDFLAGS += --llvm-lto 3
|
||||
LDFLAGS += -flto
|
||||
endif
|
||||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
# 128 * 1024, double the usual emscripten stack size
|
||||
LDFLAGS += -s STACK_SIZE=131072
|
||||
|
||||
LDFLAGS += --extern-pre-js emscripten/pre.js
|
||||
|
||||
CFLAGS += -Wall -I. -Ilibretro-common/include -std=gnu99 #\
|
||||
# -s EXPORTED_FUNCTIONS="['_main', '_malloc', '_cmd_savefiles', '_cmd_save_state', '_cmd_take_screenshot']"
|
||||
CFLAGS += -Wall -I. -Ilibretro-common/include -Ideps/7zip -std=gnu99
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
$(TARGET): $(RARCH_OBJ) $(libretro)
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro) $(LIBS) $(LDFLAGS)
|
||||
$(libretro_new): ;
|
||||
|
||||
mv_libretro:
|
||||
$(Q)mv -f $(libretro) $(libretro_new) || true
|
||||
|
||||
$(TARGET): $(RARCH_OBJ) $(libretro_new) mv_libretro
|
||||
@$(if $(Q), $(shell echo echo "LD $@ \<obj\> $(libretro_new) $(LIBS) $(LDFLAGS)"),)
|
||||
$(Q)$(LD) -o $@ $(RARCH_OBJ) $(libretro_new) $(LIBS) $(LDFLAGS)
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
|
||||
$(Q)$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) $(EOPTS) -c -o $@ $<
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR)
|
||||
rm -f $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean mv_libretro
|
||||
@@ -116,6 +116,7 @@ else ifeq ($(platform), ps3-cobra)
|
||||
# NGC/Wii - libogc
|
||||
else ifeq ($(libogc_platform), 1)
|
||||
EXTERNAL_LIBOGC ?= 0
|
||||
HAVE_OGG_OGC ?= 0
|
||||
GX_PTHREAD_LEGACY ?= 1
|
||||
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
|
||||
@@ -183,6 +184,10 @@ else ifeq ($(libogc_platform), 1)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OGG_OGC), 1)
|
||||
LIBS += -L$(DEVKITPRO)/portlibs/ppc/lib -lvorbisfile -lvorbis -logg
|
||||
endif
|
||||
|
||||
ifeq ($(EXTERNAL_LIBOGC), 1)
|
||||
LIBS += -lfat
|
||||
endif
|
||||
|
||||
+4
-2
@@ -57,6 +57,8 @@ HAVE_CHD = 1
|
||||
HAVE_STB_VORBIS = 1
|
||||
HAVE_IBXM = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
HAVE_CLOUD_SYNC = 1
|
||||
HAVE_SSL = 1
|
||||
|
||||
# RetroArch libnx useful flags
|
||||
HAVE_THREADS = 1
|
||||
@@ -127,7 +129,7 @@ APP_ICON := pkg/libnx/retroarch.jpg
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE -mcpu=cortex-a57+crc+fp+simd
|
||||
|
||||
CFLAGS := -g -Wall -O3 -fcommon -ffast-math -ffunction-sections \
|
||||
CFLAGS := -g -Wall -O3 -fcommon -ffunction-sections \
|
||||
$(ARCH) $(DEFINES) $(INCLUDE_DIRS) -I$(LIBNX)/include -I$(PORTLIBS)/include/ -include $(LIBNX)/include/switch.h #$(shell $(PORTLIBS)/bin/freetype-config --cflags)
|
||||
|
||||
CFLAGS += $(INCLUDE) -DSWITCH=1 -DHAVE_LIBNX=1 -DNXLINK=1 -DHAVE_SHADERPIPELINE -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES -DHAVE_UPDATE_CORE_INFO -DHAVE_STB_FONT #-DHAVE_FREETYPE
|
||||
@@ -148,7 +150,7 @@ LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs $(ARCH) -Wl,--allow-multiple-de
|
||||
# add things from Makefile.common
|
||||
CFLAGS += $(DEF_FLAGS)
|
||||
|
||||
LIBS := -lswresample -lavformat -lavcodec -lavutil -lswscale -lstdc++ -lbz2 -lpng -lz -lnx -lvpx -lopus -llzma -lm
|
||||
LIBS := -lswresample -lavformat -lavcodec -lavutil -lswscale -lstdc++ -lbz2 -lpng -lz -lnx -lvpx -lopus -llzma -lmbedtls -lmbedx509 -lmbedcrypto -lnx -lm
|
||||
|
||||
ifeq ($(HAVE_OPENGL), 1)
|
||||
LIBS := -lEGL -lglapi -ldrm_nouveau $(LIBS)
|
||||
|
||||
+30
-5
@@ -118,7 +118,7 @@ TARGET = retroarch
|
||||
|
||||
OBJ :=
|
||||
LINK := $(CXX)
|
||||
DEF_FLAGS := -march=armv5te -mtune=arm926ej-s -ffast-math -fomit-frame-pointer
|
||||
DEF_FLAGS := -march=armv5te -mtune=arm926ej-s -fomit-frame-pointer
|
||||
DEF_FLAGS += -ffunction-sections -fdata-sections
|
||||
DEF_FLAGS += -I. -Ideps -Ideps/stb -DMIYOO=1 -DDINGUX -MMD
|
||||
DEF_FLAGS += -Wall -Wno-unused-variable -flto
|
||||
@@ -160,12 +160,36 @@ CXXFLAGS += $(DEF_FLAGS)
|
||||
|
||||
HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
Q := @
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CPPFLAGS: $(CPPFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBRARY_DIRS: $(LIBRARY_DIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
OBJCFLAGS: $(OBJCFLAGS)
|
||||
RARCH_OBJ: $(RARCH_OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
-include $(RARCH_OBJ:.o=.d)
|
||||
|
||||
SYMBOL_MAP := -Wl,-Map=output.map
|
||||
@@ -199,9 +223,10 @@ $(OBJDIR)/%.o: %.S $(HEADERS)
|
||||
$(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR_BASE)
|
||||
rm -f $(TARGET)
|
||||
rm -f *.d
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -rf $(OBJDIR_BASE)
|
||||
$(Q)rm -f $(TARGET)
|
||||
$(Q)rm -f *.d
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
|
||||
+44
-8
@@ -58,6 +58,7 @@ LIBS := $(WHOLE_START) $(LIB_CORE) $(WHOLE_END)
|
||||
libogc_platform := 1
|
||||
|
||||
EXTERNAL_LIBOGC ?= 0
|
||||
HAVE_OGG_OGC ?= 0
|
||||
GX_PTHREAD_LEGACY ?= 1
|
||||
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
|
||||
@@ -102,6 +103,10 @@ ifeq ($(BIG_STACK), 1)
|
||||
LDFLAGS += -T bootstrap/gx/ogc.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OGG_OGC), 1)
|
||||
LIBS += -L$(DEVKITPRO)/portlibs/ppc/lib -lvorbisfile -lvorbis -logg
|
||||
endif
|
||||
|
||||
ifeq ($(EXTERNAL_LIBOGC), 1)
|
||||
LIBS += -lfat
|
||||
endif
|
||||
@@ -233,34 +238,65 @@ else
|
||||
CFLAGS += -O3
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
OBJOUT = -o
|
||||
LINKOUT = -o
|
||||
LINK = $(CXX)
|
||||
|
||||
all: $(EXT_TARGET)
|
||||
|
||||
define INFO
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
LD: $(LD)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
LINKOUT: $(LINKOUT)
|
||||
OBJ: $(OBJ)
|
||||
OBJOUT: $(OBJOUT)
|
||||
PLATEXTRA: $(PLATEXTRA)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
%.dol: %.elf
|
||||
$(ELF2DOL) $< $@
|
||||
|
||||
$(EXT_INTER_TARGET): $(OBJ)
|
||||
$(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS)
|
||||
@$(if $(Q), $(shell echo echo LINK $@),)
|
||||
$(Q)$(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.binobj: %.bin
|
||||
$(LD) -r -b binary $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LD) -r -b binary $(OBJOUT)$@ $<
|
||||
|
||||
clean:
|
||||
rm -f $(EXT_TARGET)
|
||||
rm -f $(EXT_INTER_TARGET)
|
||||
rm -f $(OBJ)
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -f $(EXT_TARGET)
|
||||
$(Q)rm -f $(EXT_INTER_TARGET)
|
||||
$(Q)rm -f $(OBJ)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
||||
+37
-8
@@ -176,38 +176,67 @@ else
|
||||
CXXFLAGS += -O3
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
TARGETS := $(TARGET).self
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
define INFO
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
LD: $(LD)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBS: $(LIBS)
|
||||
OBJ: $(OBJ)
|
||||
OBJOUT: $(OBJOUT)
|
||||
ORBISDEV: $(ORBISDEV)
|
||||
TARGET: $(TARGET)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
OBJOUT = -o
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CXXFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.s
|
||||
$(CC) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c $(OBJOUT)$@ $<
|
||||
|
||||
$(TARGET).elf: $(OBJ)
|
||||
$(LD) $(ORBISDEV)/usr/lib/crt0.o $(OBJ) $(LDFLAGS) $(LIBS) -o $(TARGET).elf
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LD) $(ORBISDEV)/usr/lib/crt0.o $(OBJ) $(LDFLAGS) $(LIBS) -o $(TARGET).elf
|
||||
|
||||
$(TARGET).oelf: $(TARGET).elf
|
||||
@orbis-elf-create $(TARGET).elf $(TARGET).oelf
|
||||
orbis-elf-create $(TARGET).elf $(TARGET).oelf
|
||||
|
||||
$(TARGET).self: $(TARGET).oelf
|
||||
python $(ORBISDEV)/bin/make_fself.py --auth-info $(AUTH_INFO) $(TARGET).oelf $(TARGET).self
|
||||
|
||||
install:
|
||||
@cp $(TARGET).self $(SELF_PATH_INSTALL)/homebrew.self
|
||||
cp $(TARGET).self $(SELF_PATH_INSTALL)/homebrew.self
|
||||
@echo "Installed!"
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET).elf $(TARGET).oelf $(TARGET).self
|
||||
$(Q)rm -f $(OBJ) $(TARGET).elf $(TARGET).oelf $(TARGET).self
|
||||
|
||||
.PHONY: clean all
|
||||
+35
-2
@@ -83,6 +83,10 @@ ifeq ($(strip $(PS2SDK)),)
|
||||
$(error "Please set PS2SDK in your environment. export PS2SDK=<path to>ps2sdk")
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
INCDIR = -I$(PS2DEV)/gsKit/include -I$(PS2SDK)/ports/include
|
||||
INCDIR += -Ilibretro-common/include -Ideps -Ideps/stb -Ideps/7zip
|
||||
|
||||
@@ -90,7 +94,7 @@ LDFLAGS += -L$(PS2DEV)/gsKit/lib -L$(PS2SDK)/ports/lib -L.
|
||||
# Lib cdvd is needed to get proper time
|
||||
LIBS += -lpatches -lgskit -ldmakit -lps2_drivers -lz -lelf-loader
|
||||
|
||||
CFLAGS = $(OPTIMIZE_LV) $(DISABLE_WARNINGS) $(DEFINES) -DPS2 -ffast-math -fsingle-precision-constant
|
||||
CFLAGS = $(OPTIMIZE_LV) $(DISABLE_WARNINGS) $(DEFINES) -DPS2 -fsingle-precision-constant
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
EE_OBJS += $(OBJ)
|
||||
@@ -106,8 +110,25 @@ EE_GPVAL = $(GPVAL)
|
||||
|
||||
all: $(EE_BIN)
|
||||
|
||||
define INFO
|
||||
EE_BIN: $(EE_BIN)
|
||||
EE_CC: $(EE_CC)
|
||||
EE_CFLAGS: $(EE_CFLAGS)
|
||||
EE_CXX: $(EE_CXX)
|
||||
EE_CXXFLAGS: $(EE_CXXFLAGS)
|
||||
EE_INCS: $(EE_INCS)
|
||||
EE_OBJS: $(EE_OBJS)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f $(EE_BIN) $(EE_OBJS)
|
||||
@$(if $(Q), $(shell echo echo RM $<),)
|
||||
$(Q)rm -f $(EE_BIN) $(EE_OBJS)
|
||||
|
||||
prepare:
|
||||
ps2client -h $(PS2_IP) reset
|
||||
@@ -131,3 +152,15 @@ release: all
|
||||
#Include preferences
|
||||
include $(PS2SDK)/samples/Makefile.pref
|
||||
include $(PS2SDK)/samples/Makefile.eeglobal_cpp
|
||||
|
||||
%.o: %.c
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(EE_CC) $(EE_CFLAGS) $(EE_INCS) -c $< -o $@
|
||||
|
||||
%.o: %.cc
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(EE_CXX) $(EE_CXXFLAGS) $(EE_INCS) -c $< -o $@
|
||||
@@ -21,7 +21,7 @@ endif
|
||||
|
||||
INCDIR = -Ilibretro-common/include
|
||||
INCDIR += -I$(PS2SDK)/ports/include
|
||||
CFLAGS = $(OPTIMIZE_LV) $(DISABLE_WARNINGS) -ffast-math -fsingle-precision-constant
|
||||
CFLAGS = $(OPTIMIZE_LV) $(DISABLE_WARNINGS) -fsingle-precision-constant
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
RARCH_DEFINES += -DPS2 -DIS_SALAMANDER -DRARCH_CONSOLE
|
||||
|
||||
+34
-7
@@ -6,7 +6,7 @@
|
||||
ifeq ($(strip $(PSL1GHT)),)
|
||||
$(error "Please set PSL1GHT in your environment. export PSL1GHT=<path>")
|
||||
endif
|
||||
|
||||
|
||||
include $(PSL1GHT)/ppu_rules
|
||||
|
||||
include version.all
|
||||
@@ -30,10 +30,17 @@ CORE_PATH = pkg/psl1ght/pkg/USRDIR/cores/CORE.SELF
|
||||
INCLUDE += -I. -Ideps -Ideps/stb -Ilibretro-common/include/compat/zlib -Ilibretro-common/include $(LIBPSL1GHT_INC) -Iinclude -Idefines -I$(PORTLIBS)/include -I$(PORTLIBS)/include/freetype2
|
||||
LIBDIRS += -L. -L$(PORTLIBS)/lib
|
||||
|
||||
ifeq ($(HAVE_STATIC_DUMMY),1)
|
||||
DEFINES += -DHAVE_STATIC_DUMMY
|
||||
LIBS :=
|
||||
else
|
||||
LIBS := -lretro_psl1ght
|
||||
endif
|
||||
|
||||
MACHDEP := -D__PSL1GHT__ -D__PS3__ -mcpu=cell
|
||||
CFLAGS += -Wall $(MACHDEP) $(INCLUDE)
|
||||
CFLAGS += -Wall $(DEFINES) $(MACHDEP) $(INCLUDE)
|
||||
LDFLAGS := $(MACHDEP)
|
||||
LIBS := -lretro_psl1ght -lrt -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs -lfreetype -lcamera -lgem -lspurs
|
||||
LIBS += -lrt -laudio -lrsx -lgcm_sys -lnet -lio -lsysutil -lsysmodule -lm -ljpgdec -lpngdec -llv2 -lnet -lnetctl -lsysfs -lfreetype -lcamera -lgem -lspurs
|
||||
|
||||
# system platform
|
||||
system_platform = unix
|
||||
@@ -119,13 +126,32 @@ else
|
||||
CXXFLAGS += -03 -g
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
all: $(SELF_TARGET)
|
||||
|
||||
define INFO
|
||||
CXX: $(CXX)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
OBJ: $(OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
$(ELF_TARGET): $(OBJ)
|
||||
$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(LIBS)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) -o $@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(LIBS)
|
||||
|
||||
create-core: $(SELF_TARGET)
|
||||
cp $(SELF_TARGET) $(CORE_PATH)
|
||||
cp $(SELF_TARGET) $(CORE_PATH)
|
||||
|
||||
pkg: create-core
|
||||
$(PKG) --contentid $(CONTENTID) pkg/psl1ght/pkg/ $(PACKAGE_BASENAME).pkg
|
||||
@@ -133,7 +159,8 @@ pkg: create-core
|
||||
# $(PACKAGE_FINALIZE) $(PACKAGE_BASENAME).gnpdrm.pkg
|
||||
|
||||
clean:
|
||||
rm -f $(ELF_TARGET)
|
||||
rm -f $(OBJ)
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -f $(ELF_TARGET)
|
||||
$(Q)rm -f $(OBJ)
|
||||
|
||||
.PHONY: clean
|
||||
+1
-1
@@ -16,7 +16,7 @@ else
|
||||
endif
|
||||
|
||||
INCDIR = deps deps/stb deps/7zip libretro-common/include libretro-common/include/compat/zlib
|
||||
CFLAGS = $(OPTIMIZE_LV) -ffast-math -fsingle-precision-constant
|
||||
CFLAGS = $(OPTIMIZE_LV) -fsingle-precision-constant
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
RARCH_DEFINES = -DPSP \
|
||||
|
||||
@@ -12,7 +12,7 @@ else
|
||||
endif
|
||||
|
||||
INCDIR = $(PSPPATH)/include libretro-common/include
|
||||
CFLAGS = $(OPTIMIZE_LV) -ffast-math -fsingle-precision-constant
|
||||
CFLAGS = $(OPTIMIZE_LV) -fsingle-precision-constant
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
RARCH_DEFINES = -DPSP -DIS_SALAMANDER -DRARCH_CONSOLE
|
||||
|
||||
+31
-7
@@ -120,7 +120,7 @@ OPK_NAME = retroarch_retrofw.opk
|
||||
|
||||
OBJ :=
|
||||
LINK := $(CXX)
|
||||
DEF_FLAGS := -march=mips32 -mtune=mips32 -mhard-float -ffast-math -fomit-frame-pointer
|
||||
DEF_FLAGS := -march=mips32 -mtune=mips32 -mhard-float -fomit-frame-pointer
|
||||
DEF_FLAGS += -mplt -mno-shared
|
||||
DEF_FLAGS += -ffunction-sections -fdata-sections
|
||||
DEF_FLAGS += -I. -Ideps -Ideps/stb -DDINGUX=1 -DRETROFW=1 -MMD
|
||||
@@ -164,7 +164,9 @@ CXXFLAGS += $(DEF_FLAGS)
|
||||
|
||||
HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
Q := @
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
@@ -182,9 +184,30 @@ X-OD-NeedsDownscaling=true
|
||||
endef
|
||||
export DESKTOP_ENTRY
|
||||
|
||||
|
||||
all: $(TARGET) opk
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CPPFLAGS: $(CPPFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBRARY_DIRS: $(LIBRARY_DIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
OBJCFLAGS: $(OBJCFLAGS)
|
||||
RARCH_OBJ: $(RARCH_OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
-include $(RARCH_OBJ:.o=.d)
|
||||
|
||||
SYMBOL_MAP := -Wl,-Map=output.map
|
||||
@@ -214,10 +237,11 @@ $(OBJDIR)/%.o: %.S $(HEADERS)
|
||||
$(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR_BASE)
|
||||
rm -f $(TARGET)
|
||||
rm -f *.d
|
||||
rm -rf $(OPK_NAME)
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -rf $(OBJDIR_BASE)
|
||||
$(Q)rm -f $(TARGET)
|
||||
$(Q)rm -f *.d
|
||||
$(Q)rm -rf $(OPK_NAME)
|
||||
|
||||
opk: $(TARGET)
|
||||
echo "$$DESKTOP_ENTRY" > default.retrofw.desktop
|
||||
|
||||
+30
-5
@@ -166,7 +166,9 @@ CXXFLAGS += $(DEF_FLAGS)
|
||||
|
||||
HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
Q := @
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
@@ -186,6 +188,28 @@ export DESKTOP_ENTRY
|
||||
|
||||
all: $(TARGET) opk
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CPPFLAGS: $(CPPFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBRARY_DIRS: $(LIBRARY_DIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
OBJCFLAGS: $(OBJCFLAGS)
|
||||
RARCH_OBJ: $(RARCH_OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
-include $(RARCH_OBJ:.o=.d)
|
||||
|
||||
SYMBOL_MAP := -Wl,-Map=output.map
|
||||
@@ -215,10 +239,11 @@ $(OBJDIR)/%.o: %.S $(HEADERS)
|
||||
$(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR_BASE)
|
||||
rm -f $(TARGET)
|
||||
rm -f *.d
|
||||
rm -rf $(OPK_NAME)
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -rf $(OBJDIR_BASE)
|
||||
$(Q)rm -f $(TARGET)
|
||||
$(Q)rm -f *.d
|
||||
$(Q)rm -rf $(OPK_NAME)
|
||||
|
||||
opk: $(TARGET)
|
||||
echo "$$DESKTOP_ENTRY" > default.rs90.desktop
|
||||
|
||||
+47
-15
@@ -138,7 +138,7 @@ ifeq ($(HAVE_VITAGLES), 1)
|
||||
ARCHFLAGS += -DSCE_LIBC_SIZE=$(SCE_LIBC_SIZE)
|
||||
endif
|
||||
|
||||
CFLAGS += $(ARCHFLAGS) -mword-relocations -fno-optimize-sibling-calls
|
||||
CFLAGS += $(ARCHFLAGS) -mword-relocations
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -g -Og
|
||||
@@ -147,9 +147,9 @@ else
|
||||
endif
|
||||
|
||||
ASFLAGS := $(CFLAGS)
|
||||
LDFLAGS := -Wl,-q
|
||||
LDFLAGS := -Wl,-q,--pic-veneer
|
||||
|
||||
CFLAGS += -Wall -ffast-math
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -DRARCH_INTERNAL -DHAVE_SCREENSHOTS -DRARCH_CONSOLE
|
||||
CFLAGS += -DHAVE_DSP_FILTER
|
||||
CFLAGS += -DHAVE_VIDEO_FILTER
|
||||
@@ -190,6 +190,10 @@ else
|
||||
LIBS += -lretro_vita
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
LIBS += $(WHOLE_END) $(VITA_LIBS) -lm -lc
|
||||
|
||||
TARGETS := $(TARGET).vpk
|
||||
@@ -199,25 +203,51 @@ POSTCOMPILE = mv -f $*.Tdepend $*.depend
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEPFLAGS: $(DEPFLAGS)
|
||||
INCDIRS: $(INCDIRS)
|
||||
LD: $(LD)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
OBJ: $(OBJ)
|
||||
POSTCOMPILE: $(POSTCOMPILE)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
%.o: %.cpp
|
||||
%.o: %.cpp %.depend
|
||||
$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(POSTCOMPILE)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) -c -o $@ $< $(CXXFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
%.o: %.c
|
||||
%.o: %.c %.depend
|
||||
$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(POSTCOMPILE)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(CFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
%.o: %.S
|
||||
%.o: %.S %.depend
|
||||
$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(POSTCOMPILE)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
%.o: %.s
|
||||
%.o: %.s %.depend
|
||||
$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(POSTCOMPILE)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) -c -o $@ $< $(ASFLAGS) $(INCDIRS) $(DEPFLAGS)
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
%.depend: ;
|
||||
|
||||
@@ -228,7 +258,8 @@ liblibScePiglet_stub.a:
|
||||
cp deps/Pigs-In-A-Blanket/piglet_stub/libScePiglet/liblibScePiglet_stub.a .
|
||||
|
||||
$(TARGET).elf: $(OBJ) liblibScePiglet_stub.a
|
||||
$(LD) $(OBJ) $(LDFLAGS) $(LIBDIRS) $(LIBS) -o $@
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LD) $(OBJ) $(LDFLAGS) $(LIBDIRS) $(LIBS) -o $@
|
||||
|
||||
%.velf: %.elf
|
||||
cp $< $<.unstripped.elf
|
||||
@@ -243,9 +274,10 @@ $(TARGET).elf: $(OBJ) liblibScePiglet_stub.a
|
||||
vita-pack-vpk -s param.sfo -b $< $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) $(TARGET).elf $(TARGET).elf.unstripped.elf $(TARGET).velf $(TARGET).self param.sfo $(TARGET).vpk
|
||||
rm -rf deps/Pigs-In-A-Blanket/piglet_stub/libScePiglet
|
||||
rm -f $(OBJ:.o=.depend)
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -f $(OBJ) $(TARGET).elf $(TARGET).elf.unstripped.elf $(TARGET).velf $(TARGET).self param.sfo $(TARGET).vpk
|
||||
$(Q)rm -rf deps/Pigs-In-A-Blanket/piglet_stub/libScePiglet
|
||||
$(Q)rm -f $(OBJ:.o=.depend)
|
||||
|
||||
# Useful for developers
|
||||
vpksend: $(TARGET).vpk
|
||||
|
||||
@@ -14,7 +14,7 @@ PREFIX = arm-vita-eabi
|
||||
CC = $(PREFIX)-gcc
|
||||
|
||||
INCDIR = libretro-common/include
|
||||
CFLAGS = -Wl,-q $(OPTIMIZE_LV) -I$(INCDIR) -std=gnu99 -mfloat-abi=hard -ffast-math -fsingle-precision-constant -mword-relocations
|
||||
CFLAGS = -Wl,-q $(OPTIMIZE_LV) -I$(INCDIR) -std=gnu99 -mfloat-abi=hard -fsingle-precision-constant -mword-relocations
|
||||
ASFLAGS = $(CFLAGS)
|
||||
|
||||
RARCH_DEFINES = -DVITA -DIS_SALAMANDER -DRARCH_CONSOLE
|
||||
|
||||
+327
-271
@@ -1,271 +1,327 @@
|
||||
include version.all
|
||||
|
||||
ifneq ($(CROSS_COMPILE),arm-webos-linux-gnueabi-)
|
||||
$(error You need webOS toolchain to build this. See https://github.com/webosbrew/native-toolchain)
|
||||
endif
|
||||
|
||||
ifdef SDKTARGETSYSROOT
|
||||
$(warning OE-based toolchain isn't supported anymore. Please use https://github.com/webosbrew/native-toolchain)
|
||||
STAGING_DIR = $(SDKTARGETSYSROOT)
|
||||
else ifndef STAGING_DIR
|
||||
$(error Can't find buildroot based toolchain. Please use https://github.com/webosbrew/native-toolchain)
|
||||
endif
|
||||
|
||||
WEBOS_FREETYPE_CONFIG ?= $(STAGING_DIR)/usr/bin/freetype-config
|
||||
|
||||
WEBOS_INC_DIR ?= $(STAGING_DIR)/usr/include
|
||||
WEBOS_LIB_DIR ?= $(STAGING_DIR)/usr/lib
|
||||
|
||||
ADD_SDL2_LIB ?= 0
|
||||
SDL2_PREBUILT_ARCHIVE ?= https://github.com/webosbrew/SDL-webOS/releases/download/release-2.30.0-webos.2/SDL2-2.30.0-webos.tar.gz
|
||||
|
||||
#########################
|
||||
#########################
|
||||
|
||||
PACKAGE_NAME = com.retroarch
|
||||
PACKAGE_VERSION := $(patsubst "%",%,$(RARCH_VERSION))
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
HAVE_CLOUDSYNC = 1
|
||||
HAVE_SCREENSHOTS = 1
|
||||
HAVE_REWIND = 1
|
||||
HAVE_7ZIP = 1
|
||||
HAVE_ACCESSIBILITY = 1
|
||||
HAVE_AL = 0
|
||||
# ALSA freezes when switching back from menu
|
||||
HAVE_ALSA = 0
|
||||
HAVE_ANGLE = 0
|
||||
HAVE_AUDIOIO = 0
|
||||
HAVE_AUDIOMIXER = 1
|
||||
HAVE_BLISSBOX = 0
|
||||
HAVE_BSV_MOVIE = 1
|
||||
HAVE_BUILTINBEARSSL = 0
|
||||
HAVE_BUILTINFLAC = 1
|
||||
HAVE_DSP_FILTER = 1
|
||||
HAVE_VIDEO_FILTER = 1
|
||||
HAVE_STATIC_VIDEO_FILTERS = 1
|
||||
HAVE_STATIC_AUDIO_FILTERS = 1
|
||||
HAVE_FILTERS_BUILTIN = 1
|
||||
HAVE_BUILTINMBEDTLS = 1
|
||||
HAVE_BUILTINZLIB = 1
|
||||
HAVE_C99 = 1
|
||||
HAVE_CC = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_NEAREST_RESAMPLER = 1
|
||||
HAVE_CHD = 1
|
||||
HAVE_COMMAND = 1
|
||||
HAVE_CXX = 1
|
||||
HAVE_DR_MP3 = 1
|
||||
HAVE_DYNAMIC = 1
|
||||
HAVE_DYLIB = 1
|
||||
HAVE_EGL = 0
|
||||
HAVE_FREETYPE = 0
|
||||
HAVE_GDI = 1
|
||||
HAVE_GETADDRINFO = 1
|
||||
HAVE_GETOPT_LONG = 1
|
||||
HAVE_GLSL = 1
|
||||
HAVE_GLSLANG = 0
|
||||
HAVE_GLSLANG_HLSL = 0
|
||||
HAVE_GLSLANG_OGLCOMPILER = 0
|
||||
HAVE_GLSLANG_OSDEPENDENT = 0
|
||||
HAVE_GLSLANG_SPIRV = 0
|
||||
HAVE_GLSLANG_SPIRV_TOOLS = 0
|
||||
HAVE_GLSLANG_SPIRV_TOOLS_OPT = 0
|
||||
HAVE_HID = 1
|
||||
HAVE_IBXM = 1
|
||||
HAVE_IMAGEVIEWER = 1
|
||||
HAVE_LANGEXTRA = 1
|
||||
HAVE_LIBRETRODB = 1
|
||||
HAVE_MENU = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_NEON = 1
|
||||
HAVE_NETWORKING = 1
|
||||
HAVE_IFINFO = 1
|
||||
HAVE_NETWORK_CMD = 1
|
||||
HAVE_NETPLAYDISCOVERY = 1
|
||||
HAVE_NETWORKGAMEPAD = 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_MMAP = 1
|
||||
HAVE_ONLINE_UPDATER = 1
|
||||
HAVE_OPENDINGUX_FBDEV = 0
|
||||
HAVE_OPENGL = 0
|
||||
HAVE_OPENGL1 = 0
|
||||
HAVE_OPENGL_CORE = 0
|
||||
HAVE_OPENGLES = 1
|
||||
HAVE_OPENGLES3 = 0
|
||||
HAVE_OPENGLES3_1 = 0
|
||||
HAVE_OPENGLES3_2 = 0
|
||||
HAVE_OPENSSL = 0
|
||||
HAVE_OVERLAY = 1
|
||||
HAVE_PULSE = 1
|
||||
HAVE_RBMP = 1
|
||||
HAVE_RJPEG = 1
|
||||
HAVE_RPILED = 0
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RUNAHEAD = 1
|
||||
HAVE_SDL = 0
|
||||
HAVE_SDL2 = 1
|
||||
HAVE_SHADERPIPELINE = 1
|
||||
HAVE_STB_FONT = 1
|
||||
HAVE_STB_IMAGE = 1
|
||||
HAVE_STB_VORBIS = 1
|
||||
HAVE_STDIN_CMD = 1
|
||||
HAVE_STRCASESTR = 1
|
||||
HAVE_THREADS = 1
|
||||
HAVE_UDEV = 0
|
||||
HAVE_RGUI = 1
|
||||
HAVE_MATERIALUI = 0
|
||||
HAVE_XMB = 1
|
||||
HAVE_OZONE = 1
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_CHEEVOS = 1
|
||||
HAVE_LIBSHAKE = 1
|
||||
HAVE_UPDATE_ASSETS = 1
|
||||
HAVE_UPDATE_CORES = 1
|
||||
HAVE_UPDATE_CORE_INFO = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
|
||||
OS = Linux
|
||||
TARGET = retroarch
|
||||
|
||||
OBJ :=
|
||||
LINK := $(CC)
|
||||
DEF_FLAGS += -ffunction-sections -fdata-sections
|
||||
DEF_FLAGS += -I. -Ideps -Ideps/stb -DWEBOS=1 -MMD
|
||||
DEF_FLAGS += -Wall -Wno-unused-variable
|
||||
LIBS := -ldl -lz -lrt -pthread
|
||||
CFLAGS :=
|
||||
CXXFLAGS := -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS
|
||||
ASFLAGS :=
|
||||
LDFLAGS := -Wl,-rpath=\$$ORIGIN/lib,--gc-sections
|
||||
INCLUDE_DIRS = -I$(WEBOS_INC_DIR)
|
||||
LIBRARY_DIRS = -L$(WEBOS_LIB_DIR)
|
||||
DEFINES := -DRARCH_INTERNAL -D_FILE_OFFSET_BITS=64 -UHAVE_STATIC_DUMMY
|
||||
DEFINES += -DHAVE_C99=1 -DHAVE_CXX=1 -D_GNU_SOURCE
|
||||
DEFINES += -DHAVE_GETOPT_LONG=1 -DHAVE_STRCASESTR=1 -DHAVE_DYNAMIC=1
|
||||
DEFINES += -DHAVE_FILTERS_BUILTIN
|
||||
DEFINES += -DHAVE_SDL2
|
||||
DEFINES += -DHAVE_PULSE
|
||||
DEFINES += -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES
|
||||
DEFINES += -DHAVE_UPDATE_CORE_INFO
|
||||
|
||||
PKG_CONFIG=pkg-config
|
||||
|
||||
SDL2_CFLAGS := $(shell $(PKG_CONFIG) --cflags sdl2)
|
||||
SDL2_LIBS := $(shell $(PKG_CONFIG) --libs sdl2)
|
||||
OPENGLES_LIBS = -lGLESv2
|
||||
PULSE_LIBS = $(shell $(PKG_CONFIG) --libs libpulse)
|
||||
MMAP_LIBS = -lc
|
||||
NEON_CFLAGS = -mfpu=neon
|
||||
NEON_ASFLAGS = -mfpu=neon
|
||||
NETWORKING_LIBS = -lc
|
||||
|
||||
OBJDIR_BASE := obj-unix
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
OBJDIR := $(OBJDIR_BASE)/debug
|
||||
DEF_FLAGS += -O0 -g -DDEBUG -D_DEBUG
|
||||
else
|
||||
OBJDIR := $(OBJDIR_BASE)/release
|
||||
DEF_FLAGS += -O2 -DNDEBUG
|
||||
endif
|
||||
|
||||
include Makefile.common
|
||||
|
||||
DEF_FLAGS += $(INCLUDE_DIRS)
|
||||
LDFLAGS += $(CFLAGS) $(CXXFLAGS) $(DEF_FLAGS)
|
||||
CFLAGS += $(DEF_FLAGS)
|
||||
CXXFLAGS += $(DEF_FLAGS)
|
||||
|
||||
HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
Q := @
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
define APPINFO
|
||||
{
|
||||
"id": "$(PACKAGE_NAME)",
|
||||
"version": "$(PACKAGE_VERSION)",
|
||||
"vendor": "webosbrew.org",
|
||||
"title": "RetroArch",
|
||||
"icon": "icon160.png",
|
||||
"main": "retroarch",
|
||||
"iconColor": "#333333",
|
||||
"type": "native",
|
||||
"appDescription": "Emulation frontend"
|
||||
}
|
||||
endef
|
||||
export APPINFO
|
||||
|
||||
all: $(TARGET) ipk
|
||||
|
||||
-include $(RARCH_OBJ:.o=.d)
|
||||
|
||||
SYMBOL_MAP := -Wl,-Map=output.map
|
||||
|
||||
$(TARGET): $(RARCH_OBJ)
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LINK) -o $@ $(RARCH_OBJ) $(LIBS) $(LDFLAGS) $(LIBRARY_DIRS)
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.m
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo OBJC $<),)
|
||||
$(Q)$(CXX) $(OBJCFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.S $(HEADERS)
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo AS $<),)
|
||||
$(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR_BASE)
|
||||
rm -f $(TARGET)
|
||||
rm -f *.d
|
||||
rm -rf SDL
|
||||
rm -rf webos/*.ipk
|
||||
rm -rf webos/dist
|
||||
|
||||
sdl2: $(TARGET)
|
||||
ifeq ($(ADD_SDL2_LIB), 1)
|
||||
@echo "Downloading SDL2 prebuilt"
|
||||
mkdir -p SDL
|
||||
wget -qO - $(SDL2_PREBUILT_ARCHIVE) | tar -C SDL -zxvf -
|
||||
endif
|
||||
|
||||
ipk: $(TARGET) sdl2
|
||||
rm -rf webos/dist
|
||||
mkdir -p webos/dist/lib
|
||||
echo "$$APPINFO" > webos/dist/appinfo.json
|
||||
cp -t webos/dist -vf $(TARGET) webos/icon160.png
|
||||
cp -t webos/dist/lib -vf $(WEBOS_LIB_DIR)/libstdc++.so.6
|
||||
ifeq ($(ADD_SDL2_LIB), 1)
|
||||
cp -t webos/dist/lib -vf SDL/lib/libSDL2-2.0.so.0
|
||||
endif
|
||||
$(STRIP) webos/dist/$(TARGET)
|
||||
cd webos && ares-package dist
|
||||
|
||||
install: ipk
|
||||
ares-install webos/$(PACKAGE_NAME)_$(PACKAGE_VERSION)_$(ARCH).ipk
|
||||
|
||||
launch: install
|
||||
ares-launch com.retroarch
|
||||
|
||||
.PHONY: all clean ipk
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
include version.all
|
||||
|
||||
ifneq ($(filter $(CROSS_COMPILE),arm-webos-linux-gnueabi- aarch64-webos-linux-gnu-),$(CROSS_COMPILE))
|
||||
$(error You need webOS toolchain to build this. See https://github.com/webosbrew/native-toolchain)
|
||||
endif
|
||||
|
||||
ifdef SDKTARGETSYSROOT
|
||||
$(warning "OE-based toolchain isn't supported anymore. Please use https://github.com/webosbrew/native-toolchain")
|
||||
STAGING_DIR = $(SDKTARGETSYSROOT)
|
||||
else ifndef STAGING_DIR
|
||||
$(error "Can't find buildroot based toolchain. Please use https://github.com/webosbrew/native-toolchain")
|
||||
endif
|
||||
|
||||
WEBOS_FREETYPE_CONFIG ?= $(STAGING_DIR)/usr/bin/freetype-config
|
||||
|
||||
WEBOS_INC_DIR ?= $(STAGING_DIR)/usr/include
|
||||
WEBOS_USR_LIB_DIR ?= $(STAGING_DIR)/usr/lib
|
||||
WEBOS_LIB_DIR ?= $(STAGING_DIR)/lib
|
||||
|
||||
ADD_SDL2_LIB ?= 0
|
||||
SDL2_PREBUILT_ARCHIVE ?= https://github.com/webosbrew/SDL-webOS/releases/download/release-2.30.12-webos.1/SDL2-2.30.12-webos-abi.tar.gz
|
||||
|
||||
#########################
|
||||
#########################
|
||||
|
||||
APP_PACKAGE_NAME ?= com.retroarch.webos
|
||||
IPK_VERSION := $(shell grep '#define PACKAGE_VERSION' version.all | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/')
|
||||
|
||||
DEBUG ?= 0
|
||||
|
||||
HAVE_CLOUDSYNC = 1
|
||||
HAVE_SCREENSHOTS = 1
|
||||
HAVE_REWIND = 1
|
||||
HAVE_7ZIP = 1
|
||||
HAVE_ACCESSIBILITY = 1
|
||||
HAVE_AL = 0
|
||||
# ALSA freezes when switching back from menu
|
||||
HAVE_ALSA = 0
|
||||
HAVE_ANGLE = 0
|
||||
HAVE_AUDIOIO = 0
|
||||
HAVE_AUDIOMIXER = 1
|
||||
HAVE_BLISSBOX = 0
|
||||
HAVE_BSV_MOVIE = 1
|
||||
HAVE_BUILTINBEARSSL = 0
|
||||
HAVE_BUILTINFLAC = 1
|
||||
HAVE_DSP_FILTER = 1
|
||||
HAVE_VIDEO_FILTER = 1
|
||||
HAVE_STATIC_VIDEO_FILTERS = 1
|
||||
HAVE_STATIC_AUDIO_FILTERS = 1
|
||||
HAVE_FILTERS_BUILTIN = 1
|
||||
HAVE_BUILTINMBEDTLS = 1
|
||||
HAVE_BUILTINZLIB = 1
|
||||
HAVE_C99 = 1
|
||||
HAVE_CC = 1
|
||||
HAVE_CC_RESAMPLER = 1
|
||||
HAVE_NEAREST_RESAMPLER = 1
|
||||
HAVE_CHD = 1
|
||||
HAVE_COMMAND = 1
|
||||
HAVE_CXX = 1
|
||||
HAVE_DR_MP3 = 1
|
||||
HAVE_DYNAMIC = 1
|
||||
HAVE_DYLIB = 1
|
||||
HAVE_EGL = 0
|
||||
HAVE_FREETYPE = 1
|
||||
HAVE_GDI = 0
|
||||
HAVE_GETADDRINFO = 1
|
||||
HAVE_GETOPT_LONG = 1
|
||||
HAVE_GLSL = 1
|
||||
HAVE_GLSLANG = 0
|
||||
HAVE_GLSLANG_HLSL = 0
|
||||
HAVE_GLSLANG_OGLCOMPILER = 0
|
||||
HAVE_GLSLANG_OSDEPENDENT = 0
|
||||
HAVE_GLSLANG_SPIRV = 0
|
||||
HAVE_GLSLANG_SPIRV_TOOLS = 0
|
||||
HAVE_GLSLANG_SPIRV_TOOLS_OPT = 0
|
||||
HAVE_HID = 1
|
||||
HAVE_IBXM = 1
|
||||
HAVE_IMAGEVIEWER = 1
|
||||
HAVE_LANGEXTRA = 1
|
||||
HAVE_LIBRETRODB = 1
|
||||
HAVE_MENU = 1
|
||||
HAVE_MENU_COMMON = 1
|
||||
HAVE_NEON = 0
|
||||
HAVE_NETWORKING = 1
|
||||
HAVE_IFINFO = 1
|
||||
HAVE_NETWORK_CMD = 1
|
||||
HAVE_NETPLAYDISCOVERY = 1
|
||||
HAVE_NETWORKGAMEPAD = 1
|
||||
HAVE_GFX_WIDGETS = 1
|
||||
HAVE_MMAP = 1
|
||||
HAVE_ONLINE_UPDATER = 1
|
||||
HAVE_OPENDINGUX_FBDEV = 0
|
||||
HAVE_OPENGL = 0
|
||||
HAVE_OPENGL1 = 0
|
||||
HAVE_OPENGL_CORE = 0
|
||||
HAVE_OPENGLES = 1
|
||||
HAVE_OPENGLES3 = 0
|
||||
HAVE_OPENGLES3_1 = 0
|
||||
HAVE_OPENGLES3_2 = 0
|
||||
HAVE_OPENSSL = 0
|
||||
HAVE_OVERLAY = 1
|
||||
HAVE_PULSE = 1
|
||||
HAVE_RBMP = 1
|
||||
HAVE_RJPEG = 1
|
||||
HAVE_RPILED = 0
|
||||
HAVE_RPNG = 1
|
||||
HAVE_RUNAHEAD = 1
|
||||
HAVE_SDL = 0
|
||||
HAVE_SDL2 = 1
|
||||
HAVE_SHADERPIPELINE = 1
|
||||
HAVE_STB_FONT = 0
|
||||
HAVE_STB_IMAGE = 1
|
||||
HAVE_STB_VORBIS = 1
|
||||
HAVE_STDIN_CMD = 1
|
||||
HAVE_STRCASESTR = 1
|
||||
HAVE_THREADS = 1
|
||||
HAVE_UDEV = 0
|
||||
HAVE_RGUI = 1
|
||||
HAVE_MATERIALUI = 0
|
||||
HAVE_XMB = 1
|
||||
HAVE_OZONE = 1
|
||||
HAVE_ZLIB = 1
|
||||
HAVE_ZSTD = 1
|
||||
HAVE_CONFIGFILE = 1
|
||||
HAVE_PATCH = 1
|
||||
HAVE_CHEATS = 1
|
||||
HAVE_CHEEVOS = 1
|
||||
HAVE_LIBSHAKE = 1
|
||||
HAVE_UPDATE_ASSETS = 1
|
||||
HAVE_UPDATE_CORES = 1
|
||||
HAVE_UPDATE_CORE_INFO = 1
|
||||
HAVE_CORE_INFO_CACHE = 1
|
||||
|
||||
OS = Linux
|
||||
TARGET = retroarch
|
||||
|
||||
OBJ :=
|
||||
LINK := $(CC)
|
||||
DEF_FLAGS += -ffunction-sections -fdata-sections
|
||||
DEF_FLAGS += -I. -Ideps -Ideps/stb -DWEBOS=1 -MMD
|
||||
DEF_FLAGS += -Wall -Wno-unused-variable
|
||||
LIBS := -ldl -lz -lrt -pthread
|
||||
ifeq ($(findstring arm64,$(ARCH)),arm64)
|
||||
ARCHFLAGS := -mcpu=cortex-a53
|
||||
else
|
||||
ARCHFLAGS := -mcpu=cortex-a9 -mtune=cortex-a53 -mfloat-abi=softfp
|
||||
HAVE_NEON = 1
|
||||
endif
|
||||
CFLAGS := $(ARCHFLAGS)
|
||||
CXXFLAGS := $(ARCHFLAGS) -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS
|
||||
ASFLAGS := $(ARCHFLAGS)
|
||||
LDFLAGS := -Wl,-rpath=\$$ORIGIN/lib,--gc-sections
|
||||
INCLUDE_DIRS = -I$(WEBOS_INC_DIR)
|
||||
LIBRARY_DIRS = -L$(WEBOS_USR_LIB_DIR)
|
||||
DEFINES := -DRARCH_INTERNAL -D_FILE_OFFSET_BITS=64 -UHAVE_STATIC_DUMMY
|
||||
DEFINES += -DHAVE_C99=1 -DHAVE_CXX=1 -D_GNU_SOURCE
|
||||
DEFINES += -DHAVE_GETOPT_LONG=1 -DHAVE_STRCASESTR=1 -DHAVE_DYNAMIC=1
|
||||
DEFINES += -DHAVE_FILTERS_BUILTIN
|
||||
DEFINES += -DHAVE_SDL2
|
||||
DEFINES += -DHAVE_PULSE
|
||||
DEFINES += -DHAVE_NETWORKING -DHAVE_IFINFO -DHAVE_ONLINE_UPDATER -DHAVE_UPDATE_ASSETS -DHAVE_UPDATE_CORES
|
||||
DEFINES += -DHAVE_NETWORKGAMEPAD
|
||||
DEFINES += -DHAVE_FREETYPE
|
||||
DEFINES += -DHAVE_UPDATE_CORE_INFO
|
||||
ifneq (,$(filter 1,$(HAVE_OPENGLES3) $(HAVE_OPENGLES3_1) $(HAVE_OPENGLES3_2)))
|
||||
DEFINES += -DHAVE_OPENGLES3
|
||||
endif
|
||||
ifeq ($(HAVE_OPENGLES3_1),1)
|
||||
DEFINES += -DHAVE_OPENGLES3_1
|
||||
endif
|
||||
ifeq ($(HAVE_OPENGLES3_2),1)
|
||||
DEFINES += -DHAVE_OPENGLES3_2
|
||||
endif
|
||||
|
||||
PKG_CONFIG=pkg-config
|
||||
|
||||
SDL2_CFLAGS := $(shell $(PKG_CONFIG) --cflags sdl2)
|
||||
SDL2_LIBS := $(shell $(PKG_CONFIG) --libs sdl2)
|
||||
OPENGLES_LIBS = -lGLESv2
|
||||
PULSE_LIBS = $(shell $(PKG_CONFIG) --libs libpulse)
|
||||
FREETYPE_CFLAGS := $(shell $(PKG_CONFIG) --cflags freetype2)
|
||||
FREETYPE_LIBS := $(shell $(PKG_CONFIG) --libs freetype2)
|
||||
FONTCONFIG_CFLAGS := $(shell $(PKG_CONFIG) --cflags fontconfig)
|
||||
FONTCONFIG_LIBS := $(shell $(PKG_CONFIG) --libs fontconfig)
|
||||
MMAP_LIBS = -lc
|
||||
ifeq ($(HAVE_NEON),1)
|
||||
NEON_CFLAGS += -mfpu=neon
|
||||
NEON_ASFLAGS += -mfpu=neon
|
||||
endif
|
||||
NETWORKING_LIBS = -lc
|
||||
|
||||
OBJDIR_BASE := obj-unix
|
||||
|
||||
ifeq ($(DEBUG), 1)
|
||||
OBJDIR := $(OBJDIR_BASE)/debug
|
||||
DEF_FLAGS += -O0 -g -DDEBUG -D_DEBUG
|
||||
else
|
||||
OBJDIR := $(OBJDIR_BASE)/release
|
||||
DEF_FLAGS += -O2 -DNDEBUG
|
||||
endif
|
||||
|
||||
include Makefile.common
|
||||
|
||||
DEF_FLAGS += $(INCLUDE_DIRS)
|
||||
LDFLAGS += $(CFLAGS) $(CXXFLAGS) $(DEF_FLAGS)
|
||||
CFLAGS += $(DEF_FLAGS)
|
||||
CXXFLAGS += $(DEF_FLAGS)
|
||||
|
||||
HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h)
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ))
|
||||
|
||||
define APPINFO
|
||||
{
|
||||
"id": "$(APP_PACKAGE_NAME)",
|
||||
"version": "$(IPK_VERSION)",
|
||||
"vendor": "webosbrew.org",
|
||||
"title": "RetroArch",
|
||||
"icon": "icon160.png",
|
||||
"main": "retroarch",
|
||||
"iconColor": "#333333",
|
||||
"type": "native",
|
||||
"appDescription": "Emulation frontend",
|
||||
"cloudgame_active": true,
|
||||
"useAllMouseButtons": true,
|
||||
"useAllKeyboardKeys": true
|
||||
}
|
||||
endef
|
||||
export APPINFO
|
||||
|
||||
all: $(TARGET) ipk
|
||||
|
||||
define INFO
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CPPFLAGS: $(CPPFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBRARY_DIRS: $(LIBRARY_DIRS)
|
||||
LIBS: $(LIBS)
|
||||
LINK: $(LINK)
|
||||
OBJCFLAGS: $(OBJCFLAGS)
|
||||
RARCH_OBJ: $(RARCH_OBJ)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
-include $(RARCH_OBJ:.o=.d)
|
||||
|
||||
SYMBOL_MAP := -Wl,-Map=output.map
|
||||
|
||||
$(TARGET): $(RARCH_OBJ)
|
||||
@$(if $(Q), $(shell echo echo LD $@),)
|
||||
$(Q)$(LINK) -o $@ $(RARCH_OBJ) $(LIBS) $(LDFLAGS) $(LIBRARY_DIRS)
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo CXX $<),)
|
||||
$(Q)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.m
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo OBJC $<),)
|
||||
$(Q)$(CXX) $(OBJCFLAGS) $(DEFINES) -MMD -c -o $@ $<
|
||||
|
||||
$(OBJDIR)/%.o: %.S $(HEADERS)
|
||||
@mkdir -p $(dir $@)
|
||||
@$(if $(Q), $(shell echo echo AS $<),)
|
||||
$(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $<
|
||||
|
||||
clean:
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -rf $(OBJDIR_BASE)
|
||||
$(Q)rm -f $(TARGET)
|
||||
$(Q)rm -f *.d
|
||||
$(Q)rm -rf SDL
|
||||
$(Q)rm -rf webos/*.ipk
|
||||
$(Q)rm -rf webos/dist
|
||||
|
||||
sdl2: $(TARGET)
|
||||
ifeq ($(ADD_SDL2_LIB), 1)
|
||||
@echo "Downloading SDL2 prebuilt"
|
||||
mkdir -p SDL
|
||||
wget -qO - $(SDL2_PREBUILT_ARCHIVE) | tar -C SDL -zxvf -
|
||||
endif
|
||||
|
||||
ipk: $(TARGET) sdl2
|
||||
rm -rf webos/dist
|
||||
mkdir -p webos/dist/lib
|
||||
echo "$$APPINFO" > webos/dist/appinfo.json
|
||||
cp -t webos/dist -vf $(TARGET) webos/icon160.png
|
||||
cp -t webos/dist/lib -vf $(WEBOS_USR_LIB_DIR)/libstdc++.so.6
|
||||
cp -t webos/dist/lib -vf $(WEBOS_LIB_DIR)/libatomic.so.1
|
||||
ifeq ($(ADD_SDL2_LIB), 1)
|
||||
cp -t webos/dist/lib -vf SDL/lib/libSDL2-2.0.so.0
|
||||
endif
|
||||
ifneq ($(DEBUG), 1)
|
||||
$(STRIP) webos/dist/$(TARGET)
|
||||
endif
|
||||
cd webos && ares-package dist
|
||||
|
||||
install: ipk
|
||||
ares-install webos/$(APP_PACKAGE_NAME)_$(IPK_VERSION)_$(ARCH).ipk
|
||||
|
||||
launch: install
|
||||
ares-launch $(APP_PACKAGE_NAME)
|
||||
|
||||
.PHONY: all clean ipk
|
||||
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
+30
-6
@@ -61,6 +61,7 @@ LIBS := $(WHOLE_START) $(LIB_CORE) $(WHOLE_END)
|
||||
libogc_platform := 1
|
||||
|
||||
EXTERNAL_LIBOGC ?= 0
|
||||
HAVE_OGG_OGC ?= 0
|
||||
GX_PTHREAD_LEGACY ?= 1
|
||||
CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
|
||||
CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
|
||||
@@ -105,6 +106,10 @@ ifeq ($(BIG_STACK), 1)
|
||||
LDFLAGS += -T bootstrap/gx/rvl.ld
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_OGG_OGC), 1)
|
||||
LIBS += -L$(DEVKITPRO)/portlibs/ppc/lib -lvorbisfile -lvorbis -logg
|
||||
endif
|
||||
|
||||
ifeq ($(EXTERNAL_LIBOGC), 1)
|
||||
LIBS += -lfat
|
||||
endif
|
||||
@@ -265,12 +270,28 @@ ifeq ($(LOAD_WITHOUT_CORE_INFO),1)
|
||||
CFLAGS += -DLOAD_WITHOUT_CORE_INFO
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
endif
|
||||
|
||||
OBJOUT = -o
|
||||
LINKOUT = -o
|
||||
LINK = $(CXX)
|
||||
|
||||
all: $(EXT_TARGET)
|
||||
|
||||
define INFO
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
OBJOUT: $(OBJOUT)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
%.dol: %.elf
|
||||
$(ELF2DOL) $< $@
|
||||
|
||||
@@ -278,13 +299,15 @@ $(EXT_INTER_TARGET): $(OBJ)
|
||||
$(LINK) $(LINKOUT)$@ $(LDFLAGS) $(LIBDIRS) $(OBJ) $(PLATEXTRA) $(LIBS)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
@$(if $(Q), $(shell echo echo CC $<),)
|
||||
$(Q)$(CC) $(CFLAGS) -c $(OBJOUT)$@ $<
|
||||
|
||||
%.binobj: %.bin
|
||||
$(LD) -r -b binary $(OBJOUT)$@ $<
|
||||
@@ -294,10 +317,11 @@ $(APP_BOOTER_DIR)/app_booter.bin:
|
||||
$(MAKE) -C $(APP_BOOTER_DIR)
|
||||
|
||||
clean:
|
||||
rm -f $(EXT_TARGET)
|
||||
rm -f $(EXT_INTER_TARGET)
|
||||
rm -f $(OBJ)
|
||||
$(MAKE) -C $(APP_BOOTER_DIR) clean
|
||||
@$(if $(Q), echo $@,)
|
||||
$(Q)rm -f $(EXT_TARGET)
|
||||
$(Q)rm -f $(EXT_INTER_TARGET)
|
||||
$(Q)rm -f $(OBJ)
|
||||
$(Q)$(MAKE) -C $(APP_BOOTER_DIR) clean
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
|
||||
+32
-1
@@ -203,7 +203,7 @@ INCDIRS += -Iwiiu
|
||||
INCDIRS += -Iwiiu/include
|
||||
|
||||
CFLAGS := -mcpu=750 -meabi -mhard-float
|
||||
CFLAGS += -ffast-math -Werror=implicit-function-declaration
|
||||
CFLAGS += -Werror=implicit-function-declaration
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
#CFLAGS += -fomit-frame-pointer -mword-relocations
|
||||
CFLAGS += -Wall
|
||||
@@ -304,6 +304,37 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.depend
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
define INFO
|
||||
AR: $(AR)
|
||||
ASFLAGS: $(ASFLAGS)
|
||||
BUILD_DIR: $(BUILD_DIR)
|
||||
CC: $(CC)
|
||||
CFLAGS: $(CFLAGS)
|
||||
CXX: $(CXX)
|
||||
CXXFLAGS: $(CXXFLAGS)
|
||||
DEFINES: $(DEFINES)
|
||||
DEPFLAGS: $(DEPFLAGS)
|
||||
ELF2RPL: $(ELF2RPL)
|
||||
HBL_ELF_LDFLAGS: $(HBL_ELF_LDFLAGS)
|
||||
HBL_ELF_OBJ: $(HBL_ELF_OBJ)
|
||||
INCDIRS: $(INCDIRS)
|
||||
LD: $(LD)
|
||||
LDFLAGS: $(LDFLAGS)
|
||||
LIBDIRS: $(LIBDIRS)
|
||||
LIBS: $(LIBS)
|
||||
MAKE: $(MAKE)
|
||||
OBJ: $(OBJ)
|
||||
RPX_LDFLAGS: $(RPX_LDFLAGS)
|
||||
RPX_OBJ: $(RPX_OBJ)
|
||||
TARGET: $(TARGET)
|
||||
endef
|
||||
export INFO
|
||||
|
||||
info:
|
||||
ifneq ($(V),1)
|
||||
@echo "$$INFO"
|
||||
endif
|
||||
|
||||
%: $(BUILD_DIR)/%
|
||||
cp $< $@
|
||||
|
||||
|
||||
+3
-2
@@ -89,6 +89,7 @@ AVUTIL_LIBS := -lavutil
|
||||
SWSCALE_LIBS := -lswscale
|
||||
AVFORMAT_LIBS := -lavformat
|
||||
SWRESAMPLE_LIBS := -lswresample
|
||||
AVDEVICE_LIBS := -lavdevice
|
||||
FFMPEG_LIBS := -lws2_32 -lz
|
||||
endif
|
||||
|
||||
@@ -131,8 +132,8 @@ ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -O0 -g
|
||||
CXXFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O3 -ffast-math
|
||||
CXXFLAGS += -O3 -ffast-math
|
||||
CFLAGS += -O3
|
||||
CXXFLAGS += -O3
|
||||
endif
|
||||
|
||||
CFLAGS += $(DEF_FLAGS) -Wall -Wno-unused-result -Wno-unused-variable -I. -Ideps
|
||||
|
||||
@@ -73,6 +73,7 @@ RetroArch has been ported to the following platforms:
|
||||
- Emscripten (WebAssembly and JavaScript)
|
||||
- FreeBSD
|
||||
- Haiku
|
||||
- LG webOS
|
||||
- Linux
|
||||
- Original Microsoft Xbox
|
||||
- Microsoft Xbox 360 (Libxenon/XeXDK)
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
# Security Policy
|
||||
|
||||
## Reasonable expectations
|
||||
|
||||
RetroArch is a frontend for the libretro API. The main functionality is fulfilled by invoking other binary libraries ("cores") which are not restricted by RetroArch in any way. Cores are able to read/write/delete files, spawn processes, communicate over the network. Also, source for cores is not necessarily in control by libretro team, and core binaries / RetroArch binaries are not signed. For this reason, it is a bad idea to use RetroArch or any other libretro frontend on security critical systems.
|
||||
|
||||
Also, RetroArch and cores have been packaged in several ways. Content on the [official download site](https://buildbot.libretro.com/) is built from a direct mirror of the original RetroArch and core repositories, no binaries are reused. Note that source for the core repositories may be outside libretro team control.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
For most delivery channels, libretro team does not have control over the version. The exceptions are:
|
||||
- [official download site](https://buildbot.libretro.com/)
|
||||
- Steam release
|
||||
- Apple App Store release
|
||||
- various Android app store releases
|
||||
- note that Google Play Store version is years behind and can not be updated
|
||||
|
||||
You may report vulnerability against any recent version, but be reasonable.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please report security vulnerabilities at libretro@gmail.com
|
||||
|
||||
## Possible remediation
|
||||
|
||||
Due to the variety of delivery channels, RetroArch team can not recall any given version universally. Security fixes are accepted for next release, and notice may be posted in the channels controlled by RetroArch team, depending on the severity assessed by RetroArch team.
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
#include "game_ai.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <retro_assert.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "../deps/game_ai_lib/GameAI.h"
|
||||
|
||||
#define GAME_AI_MAX_PLAYERS 2
|
||||
|
||||
void * ga = NULL;
|
||||
volatile void * g_ram_ptr = NULL;
|
||||
volatile int g_ram_size = 0;
|
||||
volatile signed short int g_buttons_bits[GAME_AI_MAX_PLAYERS] = {0};
|
||||
volatile int g_frameCount = 0;
|
||||
volatile char game_ai_lib_path[1024] = {0};
|
||||
volatile char g_game_name[1024] = {0};
|
||||
retro_log_printf_t g_log = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
HINSTANCE g_lib_handle = NULL;
|
||||
#else
|
||||
void * g_lib_handle = NULL;
|
||||
#endif
|
||||
|
||||
/* GameAI Lib API*/
|
||||
create_game_ai_t create_game_ai = NULL;
|
||||
destroy_game_ai_t destroy_game_ai = NULL;
|
||||
game_ai_lib_init_t game_ai_lib_init = NULL;
|
||||
game_ai_lib_think_t game_ai_lib_think = NULL;
|
||||
game_ai_lib_set_show_debug_t game_ai_lib_set_show_debug = NULL;
|
||||
game_ai_lib_set_debug_log_t game_ai_lib_set_debug_log = NULL;
|
||||
|
||||
/* Helper functions */
|
||||
void game_ai_debug_log(int level, const char *fmt, ...)
|
||||
{
|
||||
va_list vp;
|
||||
va_start(vp, fmt);
|
||||
|
||||
if (g_log)
|
||||
g_log((enum retro_log_level)level, fmt, vp);
|
||||
|
||||
va_end(vp);
|
||||
}
|
||||
|
||||
void array_to_bits_16(volatile signed short *result, const bool b[16])
|
||||
{
|
||||
for (int bit = 0; bit <= 15; bit++)
|
||||
*result |= b[bit] ? (1 << bit) : 0;
|
||||
}
|
||||
|
||||
/* Interface to RA */
|
||||
|
||||
signed short int game_ai_input(unsigned int port, unsigned int device,
|
||||
unsigned int idx, unsigned int id, signed short int result)
|
||||
{
|
||||
if (ga && (port < GAME_AI_MAX_PLAYERS))
|
||||
return g_buttons_bits[port];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void game_ai_init(void)
|
||||
{
|
||||
if (!create_game_ai)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
|
||||
|
||||
g_lib_handle = LoadLibrary(TEXT("game_ai.dll"));
|
||||
retro_assert(hinstLib);
|
||||
|
||||
char full_module_path[MAX_PATH];
|
||||
DWORD dwLen = GetModuleFileNameA(g_lib_handle, static_cast<char*>(&full_module_path), MAX_PATH);
|
||||
|
||||
if (hinstLib)
|
||||
{
|
||||
create_game_ai = (create_game_ai_t) GetProcAddress(hinstLib, "create_game_ai");
|
||||
retro_assert(create_game_ai);
|
||||
|
||||
destroy_game_ai = (destroy_game_ai_t) GetProcAddress(hinstLib, "destroy_game_ai");
|
||||
retro_assert(destroy_game_ai);
|
||||
|
||||
game_ai_lib_init = (game_ai_lib_init_t) GetProcAddress(hinstLib, "game_ai_lib_init");
|
||||
retro_assert(game_ai_lib_init);
|
||||
|
||||
game_ai_lib_think = (game_ai_lib_think_t) GetProcAddress(hinstLib, "game_ai_lib_think");
|
||||
retro_assert(game_ai_lib_think);
|
||||
|
||||
game_ai_lib_set_show_debug = (game_ai_lib_set_show_debug_t) GetProcAddress(hinstLib, "game_ai_lib_set_show_debug");
|
||||
retro_assert(game_ai_lib_set_show_debug);
|
||||
|
||||
game_ai_lib_set_debug_log = (game_ai_lib_set_debug_log_t) GetProcAddress(hinstLib, "game_ai_lib_set_debug_log");
|
||||
retro_assert(game_ai_lib_set_debug_log);
|
||||
}
|
||||
#else
|
||||
g_lib_handle = dlopen("./libgame_ai.so", RTLD_NOW);
|
||||
retro_assert(g_lib_handle);
|
||||
|
||||
if (g_lib_handle)
|
||||
{
|
||||
dlinfo(g_lib_handle, RTLD_DI_ORIGIN, (void *) &game_ai_lib_path);
|
||||
|
||||
create_game_ai = (create_game_ai_t)(dlsym(g_lib_handle, "create_game_ai"));
|
||||
retro_assert(create_game_ai);
|
||||
|
||||
destroy_game_ai = (destroy_game_ai_t)(dlsym(g_lib_handle, "destroy_game_ai"));
|
||||
retro_assert(destroy_game_ai);
|
||||
|
||||
game_ai_lib_init = (game_ai_lib_init_t)(dlsym(g_lib_handle, "game_ai_lib_init"));
|
||||
retro_assert(game_ai_lib_init);
|
||||
|
||||
game_ai_lib_think = (game_ai_lib_think_t)(dlsym(g_lib_handle, "game_ai_lib_think"));
|
||||
retro_assert(game_ai_lib_think);
|
||||
|
||||
game_ai_lib_set_show_debug = (game_ai_lib_set_show_debug_t)(dlsym(g_lib_handle, "game_ai_lib_set_show_debug"));
|
||||
retro_assert(game_ai_lib_set_show_debug);
|
||||
|
||||
game_ai_lib_set_debug_log = (game_ai_lib_set_debug_log_t)(dlsym(g_lib_handle, "game_ai_lib_set_debug_log"));
|
||||
retro_assert(game_ai_lib_set_debug_log);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void game_ai_shutdown(void)
|
||||
{
|
||||
if (g_lib_handle)
|
||||
{
|
||||
if (ga)
|
||||
{
|
||||
destroy_game_ai(ga);
|
||||
ga = NULL;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
FreeLibrary(g_lib_handle);
|
||||
#else
|
||||
dlclose(g_lib_handle);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void game_ai_load(const char * name, void * ram_ptr, int ram_size, retro_log_printf_t log)
|
||||
{
|
||||
strcpy((char *) &g_game_name[0], name);
|
||||
|
||||
g_ram_ptr = ram_ptr;
|
||||
g_ram_size = ram_size;
|
||||
|
||||
g_log = log;
|
||||
|
||||
if (ga)
|
||||
{
|
||||
destroy_game_ai(ga);
|
||||
ga = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void game_ai_think(bool override_p1, bool override_p2, bool show_debug,
|
||||
const void *frame_data, unsigned int frame_width, unsigned int frame_height,
|
||||
unsigned int frame_pitch, unsigned int pixel_format)
|
||||
{
|
||||
if (ga)
|
||||
game_ai_lib_set_show_debug(ga, show_debug);
|
||||
|
||||
if (!ga && g_ram_ptr)
|
||||
{
|
||||
ga = create_game_ai((char *) &g_game_name[0]);
|
||||
retro_assert(ga);
|
||||
|
||||
if (ga)
|
||||
{
|
||||
char data_path[1024] = {0};
|
||||
strcpy(&data_path[0], (char *)game_ai_lib_path);
|
||||
strcat(&data_path[0], "/data/");
|
||||
strcat(&data_path[0], (char *)g_game_name);
|
||||
|
||||
game_ai_lib_init(ga, (void *) g_ram_ptr, g_ram_size);
|
||||
game_ai_lib_set_debug_log(ga, game_ai_debug_log);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_frameCount >= (GAMEAI_SKIPFRAMES - 1))
|
||||
{
|
||||
if (ga)
|
||||
{
|
||||
bool b[GAMEAI_MAX_BUTTONS] = {0};
|
||||
|
||||
g_buttons_bits[0]=0;
|
||||
g_buttons_bits[1]=0;
|
||||
|
||||
if (override_p1)
|
||||
{
|
||||
game_ai_lib_think(ga, b, 0, frame_data, frame_width, frame_height, frame_pitch, pixel_format);
|
||||
array_to_bits_16(&g_buttons_bits[0], b);
|
||||
}
|
||||
|
||||
if (override_p2)
|
||||
{
|
||||
game_ai_lib_think(ga, b, 1, frame_data, frame_width, frame_height, frame_pitch, pixel_format);
|
||||
array_to_bits_16(&g_buttons_bits[1], b);
|
||||
}
|
||||
}
|
||||
g_frameCount=0;
|
||||
}
|
||||
else
|
||||
g_frameCount++;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* copyright (c) 2011-2015 - Daniel De Matteis
|
||||
* copyright (c) 2016-2019 - Brad Parker
|
||||
* Copyright (C) 2011-2016 - Daniel De Matteis
|
||||
* Copyright (C) 2021 - David G.F.
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
@@ -15,28 +15,30 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __VGA_DEFINES_H
|
||||
#define __VGA_DEFINES_H
|
||||
#ifndef RARCH_GAME_AI_H__
|
||||
#define RARCH_GAME_AI_H__
|
||||
|
||||
#define VGA_WIDTH 320
|
||||
#define VGA_HEIGHT 200
|
||||
#include <boolean.h>
|
||||
#include <retro_common_api.h>
|
||||
|
||||
typedef struct vga
|
||||
{
|
||||
unsigned char *vga_menu_frame;
|
||||
unsigned char *vga_frame;
|
||||
#include <libretro.h>
|
||||
|
||||
unsigned vga_menu_width;
|
||||
unsigned vga_menu_height;
|
||||
unsigned vga_menu_pitch;
|
||||
unsigned vga_menu_bits;
|
||||
unsigned vga_video_width;
|
||||
unsigned vga_video_height;
|
||||
unsigned vga_video_pitch;
|
||||
unsigned vga_video_bits;
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
bool color;
|
||||
bool vga_rgb32;
|
||||
} vga_t;
|
||||
signed short int game_ai_input(unsigned int port, unsigned int device,
|
||||
unsigned int idx, unsigned int id, signed short int result);
|
||||
|
||||
void game_ai_init(void);
|
||||
|
||||
void game_ai_shutdown(void);
|
||||
|
||||
void game_ai_load(const char * name, void * ram_ptr,
|
||||
int ram_size, retro_log_printf_t log);
|
||||
|
||||
void game_ai_think(bool override_p1, bool override_p2, bool show_debug,
|
||||
const void *frame_data, unsigned int frame_w, unsigned int frame_h,
|
||||
unsigned int frame_pitch, unsigned int pixel_format);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
+8
-14
@@ -21,23 +21,11 @@
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#define AUDIO_CHUNK_SIZE_BLOCKING 512
|
||||
|
||||
/* So we don't get complete line-noise when fast-forwarding audio. */
|
||||
#define AUDIO_CHUNK_SIZE_NONBLOCKING 2048
|
||||
|
||||
#define AUDIO_MAX_RATIO 16
|
||||
#define AUDIO_MIN_RATIO 0.0625
|
||||
|
||||
#define AUDIO_MIXER_MAX_STREAMS 16
|
||||
|
||||
#define AUDIO_MIXER_MAX_SYSTEM_STREAMS (AUDIO_MIXER_MAX_STREAMS + 8)
|
||||
|
||||
/* Fastforward timing calculations running average samples. Helps with a
|
||||
consistent pitch when fast-forwarding. */
|
||||
#define AUDIO_FF_EXP_AVG_SAMPLES 16
|
||||
|
||||
/* do not define more than (MAX_SYSTEM_STREAMS - MAX_STREAMS) */
|
||||
/* Do not define more than (MAX_SYSTEM_STREAMS - MAX_STREAMS) */
|
||||
enum audio_mixer_system_slot
|
||||
{
|
||||
AUDIO_MIXER_SYSTEM_SLOT_OK = AUDIO_MIXER_MAX_STREAMS,
|
||||
@@ -161,7 +149,13 @@ enum audio_driver_state_flags
|
||||
* @see audio_driver_t::write_avail
|
||||
* @see audio_driver_t::buffer_size
|
||||
*/
|
||||
AUDIO_FLAG_CONTROL = (1 << 5)
|
||||
AUDIO_FLAG_CONTROL = (1 << 5),
|
||||
|
||||
/**
|
||||
* Indicates that the audio driver is forcing gain to 0.
|
||||
* Used for temporary rewind and fast-forward muting.
|
||||
*/
|
||||
AUDIO_FLAG_MUTED = (1 << 6)
|
||||
};
|
||||
|
||||
typedef struct audio_statistics
|
||||
|
||||
+1000
-177
File diff suppressed because it is too large.
Load diff
+7
-21
@@ -110,7 +110,7 @@ typedef struct audio_driver
|
||||
* Unless said otherwise with set_nonblock_state(), all writes
|
||||
* are blocking, and it should block till it has written all frames.
|
||||
*/
|
||||
ssize_t (*write)(void *data, const void *buf, size_t size);
|
||||
ssize_t (*write)(void *data, const void *s, size_t len);
|
||||
|
||||
/**
|
||||
* Temporarily pauses the audio driver.
|
||||
@@ -169,8 +169,8 @@ typedef struct audio_driver
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double source_ratio_original;
|
||||
double source_ratio_current;
|
||||
double src_ratio_orig;
|
||||
double src_ratio_curr;
|
||||
|
||||
uint64_t free_samples_count;
|
||||
|
||||
@@ -320,17 +320,6 @@ bool audio_driver_start(bool is_shutdown);
|
||||
|
||||
bool audio_driver_stop(void);
|
||||
|
||||
/**
|
||||
* If you need to query the size of audio samples,
|
||||
* use this function instead of checking the flags directly.
|
||||
*
|
||||
* @return The size of a single audio sample in bytes,
|
||||
* as determined by the presence of the \c AUDIO_FLAG_USE_FLOAT flag.
|
||||
* Will currently return either 2 (for \c uint16_t) or 4 (for \c float),
|
||||
* although this may change if we add support for more sample types.
|
||||
*/
|
||||
unsigned audio_driver_get_sample_size(void);
|
||||
|
||||
#ifdef HAVE_TRANSLATE
|
||||
/* TODO/FIXME - Doesn't currently work. Fix this. */
|
||||
bool audio_driver_is_ai_service_speech_running(void);
|
||||
@@ -344,16 +333,12 @@ bool audio_driver_is_ai_service_speech_running(void);
|
||||
**/
|
||||
bool audio_compute_buffer_statistics(audio_statistics_t *stats);
|
||||
|
||||
bool audio_driver_init_internal(
|
||||
void *settings_data,
|
||||
bool audio_cb_inited);
|
||||
bool audio_driver_init_internal(void *data, bool audio_cb_inited);
|
||||
|
||||
bool audio_driver_deinit(void);
|
||||
|
||||
bool audio_driver_find_driver(
|
||||
void *settings_data,
|
||||
const char *prefix,
|
||||
bool verbosity_enabled);
|
||||
bool audio_driver_find_driver(const char *audio_drv,
|
||||
const char *prefix, bool verbosity_enabled);
|
||||
|
||||
/**
|
||||
* audio_driver_sample:
|
||||
@@ -441,6 +426,7 @@ extern audio_driver_t audio_switch_thread;
|
||||
extern audio_driver_t audio_switch_libnx_audren;
|
||||
extern audio_driver_t audio_switch_libnx_audren_thread;
|
||||
extern audio_driver_t audio_rwebaudio;
|
||||
extern audio_driver_t audio_audioworklet;
|
||||
|
||||
audio_driver_state_t *audio_state_get_ptr(void);
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ static void audio_thread_loop(void *data)
|
||||
thr->driver->stop(thr->driver_data);
|
||||
while (thr->stopped)
|
||||
{
|
||||
/* If we stop right after start,
|
||||
/* If we stop right after start,
|
||||
* we might not be able to properly ack.
|
||||
* Signal in the loop instead. */
|
||||
thr->stopped_ack = true;
|
||||
@@ -249,25 +249,21 @@ static bool audio_thread_use_float(void *data)
|
||||
return thr->use_float;
|
||||
}
|
||||
|
||||
static ssize_t audio_thread_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t audio_thread_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
ssize_t _len;
|
||||
audio_thread_t *thr = (audio_thread_t*)data;
|
||||
|
||||
if (!thr)
|
||||
return 0;
|
||||
|
||||
ret = thr->driver->write(thr->driver_data, buf, size);
|
||||
|
||||
if (ret < 0)
|
||||
_len = thr->driver->write(thr->driver_data, s, len);
|
||||
if (_len < 0)
|
||||
{
|
||||
slock_lock(thr->lock);
|
||||
thr->alive = false;
|
||||
scond_signal(thr->cond);
|
||||
slock_unlock(thr->lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static const audio_driver_t audio_thread = {
|
||||
|
||||
+41
-40
@@ -44,11 +44,11 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
const char *alsa_dev = device ? device : "default";
|
||||
int errnum = 0;
|
||||
|
||||
RARCH_DBG("[ALSA]: Requesting device \"%s\" for %s stream\n", alsa_dev, snd_pcm_stream_name(stream));
|
||||
RARCH_DBG("[ALSA] Requesting device \"%s\" for %s stream...\n", alsa_dev, snd_pcm_stream_name(stream));
|
||||
|
||||
if ((errnum = snd_pcm_open(pcm, alsa_dev, stream, mode)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to open %s stream on device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to open %s stream on device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
alsa_dev,
|
||||
snd_strerror(errnum));
|
||||
@@ -58,7 +58,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_malloc(¶ms)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to allocate hardware parameters: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to allocate hardware parameters: %s.\n",
|
||||
snd_strerror(errnum));
|
||||
|
||||
goto error;
|
||||
@@ -66,7 +66,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_any(*pcm, params)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to query hardware parameters from %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to query hardware parameters from %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -78,7 +78,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
? SND_PCM_FORMAT_FLOAT : SND_PCM_FORMAT_S16;
|
||||
stream_info->has_float = (format == SND_PCM_FORMAT_FLOAT);
|
||||
|
||||
RARCH_LOG("[ALSA]: Using %s sample format for %s device \"%s\"\n",
|
||||
RARCH_LOG("[ALSA] Using %s sample format for %s device \"%s\".\n",
|
||||
snd_pcm_format_name(format),
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm)
|
||||
@@ -86,7 +86,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_set_access(*pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to set %s access for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to set %s access for %s device \"%s\": %s.\n",
|
||||
snd_pcm_access_name(SND_PCM_ACCESS_RW_INTERLEAVED),
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -98,7 +98,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_set_format(*pcm, params, format)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to set %s format for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to set %s format for %s device \"%s\": %s.\n",
|
||||
snd_pcm_format_name(format),
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -109,7 +109,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_set_channels(*pcm, params, channels)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to set %u-channel audio for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to set %u-channel audio for %s device \"%s\": %s.\n",
|
||||
channels,
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -121,7 +121,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
/* Don't allow rate resampling when probing for the default rate (but ignore if this call fails) */
|
||||
if ((errnum = snd_pcm_hw_params_set_rate_resample(*pcm, params, false)) < 0)
|
||||
{
|
||||
RARCH_WARN("[ALSA]: Failed to request a default unsampled rate for %s device \"%s\": %s\n",
|
||||
RARCH_WARN("[ALSA] Failed to request a default unsampled rate for %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -129,7 +129,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_set_rate_near(*pcm, params, &rate, 0)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to request a rate near %uHz for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to request a rate near %uHz for %s device \"%s\": %s.\n",
|
||||
rate,
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -143,7 +143,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((snd_pcm_hw_params_set_buffer_time_near(*pcm, params, &latency_usec, NULL)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to request a buffer time near %uus for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to request a buffer time near %uus for %s device \"%s\": %s.\n",
|
||||
latency_usec,
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -155,7 +155,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_set_periods_near(*pcm, params, &periods, NULL)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to request %u periods per buffer for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to request %u periods per buffer for %s device \"%s\": %s.\n",
|
||||
periods,
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -166,7 +166,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_hw_params(*pcm, params)) < 0)
|
||||
{ /* This calls snd_pcm_prepare() under the hood */
|
||||
RARCH_ERR("[ALSA]: Failed to install hardware parameters for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to install hardware parameters for %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -178,15 +178,15 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
* but some drivers are apparently broken. */
|
||||
if ((errnum = snd_pcm_hw_params_get_period_size(params, &stream_info->period_frames, NULL)) < 0)
|
||||
{
|
||||
RARCH_WARN("[ALSA]: Failed to get an exact period size from %s device \"%s\": %s\n",
|
||||
RARCH_WARN("[ALSA] Failed to get an exact period size from %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
RARCH_WARN("[ALSA]: Trying the minimum period size instead\n");
|
||||
RARCH_WARN("[ALSA] Trying the minimum period size instead.\n");
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_get_period_size_min(params, &stream_info->period_frames, NULL)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to get min period size from %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to get min period size from %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -197,28 +197,28 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
stream_info->period_size = snd_pcm_frames_to_bytes(*pcm, stream_info->period_frames);
|
||||
if (stream_info->period_size < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to convert a period size of %lu frames to bytes: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to convert a period size of %lu frames to bytes: %s.\n",
|
||||
stream_info->period_frames,
|
||||
snd_strerror(stream_info->period_frames));
|
||||
goto error;
|
||||
}
|
||||
|
||||
RARCH_LOG("[ALSA]: Period: %u periods per buffer (%lu frames, %lu bytes)\n",
|
||||
RARCH_LOG("[ALSA] Period: %u periods per buffer (%lu frames, %lu bytes).\n",
|
||||
periods,
|
||||
stream_info->period_frames,
|
||||
stream_info->period_size);
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_get_buffer_size(params, &buffer_size)) < 0)
|
||||
{
|
||||
RARCH_WARN("[ALSA]: Failed to get exact buffer size from %s device \"%s\": %s\n",
|
||||
RARCH_WARN("[ALSA] Failed to get exact buffer size from %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
RARCH_WARN("[ALSA]: Trying the maximum buffer size instead\n");
|
||||
RARCH_WARN("[ALSA] Trying the maximum buffer size instead.\n");
|
||||
|
||||
if ((errnum = snd_pcm_hw_params_get_buffer_size_max(params, &buffer_size)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to get max buffer size from %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to get max buffer size from %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -230,20 +230,20 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
stream_info->buffer_size = snd_pcm_frames_to_bytes(*pcm, buffer_size);
|
||||
if (stream_info->buffer_size < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to convert a buffer size of %lu frames to bytes: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to convert a buffer size of %lu frames to bytes: %s.\n",
|
||||
buffer_size,
|
||||
snd_strerror(buffer_size));
|
||||
goto error;
|
||||
}
|
||||
RARCH_LOG("[ALSA]: Buffer size: %lu frames (%lu bytes)\n", buffer_size, stream_info->buffer_size);
|
||||
RARCH_LOG("[ALSA] Buffer size: %lu frames (%lu bytes).\n", buffer_size, stream_info->buffer_size);
|
||||
|
||||
stream_info->can_pause = snd_pcm_hw_params_can_pause(params);
|
||||
|
||||
RARCH_LOG("[ALSA]: Can pause: %s.\n", stream_info->can_pause ? "yes" : "no");
|
||||
RARCH_LOG("[ALSA] Can pause: %s.\n", stream_info->can_pause ? "yes" : "no");
|
||||
|
||||
if ((errnum = snd_pcm_sw_params_malloc(&sw_params)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to allocate software parameters: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to allocate software parameters: %s.\n",
|
||||
snd_strerror(errnum));
|
||||
|
||||
goto error;
|
||||
@@ -251,7 +251,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_sw_params_current(*pcm, sw_params)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to query current software parameters for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to query current software parameters for %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -261,7 +261,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_sw_params_set_start_threshold(*pcm, sw_params, buffer_size / 2)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to set start %lu-frame threshold for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to set start %lu-frame threshold for %s device \"%s\": %s.\n",
|
||||
buffer_size / 2,
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
@@ -272,7 +272,7 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
|
||||
if ((errnum = snd_pcm_sw_params(*pcm, sw_params)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to install software parameters for %s device \"%s\": %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to install software parameters for %s device \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -283,11 +283,12 @@ int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
snd_pcm_hw_params_free(params);
|
||||
snd_pcm_sw_params_free(sw_params);
|
||||
|
||||
RARCH_LOG("[ALSA]: Initialized %s device \"%s\"\n",
|
||||
RARCH_LOG("[ALSA] Initialized %s device \"%s\".\n",
|
||||
snd_pcm_stream_name(stream),
|
||||
snd_pcm_name(*pcm));
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (params)
|
||||
snd_pcm_hw_params_free(params);
|
||||
@@ -312,7 +313,7 @@ void alsa_free_pcm(snd_pcm_t *pcm)
|
||||
|
||||
if ((errnum = snd_pcm_drop(pcm)) < 0)
|
||||
{
|
||||
RARCH_WARN("[ALSA]: Failed to drop remaining samples in %s stream \"%s\": %s\n",
|
||||
RARCH_WARN("[ALSA] Failed to drop remaining samples in %s stream \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -320,7 +321,7 @@ void alsa_free_pcm(snd_pcm_t *pcm)
|
||||
|
||||
if ((errnum = snd_pcm_close(pcm)) < 0)
|
||||
{
|
||||
RARCH_WARN("[ALSA]: Failed to close %s stream \"%s\": %s\n",
|
||||
RARCH_WARN("[ALSA] Failed to close %s stream \"%s\": %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_strerror(errnum));
|
||||
@@ -351,19 +352,19 @@ bool alsa_start_pcm(snd_pcm_t *pcm)
|
||||
|
||||
break;
|
||||
case SND_PCM_STATE_RUNNING:
|
||||
RARCH_DBG("[ALSA]: %s stream \"%s\" is already running, no action needed.\n",
|
||||
RARCH_DBG("[ALSA] %s stream \"%s\" is already running, no action needed.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm));
|
||||
return true;
|
||||
default:
|
||||
RARCH_ERR("[ALSA]: Failed to start %s stream \"%s\" in unexpected state %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to start %s stream \"%s\" in unexpected state %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state));
|
||||
return false;
|
||||
}
|
||||
|
||||
RARCH_DBG("[ALSA]: Started %s stream \"%s\", transitioning from %s to %s\n",
|
||||
RARCH_DBG("[ALSA] Started %s stream \"%s\", transitioning from %s to %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state),
|
||||
@@ -372,7 +373,7 @@ bool alsa_start_pcm(snd_pcm_t *pcm)
|
||||
return true;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA]: Failed to start %s stream \"%s\" in state %s: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to start %s stream \"%s\" in state %s: %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state),
|
||||
@@ -393,12 +394,12 @@ bool alsa_stop_pcm(snd_pcm_t *pcm)
|
||||
switch (pcm_state)
|
||||
{
|
||||
case SND_PCM_STATE_PAUSED:
|
||||
RARCH_DBG("[ALSA]: %s stream \"%s\" is already paused, no action needed.\n",
|
||||
RARCH_DBG("[ALSA] %s stream \"%s\" is already paused, no action needed.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm));
|
||||
return true;
|
||||
case SND_PCM_STATE_PREPARED:
|
||||
RARCH_DBG("[ALSA]: %s stream \"%s\" is prepared but not running, no action needed.\n",
|
||||
RARCH_DBG("[ALSA] %s stream \"%s\" is prepared but not running, no action needed.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm));
|
||||
return true;
|
||||
@@ -409,7 +410,7 @@ bool alsa_stop_pcm(snd_pcm_t *pcm)
|
||||
|
||||
break;
|
||||
default:
|
||||
RARCH_ERR("[ALSA]: Failed to stop %s stream \"%s\" in unexpected state %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to stop %s stream \"%s\" in unexpected state %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state));
|
||||
@@ -417,7 +418,7 @@ bool alsa_stop_pcm(snd_pcm_t *pcm)
|
||||
return false;
|
||||
}
|
||||
|
||||
RARCH_DBG("[ALSA]: Stopped %s stream \"%s\", transitioning from %s to %s\n",
|
||||
RARCH_DBG("[ALSA] Stopped %s stream \"%s\", transitioning from %s to %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state),
|
||||
@@ -426,7 +427,7 @@ bool alsa_stop_pcm(snd_pcm_t *pcm)
|
||||
return true;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA]: Failed to stop %s stream \"%s\" in state %s: %s\n",
|
||||
RARCH_ERR("[ALSA] Failed to stop %s stream \"%s\" in state %s: %s.\n",
|
||||
snd_pcm_stream_name(snd_pcm_stream(pcm)),
|
||||
snd_pcm_name(pcm),
|
||||
snd_pcm_state_name(pcm_state),
|
||||
|
||||
+10
-10
@@ -17,9 +17,8 @@
|
||||
#ifndef _RETROARCH_ALSA
|
||||
#define _RETROARCH_ALSA
|
||||
|
||||
#include <stdint.h>
|
||||
#include <boolean.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
/* Header file for common functions that are used by alsa and alsathread. */
|
||||
|
||||
@@ -38,14 +37,15 @@ typedef struct alsa_stream_info
|
||||
} alsa_stream_info_t;
|
||||
|
||||
int alsa_init_pcm(snd_pcm_t **pcm,
|
||||
const char* device,
|
||||
snd_pcm_stream_t stream,
|
||||
unsigned rate,
|
||||
unsigned latency,
|
||||
unsigned channels,
|
||||
alsa_stream_info_t *stream_info,
|
||||
unsigned *new_rate,
|
||||
int mode);
|
||||
const char* device,
|
||||
snd_pcm_stream_t stream,
|
||||
unsigned rate,
|
||||
unsigned latency,
|
||||
unsigned channels,
|
||||
alsa_stream_info_t *stream_info,
|
||||
unsigned *new_rate,
|
||||
int mode);
|
||||
|
||||
void alsa_free_pcm(snd_pcm_t *pcm);
|
||||
void *alsa_device_list_new(void *data);
|
||||
struct string_list *alsa_device_list_type_new(const char* type);
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 Daniel De Matteis
|
||||
* Copyright (C) 2023 Jesse Talavera-Greenberg
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "alsathread.h"
|
||||
|
||||
void alsa_thread_free_info_members(alsa_thread_info_t *info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
if (info->worker_thread)
|
||||
{
|
||||
slock_lock(info->cond_lock);
|
||||
info->thread_dead = true;
|
||||
slock_unlock(info->cond_lock);
|
||||
sthread_join(info->worker_thread);
|
||||
}
|
||||
if (info->buffer)
|
||||
fifo_free(info->buffer);
|
||||
if (info->cond)
|
||||
scond_free(info->cond);
|
||||
if (info->fifo_lock)
|
||||
slock_free(info->fifo_lock);
|
||||
if (info->cond_lock)
|
||||
slock_free(info->cond_lock);
|
||||
if (info->pcm)
|
||||
alsa_free_pcm(info->pcm);
|
||||
}
|
||||
/* Do NOT free() info itself; it's embedded within another struct
|
||||
* that will be freed. */
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 Daniel De Matteis
|
||||
* Copyright (C) 2023 Jesse Talavera-Greenberg
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef RETROARCH_ALSATHREAD_H
|
||||
#define RETROARCH_ALSATHREAD_H
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <boolean.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
#include "alsa.h"
|
||||
|
||||
typedef struct alsa_thread_info
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
fifo_buffer_t *buffer;
|
||||
sthread_t *worker_thread;
|
||||
slock_t *fifo_lock;
|
||||
scond_t *cond;
|
||||
slock_t *cond_lock;
|
||||
alsa_stream_info_t stream_info;
|
||||
volatile bool thread_dead;
|
||||
} alsa_thread_info_t;
|
||||
|
||||
void alsa_thread_free_info_members(alsa_thread_info_t *info);
|
||||
|
||||
#endif
|
||||
+427
-23
@@ -17,44 +17,400 @@
|
||||
|
||||
#include <encodings/utf.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#include "mmdevice_common.h"
|
||||
#include "mmdevice_common_inline.h"
|
||||
|
||||
char* mmdevice_name(IMMDevice *device)
|
||||
#include "../../verbosity.h"
|
||||
|
||||
static const char *mmdevice_data_flow_name(unsigned data_flow)
|
||||
{
|
||||
switch (data_flow)
|
||||
{
|
||||
case 0:
|
||||
return "eRender";
|
||||
case 1:
|
||||
return "eCapture";
|
||||
case 2:
|
||||
return "eAll";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
const char *mmdevice_hresult_name(int hr)
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
/* Standard error codes */
|
||||
case E_INVALIDARG:
|
||||
return "E_INVALIDARG";
|
||||
case E_NOINTERFACE:
|
||||
return "E_NOINTERFACE";
|
||||
case E_OUTOFMEMORY:
|
||||
return "E_OUTOFMEMORY";
|
||||
case E_POINTER:
|
||||
return "E_POINTER";
|
||||
/* Standard success codes */
|
||||
case S_FALSE:
|
||||
return "S_FALSE";
|
||||
case S_OK:
|
||||
return "S_OK";
|
||||
/* AUDCLNT error codes */
|
||||
case AUDCLNT_E_ALREADY_INITIALIZED:
|
||||
return "AUDCLNT_E_ALREADY_INITIALIZED";
|
||||
case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:
|
||||
return "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL";
|
||||
case AUDCLNT_E_BUFFER_ERROR:
|
||||
return "AUDCLNT_E_BUFFER_ERROR";
|
||||
case AUDCLNT_E_BUFFER_OPERATION_PENDING:
|
||||
return "AUDCLNT_E_BUFFER_OPERATION_PENDING";
|
||||
case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
|
||||
return "AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED";
|
||||
case AUDCLNT_E_BUFFER_SIZE_ERROR:
|
||||
return "AUDCLNT_E_BUFFER_SIZE_ERROR";
|
||||
case AUDCLNT_E_CPUUSAGE_EXCEEDED:
|
||||
return "AUDCLNT_E_CPUUSAGE_EXCEEDED";
|
||||
case AUDCLNT_E_DEVICE_IN_USE:
|
||||
return "AUDCLNT_E_DEVICE_IN_USE";
|
||||
case AUDCLNT_E_DEVICE_INVALIDATED:
|
||||
return "AUDCLNT_E_DEVICE_INVALIDATED";
|
||||
case AUDCLNT_E_ENDPOINT_CREATE_FAILED:
|
||||
return "AUDCLNT_E_ENDPOINT_CREATE_FAILED";
|
||||
case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:
|
||||
return "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED";
|
||||
case AUDCLNT_E_INVALID_DEVICE_PERIOD:
|
||||
return "AUDCLNT_E_INVALID_DEVICE_PERIOD";
|
||||
case AUDCLNT_E_INVALID_SIZE:
|
||||
return "AUDCLNT_E_INVALID_SIZE";
|
||||
case AUDCLNT_E_NOT_INITIALIZED:
|
||||
return "AUDCLNT_E_NOT_INITIALIZED";
|
||||
case AUDCLNT_E_OUT_OF_ORDER:
|
||||
return "AUDCLNT_E_OUT_OF_ORDER";
|
||||
case AUDCLNT_E_SERVICE_NOT_RUNNING:
|
||||
return "AUDCLNT_E_SERVICE_NOT_RUNNING";
|
||||
case AUDCLNT_E_UNSUPPORTED_FORMAT:
|
||||
return "AUDCLNT_E_UNSUPPORTED_FORMAT";
|
||||
case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
|
||||
return "AUDCLNT_E_WRONG_ENDPOINT_TYPE";
|
||||
/* AUDCLNT success codes */
|
||||
case AUDCLNT_S_BUFFER_EMPTY:
|
||||
return "AUDCLNT_S_BUFFER_EMPTY";
|
||||
/* Something else; probably from an API that we started using
|
||||
* after mic support was implemented */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
size_t mmdevice_samplerate(void *data)
|
||||
{
|
||||
HRESULT hr;
|
||||
IPropertyStore *prop_store = NULL;
|
||||
PWAVEFORMATEX devfmt_props;
|
||||
PROPVARIANT prop_var;
|
||||
bool prop_var_init = false;
|
||||
IMMDevice *device = (IMMDevice*)data;
|
||||
IPropertyStore *prop_store = NULL;
|
||||
DWORD result = 0;
|
||||
|
||||
if (!device)
|
||||
return 0;
|
||||
|
||||
hr = _IMMDevice_OpenPropertyStore(device,
|
||||
STGM_READ, &prop_store);
|
||||
|
||||
if (FAILED(hr))
|
||||
return 0;
|
||||
|
||||
PropVariantInit(&prop_var);
|
||||
hr = _IPropertyStore_GetValue(prop_store,
|
||||
PKEY_AudioEngine_DeviceFormat, &prop_var);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
devfmt_props = (PWAVEFORMATEX)prop_var.blob.pBlobData;
|
||||
result = devfmt_props->nSamplesPerSec;
|
||||
}
|
||||
|
||||
PropVariantClear(&prop_var);
|
||||
if (prop_store)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
prop_store->Release();
|
||||
#else
|
||||
prop_store->lpVtbl->Release(prop_store);
|
||||
#endif
|
||||
prop_store = NULL;
|
||||
}
|
||||
return (size_t)result;
|
||||
}
|
||||
|
||||
char *mmdevice_name(void *data)
|
||||
{
|
||||
HRESULT hr;
|
||||
PROPVARIANT prop_var;
|
||||
IMMDevice *device = (IMMDevice*)data;
|
||||
IPropertyStore *prop_store = NULL;
|
||||
char* result = NULL;
|
||||
|
||||
if (!device)
|
||||
return NULL;
|
||||
|
||||
hr = _IMMDevice_OpenPropertyStore(device, STGM_READ, &prop_store);
|
||||
hr = _IMMDevice_OpenPropertyStore(device,
|
||||
STGM_READ, &prop_store);
|
||||
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
|
||||
PropVariantInit(&prop_var);
|
||||
prop_var_init = true;
|
||||
hr = _IPropertyStore_GetValue(prop_store, PKEY_Device_FriendlyName, &prop_var);
|
||||
if (FAILED(hr))
|
||||
goto done;
|
||||
|
||||
result = utf16_to_utf8_string_alloc(prop_var.pwszVal);
|
||||
|
||||
done:
|
||||
if (prop_var_init)
|
||||
PropVariantClear(&prop_var);
|
||||
|
||||
IFACE_RELEASE(prop_store);
|
||||
hr = _IPropertyStore_GetValue(prop_store,
|
||||
PKEY_Device_FriendlyName, &prop_var);
|
||||
if (SUCCEEDED(hr))
|
||||
result = utf16_to_utf8_string_alloc(prop_var.pwszVal);
|
||||
|
||||
PropVariantClear(&prop_var);
|
||||
if (prop_store)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
prop_store->Release();
|
||||
#else
|
||||
prop_store->lpVtbl->Release(prop_store);
|
||||
#endif
|
||||
prop_store = NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void *mmdevice_list_new(const void *u, EDataFlow data_flow)
|
||||
void *mmdevice_handle(int id, unsigned data_flow)
|
||||
{
|
||||
HRESULT hr;
|
||||
IMMDeviceEnumerator *enumerator = NULL;
|
||||
IMMDevice *device = NULL;
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
#ifdef __cplusplus
|
||||
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#else
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#endif
|
||||
if (FAILED(hr))
|
||||
return NULL;
|
||||
hr = _IMMDeviceEnumerator_EnumAudioEndpoints(enumerator,
|
||||
data_flow, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to enumerate audio endpoints: %s.\n", mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IMMDeviceCollection_Item(collection, id, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to get IMMDevice #%d: %s.\n", id, mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
return device;
|
||||
|
||||
error:
|
||||
if (collection)
|
||||
#ifdef __cplusplus
|
||||
collection->Release();
|
||||
#else
|
||||
collection->lpVtbl->Release(collection);
|
||||
#endif
|
||||
if (enumerator)
|
||||
#ifdef __cplusplus
|
||||
enumerator->Release();
|
||||
#else
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
#endif
|
||||
collection = NULL;
|
||||
enumerator = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t mmdevice_get_samplerate(int id)
|
||||
{
|
||||
IMMDevice *device = (IMMDevice*)mmdevice_handle(id, 0 /* eRender */);
|
||||
if (device)
|
||||
{
|
||||
size_t _len = mmdevice_samplerate(device);
|
||||
#ifdef __cplusplus
|
||||
device->Release();
|
||||
#else
|
||||
device->lpVtbl->Release(device);
|
||||
#endif
|
||||
return _len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *mmdevice_init_device(const char *id, unsigned data_flow)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 dev_count, i;
|
||||
IMMDeviceEnumerator *enumerator = NULL;
|
||||
IMMDevice *device = NULL;
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
const char *data_flow_name = mmdevice_data_flow_name(data_flow);
|
||||
|
||||
if (id)
|
||||
RARCH_DBG("[MMDevice] Initializing %s device \"%s\"...\n", data_flow_name, id);
|
||||
else
|
||||
RARCH_DBG("[MMDevice] Initializing default %s device...\n", data_flow_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#else
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#endif
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to create device enumerator: %s.\n", mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (id)
|
||||
{
|
||||
/* If a specific device was requested... */
|
||||
int32_t idx_found = -1;
|
||||
struct string_list *list = (struct string_list*)mmdevice_list_new(NULL, data_flow);
|
||||
|
||||
if (!list)
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to allocate %s device list.\n", data_flow_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (list->elems)
|
||||
{
|
||||
size_t d;
|
||||
/* If any devices were found... */
|
||||
for (d = 0; d < list->size; d++)
|
||||
{
|
||||
if (string_is_equal(id, list->elems[d].data))
|
||||
{
|
||||
RARCH_DBG("[MMDevice] Found device #%d: \"%s\".\n", d,
|
||||
list->elems[d].data);
|
||||
idx_found = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Index was not found yet based on name string,
|
||||
* just assume id is a one-character number index. */
|
||||
if (idx_found == -1 && isdigit(id[0]))
|
||||
{
|
||||
idx_found = strtoul(id, NULL, 0);
|
||||
RARCH_LOG("[MMDevice] Fallback, %s device index is a single number index instead: %u.\n",
|
||||
data_flow_name, idx_found);
|
||||
}
|
||||
}
|
||||
string_list_free(list);
|
||||
|
||||
if (idx_found == -1)
|
||||
idx_found = 0;
|
||||
|
||||
hr = _IMMDeviceEnumerator_EnumAudioEndpoints(enumerator,
|
||||
data_flow, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to enumerate audio endpoints: %s.\n", mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IMMDeviceCollection_GetCount(collection, &dev_count);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to count IMMDevices: %s.\n", mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_count; ++i)
|
||||
{
|
||||
hr = _IMMDeviceCollection_Item(collection, i, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to get IMMDevice #%d: %s.\n", i, mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (i == (UINT32)idx_found)
|
||||
break;
|
||||
|
||||
if (device)
|
||||
#ifdef __cplusplus
|
||||
device->Release();
|
||||
#else
|
||||
device->lpVtbl->Release(device);
|
||||
#endif
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = _IMMDeviceEnumerator_GetDefaultAudioEndpoint(
|
||||
enumerator, data_flow, eConsole, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[MMDevice] Failed to get default audio endpoint: %s.\n", mmdevice_hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device)
|
||||
goto error;
|
||||
|
||||
if (collection)
|
||||
#ifdef __cplusplus
|
||||
collection->Release();
|
||||
#else
|
||||
collection->lpVtbl->Release(collection);
|
||||
#endif
|
||||
if (enumerator)
|
||||
#ifdef __cplusplus
|
||||
enumerator->Release();
|
||||
#else
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
#endif
|
||||
collection = NULL;
|
||||
enumerator = NULL;
|
||||
|
||||
return device;
|
||||
|
||||
error:
|
||||
if (collection)
|
||||
#ifdef __cplusplus
|
||||
collection->Release();
|
||||
#else
|
||||
collection->lpVtbl->Release(collection);
|
||||
#endif
|
||||
if (enumerator)
|
||||
#ifdef __cplusplus
|
||||
enumerator->Release();
|
||||
#else
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
#endif
|
||||
collection = NULL;
|
||||
enumerator = NULL;
|
||||
|
||||
if (id)
|
||||
RARCH_WARN("[MMDevice] Failed to initialize %s device \"%s\".\n", data_flow_name, id);
|
||||
else
|
||||
RARCH_ERR("[MMDevice] Failed to initialize default %s device.\n", data_flow_name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *mmdevice_list_new(const void *u, unsigned data_flow)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT i;
|
||||
@@ -120,11 +476,35 @@ void *mmdevice_list_new(const void *u, EDataFlow data_flow)
|
||||
free(dev_name_str);
|
||||
dev_name_str = NULL;
|
||||
dev_id_wstr = NULL;
|
||||
IFACE_RELEASE(device);
|
||||
if (device)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
device->Release();
|
||||
#else
|
||||
device->lpVtbl->Release(device);
|
||||
#endif
|
||||
device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
IFACE_RELEASE(collection);
|
||||
IFACE_RELEASE(enumerator);
|
||||
if (collection)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
collection->Release();
|
||||
#else
|
||||
collection->lpVtbl->Release(collection);
|
||||
#endif
|
||||
collection = NULL;
|
||||
}
|
||||
if (enumerator)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
enumerator->Release();
|
||||
#else
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
#endif
|
||||
enumerator = NULL;
|
||||
}
|
||||
|
||||
return sl;
|
||||
|
||||
@@ -138,9 +518,33 @@ error:
|
||||
if (dev_id_wstr)
|
||||
CoTaskMemFree(dev_id_wstr);
|
||||
dev_id_wstr = NULL;
|
||||
IFACE_RELEASE(device);
|
||||
IFACE_RELEASE(collection);
|
||||
IFACE_RELEASE(enumerator);
|
||||
if (device)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
device->Release();
|
||||
#else
|
||||
device->lpVtbl->Release(device);
|
||||
#endif
|
||||
device = NULL;
|
||||
}
|
||||
if (collection)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
collection->Release();
|
||||
#else
|
||||
collection->lpVtbl->Release(collection);
|
||||
#endif
|
||||
collection = NULL;
|
||||
}
|
||||
if (enumerator)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
enumerator->Release();
|
||||
#else
|
||||
enumerator->lpVtbl->Release(enumerator);
|
||||
#endif
|
||||
enumerator = NULL;
|
||||
}
|
||||
if (sl)
|
||||
string_list_free(sl);
|
||||
|
||||
|
||||
@@ -19,17 +19,33 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include "mmdevice_common_inline.h"
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
void *mmdevice_list_new(const void *u, EDataFlow data_flow);
|
||||
void *mmdevice_list_new(const void *u, unsigned data_flow);
|
||||
|
||||
/**
|
||||
* Gets the friendly name of the provided IMMDevice.
|
||||
* The string must be freed with free().
|
||||
*/
|
||||
char* mmdevice_name(IMMDevice *device);
|
||||
char* mmdevice_name(void *data);
|
||||
|
||||
/**
|
||||
* Gets the samplerate of the provided IMMDevice.
|
||||
*/
|
||||
size_t mmdevice_samplerate(void *data);
|
||||
|
||||
/**
|
||||
* Gets the handle of the IMMDevice.
|
||||
*/
|
||||
void *mmdevice_handle(int id, unsigned data_flow);
|
||||
|
||||
size_t mmdevice_get_samplerate(int id);
|
||||
|
||||
const char *mmdevice_hresult_name(int hr);
|
||||
|
||||
|
||||
void *mmdevice_init_device(const char *id, unsigned data_flow);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
|
||||
@@ -1,143 +1,114 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MMDEVICE_COMMON_INLINE_H
|
||||
#define _MMDEVICE_COMMON_INLINE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Fix for MSYS2 increasing _WIN32_WINNT to 0x0603*/
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#ifdef _WIN32_WINNT
|
||||
#undef _WIN32_WINNT
|
||||
#endif
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#else
|
||||
typedef enum EDataFlow EDataFlow;
|
||||
/* MinGW defines EDataFlow differently than MSVC does;
|
||||
* this typedef smooths that over. */
|
||||
#endif
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include <winerror.h>
|
||||
#include <propidl.h>
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <mmreg.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1CB9AD4C, 0xDBFA, 0x4C32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2);
|
||||
DEFINE_GUID(IID_IAudioRenderClient, 0xF294ACFC, 0x3146, 0x4483, 0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2);
|
||||
DEFINE_GUID(IID_IAudioCaptureClient, 0xC8ADBD64, 0xE71E, 0x48A0, 0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
#undef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
||||
#endif
|
||||
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); /* DEVPROP_TYPE_STRING */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _IMMDeviceCollection_Item(This,nDevice,ppdevice) (This)->Item(nDevice,ppdevice)
|
||||
#define _IAudioClient_Start(This) ( (This)->Start() )
|
||||
#define _IAudioClient_Stop(This) ( (This)->Stop() )
|
||||
#define _IAudioClient_GetCurrentPadding(This,pNumPaddingFrames) \
|
||||
( (This)->GetCurrentPadding(pNumPaddingFrames) )
|
||||
#define _IAudioRenderClient_GetBuffer(This,NumFramesRequested,ppData) \
|
||||
( (This)->GetBuffer(NumFramesRequested,ppData) )
|
||||
#define _IAudioRenderClient_ReleaseBuffer(This,NumFramesWritten,dwFlags) \
|
||||
( (This)->ReleaseBuffer(NumFramesWritten,dwFlags) )
|
||||
#define _IAudioClient_GetService(This,riid,ppv) ( (This)->GetService(riid,ppv) )
|
||||
#define _IAudioClient_SetEventHandle(This,eventHandle) ( (This)->SetEventHandle(eventHandle) )
|
||||
#define _IAudioClient_GetBufferSize(This,pNumBufferFrames) ( (This)->GetBufferSize(pNumBufferFrames) )
|
||||
#define _IAudioClient_GetStreamLatency(This,phnsLatency) ( (This)->GetStreamLatency(phnsLatency) )
|
||||
#define _IAudioClient_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) ( (This)->GetDevicePeriod(phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) )
|
||||
#define _IAudioClient_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \
|
||||
( (This)->Initialize(ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid))
|
||||
#define _IAudioClient_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \
|
||||
( (This)->IsFormatSupported(ShareMode,pFormat,ppClosestMatch))
|
||||
#define _IMMDevice_Activate(This,iid,dwClsCtx,pActivationParams,ppv) ((This)->Activate(iid,(dwClsCtx),pActivationParams,ppv))
|
||||
#define _IMMDeviceEnumerator_EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) (This)->EnumAudioEndpoints(dataFlow,dwStateMask,ppDevices)
|
||||
#define _IMMDeviceEnumerator_GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) (This)->GetDefaultAudioEndpoint(dataFlow,role,ppEndpoint)
|
||||
#define _IMMDevice_OpenPropertyStore(This,stgmAccess,ppProperties) (This)->OpenPropertyStore(stgmAccess,ppProperties)
|
||||
#define _IMMDevice_GetId(This,ppstrId) ((This)->GetId(ppstrId))
|
||||
#define _IPropertyStore_GetValue(This,key,pv) ( (This)->GetValue(key,pv) )
|
||||
#define _IMMDeviceCollection_GetCount(This,cProps) ( (This)->GetCount(cProps) )
|
||||
#define _IAudioCaptureClient_GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) \
|
||||
( (This) -> GetBuffer(ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) )
|
||||
#define _IAudioCaptureClient_ReleaseBuffer(This,NumFramesRead) \
|
||||
( (This) -> ReleaseBuffer(NumFramesRead) )
|
||||
#define _IAudioCaptureClient_GetNextPacketSize(This,pNumFramesInNextPacket) \
|
||||
( (This) -> GetNextPacketSize(pNumFramesInNextPacket) )
|
||||
#else
|
||||
#define _IMMDeviceCollection_Item(This,nDevice,ppdevice) (This)->lpVtbl->Item(This,nDevice,ppdevice)
|
||||
#define _IAudioClient_Start(This) ( (This)->lpVtbl -> Start(This) )
|
||||
#define _IAudioClient_Stop(This) ( (This)->lpVtbl -> Stop(This) )
|
||||
#define _IAudioClient_GetCurrentPadding(This,pNumPaddingFrames) \
|
||||
( (This)->lpVtbl -> GetCurrentPadding(This,pNumPaddingFrames) )
|
||||
#define _IAudioRenderClient_GetBuffer(This,NumFramesRequested,ppData) \
|
||||
( (This)->lpVtbl -> GetBuffer(This,NumFramesRequested,ppData) )
|
||||
#define _IAudioRenderClient_ReleaseBuffer(This,NumFramesWritten,dwFlags) \
|
||||
( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesWritten,dwFlags) )
|
||||
#define _IAudioClient_GetService(This,riid,ppv) ( (This)->lpVtbl -> GetService(This,&(riid),ppv) )
|
||||
#define _IAudioClient_SetEventHandle(This,eventHandle) ( (This)->lpVtbl -> SetEventHandle(This,eventHandle) )
|
||||
#define _IAudioClient_GetBufferSize(This,pNumBufferFrames) ( (This)->lpVtbl -> GetBufferSize(This,pNumBufferFrames) )
|
||||
#define _IAudioClient_GetStreamLatency(This,phnsLatency) ( (This)->lpVtbl -> GetStreamLatency(This,phnsLatency) )
|
||||
#define _IAudioClient_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) ( (This)->lpVtbl -> GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) )
|
||||
#define _IAudioClient_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \
|
||||
( (This)->lpVtbl->Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid))
|
||||
#define _IAudioClient_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \
|
||||
( (This)->lpVtbl->IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch))
|
||||
#define _IMMDevice_Activate(This,iid,dwClsCtx,pActivationParams,ppv) ((This)->lpVtbl->Activate(This,&(iid),dwClsCtx,pActivationParams,ppv))
|
||||
#define _IMMDeviceEnumerator_EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) (This)->lpVtbl->EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices)
|
||||
#define _IMMDeviceEnumerator_GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) (This)->lpVtbl->GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint)
|
||||
#define _IMMDevice_OpenPropertyStore(This,stgmAccess,ppProperties) (This)->lpVtbl->OpenPropertyStore(This,stgmAccess,ppProperties)
|
||||
#define _IMMDevice_GetId(This,ppstrId) (This)->lpVtbl->GetId(This,ppstrId)
|
||||
#define _IPropertyStore_GetValue(This,key,pv) ( (This)->lpVtbl -> GetValue(This,&(key),pv) )
|
||||
#define _IMMDeviceCollection_GetCount(This,cProps) ( (This)->lpVtbl -> GetCount(This,cProps) )
|
||||
#define _IAudioCaptureClient_GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) \
|
||||
( (This)->lpVtbl -> GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) )
|
||||
#define _IAudioCaptureClient_ReleaseBuffer(This,NumFramesRead) \
|
||||
( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesRead) )
|
||||
#define _IAudioCaptureClient_GetNextPacketSize(This,pNumFramesInNextPacket) \
|
||||
( (This)-> lpVtbl -> GetNextPacketSize(This,pNumFramesInNextPacket) )
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifndef IFACE_RELEASE
|
||||
#define IFACE_RELEASE(iface) \
|
||||
if (iface) \
|
||||
{ \
|
||||
iface->Release(); \
|
||||
iface = NULL; \
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#ifndef IFACE_RELEASE
|
||||
#define IFACE_RELEASE(iface) \
|
||||
if (iface) \
|
||||
{ \
|
||||
iface->lpVtbl->Release(iface);\
|
||||
iface = NULL; \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _MMDEVICE_COMMON_INLINE_H
|
||||
#define _MMDEVICE_COMMON_INLINE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Fix for MSYS2 increasing _WIN32_WINNT to 0x0603 */
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <winerror.h>
|
||||
#include <propidl.h>
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
#include <mmreg.h>
|
||||
#include <audioclient.h>
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
DEFINE_GUID(IID_IAudioClient, 0x1CB9AD4C, 0xDBFA, 0x4C32, 0xB1, 0x78, 0xC2, 0xF5, 0x68, 0xA7, 0x03, 0xB2);
|
||||
DEFINE_GUID(IID_IAudioRenderClient, 0xF294ACFC, 0x3146, 0x4483, 0xA7, 0xBF, 0xAD, 0xDC, 0xA7, 0xC2, 0x60, 0xE2);
|
||||
DEFINE_GUID(IID_IAudioCaptureClient, 0xC8ADBD64, 0xE71E, 0x48A0, 0xA4, 0xDE, 0x18, 0x5C, 0x39, 0x5C, 0xD3, 0x17);
|
||||
DEFINE_GUID(IID_IMMDeviceEnumerator, 0xA95664D2, 0x9614, 0x4F35, 0xA7, 0x46, 0xDE, 0x8D, 0xB6, 0x36, 0x17, 0xE6);
|
||||
DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E);
|
||||
#undef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71);
|
||||
#endif
|
||||
|
||||
DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14); /* DEVPROP_TYPE_STRING */
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define _IMMDeviceCollection_Item(This,nDevice,ppdevice) (This)->Item(nDevice,ppdevice)
|
||||
#define _IAudioClient_Start(This) ( (This)->Start() )
|
||||
#define _IAudioClient_Stop(This) ( (This)->Stop() )
|
||||
#define _IAudioClient_GetCurrentPadding(This,pNumPaddingFrames) \
|
||||
( (This)->GetCurrentPadding(pNumPaddingFrames) )
|
||||
#define _IAudioRenderClient_GetBuffer(This,NumFramesRequested,ppData) \
|
||||
( (This)->GetBuffer(NumFramesRequested,ppData) )
|
||||
#define _IAudioRenderClient_ReleaseBuffer(This,NumFramesWritten,dwFlags) \
|
||||
( (This)->ReleaseBuffer(NumFramesWritten,dwFlags) )
|
||||
#define _IAudioClient_GetService(This,riid,ppv) ( (This)->GetService(riid,ppv) )
|
||||
#define _IAudioClient_SetEventHandle(This,eventHandle) ( (This)->SetEventHandle(eventHandle) )
|
||||
#define _IAudioClient_GetBufferSize(This,pNumBufferFrames) ( (This)->GetBufferSize(pNumBufferFrames) )
|
||||
#define _IAudioClient_GetStreamLatency(This,phnsLatency) ( (This)->GetStreamLatency(phnsLatency) )
|
||||
#define _IAudioClient_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) ( (This)->GetDevicePeriod(phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) )
|
||||
#define _IAudioClient_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \
|
||||
( (This)->Initialize(ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid))
|
||||
#define _IAudioClient_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \
|
||||
( (This)->IsFormatSupported(ShareMode,pFormat,ppClosestMatch))
|
||||
#define _IMMDevice_Activate(This,iid,dwClsCtx,pActivationParams,ppv) ((This)->Activate(iid,(dwClsCtx),pActivationParams,ppv))
|
||||
#define _IMMDeviceEnumerator_EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) (This)->EnumAudioEndpoints(dataFlow,dwStateMask,ppDevices)
|
||||
#define _IMMDeviceEnumerator_GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) (This)->GetDefaultAudioEndpoint(dataFlow,role,ppEndpoint)
|
||||
#define _IMMDevice_OpenPropertyStore(This,stgmAccess,ppProperties) (This)->OpenPropertyStore(stgmAccess,ppProperties)
|
||||
#define _IMMDevice_GetId(This,ppstrId) ((This)->GetId(ppstrId))
|
||||
#define _IPropertyStore_GetValue(This,key,pv) ( (This)->GetValue(key,pv) )
|
||||
#define _IMMDeviceCollection_GetCount(This,cProps) ( (This)->GetCount(cProps) )
|
||||
#define _IAudioCaptureClient_GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) \
|
||||
( (This) -> GetBuffer(ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) )
|
||||
#define _IAudioCaptureClient_ReleaseBuffer(This,NumFramesRead) \
|
||||
( (This) -> ReleaseBuffer(NumFramesRead) )
|
||||
#define _IAudioCaptureClient_GetNextPacketSize(This,pNumFramesInNextPacket) \
|
||||
( (This) -> GetNextPacketSize(pNumFramesInNextPacket) )
|
||||
#else
|
||||
#define _IMMDeviceCollection_Item(This,nDevice,ppdevice) (This)->lpVtbl->Item(This,nDevice,ppdevice)
|
||||
#define _IAudioClient_Start(This) ( (This)->lpVtbl -> Start(This) )
|
||||
#define _IAudioClient_Stop(This) ( (This)->lpVtbl -> Stop(This) )
|
||||
#define _IAudioClient_GetCurrentPadding(This,pNumPaddingFrames) \
|
||||
( (This)->lpVtbl -> GetCurrentPadding(This,pNumPaddingFrames) )
|
||||
#define _IAudioRenderClient_GetBuffer(This,NumFramesRequested,ppData) \
|
||||
( (This)->lpVtbl -> GetBuffer(This,NumFramesRequested,ppData) )
|
||||
#define _IAudioRenderClient_ReleaseBuffer(This,NumFramesWritten,dwFlags) \
|
||||
( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesWritten,dwFlags) )
|
||||
#define _IAudioClient_GetService(This,riid,ppv) ( (This)->lpVtbl -> GetService(This,&(riid),ppv) )
|
||||
#define _IAudioClient_SetEventHandle(This,eventHandle) ( (This)->lpVtbl -> SetEventHandle(This,eventHandle) )
|
||||
#define _IAudioClient_GetBufferSize(This,pNumBufferFrames) ( (This)->lpVtbl -> GetBufferSize(This,pNumBufferFrames) )
|
||||
#define _IAudioClient_GetStreamLatency(This,phnsLatency) ( (This)->lpVtbl -> GetStreamLatency(This,phnsLatency) )
|
||||
#define _IAudioClient_GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) ( (This)->lpVtbl -> GetDevicePeriod(This,phnsDefaultDevicePeriod,phnsMinimumDevicePeriod) )
|
||||
#define _IAudioClient_Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid) \
|
||||
( (This)->lpVtbl->Initialize(This,ShareMode,StreamFlags,hnsBufferDuration,hnsPeriodicity,pFormat,AudioSessionGuid))
|
||||
#define _IAudioClient_IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch) \
|
||||
( (This)->lpVtbl->IsFormatSupported(This,ShareMode,pFormat,ppClosestMatch))
|
||||
#define _IMMDevice_Activate(This,iid,dwClsCtx,pActivationParams,ppv) ((This)->lpVtbl->Activate(This,&(iid),dwClsCtx,pActivationParams,ppv))
|
||||
#define _IMMDeviceEnumerator_EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices) (This)->lpVtbl->EnumAudioEndpoints(This,dataFlow,dwStateMask,ppDevices)
|
||||
#define _IMMDeviceEnumerator_GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint) (This)->lpVtbl->GetDefaultAudioEndpoint(This,dataFlow,role,ppEndpoint)
|
||||
#define _IMMDevice_OpenPropertyStore(This,stgmAccess,ppProperties) (This)->lpVtbl->OpenPropertyStore(This,stgmAccess,ppProperties)
|
||||
#define _IMMDevice_GetId(This,ppstrId) (This)->lpVtbl->GetId(This,ppstrId)
|
||||
#define _IPropertyStore_GetValue(This,key,pv) ( (This)->lpVtbl -> GetValue(This,&(key),pv) )
|
||||
#define _IMMDeviceCollection_GetCount(This,cProps) ( (This)->lpVtbl -> GetCount(This,cProps) )
|
||||
#define _IAudioCaptureClient_GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) \
|
||||
( (This)->lpVtbl -> GetBuffer(This,ppData,pNumFramesToRead,pdwFlags,pu64DevicePosition,pu64QPCPosition) )
|
||||
#define _IAudioCaptureClient_ReleaseBuffer(This,NumFramesRead) \
|
||||
( (This)->lpVtbl -> ReleaseBuffer(This,NumFramesRead) )
|
||||
#define _IAudioCaptureClient_GetNextPacketSize(This,pNumFramesInNextPacket) \
|
||||
( (This)-> lpVtbl -> GetNextPacketSize(This,pNumFramesInNextPacket) )
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+81
-83
@@ -16,22 +16,20 @@
|
||||
#include "pipewire.h"
|
||||
|
||||
#include <spa/utils/result.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include <retro_assert.h>
|
||||
|
||||
#include "verbosity.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
|
||||
static void core_error_cb(void *data, uint32_t id, int seq, int res, const char *message)
|
||||
{
|
||||
pipewire_core_t *pw = (pipewire_core_t*)data;
|
||||
|
||||
RARCH_ERR("[PipeWire]: error id:%u seq:%d res:%d (%s): %s\n",
|
||||
RARCH_ERR("[PipeWire] Error id:%u seq:%d res:%d (%s): %s.\n",
|
||||
id, seq, res, spa_strerror(res), message);
|
||||
|
||||
/* stop and exit the thread loop */
|
||||
pw_thread_loop_stop(pw->thread_loop);
|
||||
}
|
||||
|
||||
@@ -42,11 +40,9 @@ static void core_done_cb(void *data, uint32_t id, int seq)
|
||||
retro_assert(id == PW_ID_CORE);
|
||||
|
||||
pw->last_seq = seq;
|
||||
|
||||
if (pw->pending_seq == seq)
|
||||
{
|
||||
/* stop and exit the thread loop */
|
||||
pw_thread_loop_signal(pw->thread_loop, false);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct pw_core_events core_events = {
|
||||
@@ -55,66 +51,7 @@ static const struct pw_core_events core_events = {
|
||||
.error = core_error_cb,
|
||||
};
|
||||
|
||||
size_t calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels)
|
||||
{
|
||||
uint32_t sample_size = 1;
|
||||
switch (fmt)
|
||||
{
|
||||
case SPA_AUDIO_FORMAT_S8:
|
||||
case SPA_AUDIO_FORMAT_U8:
|
||||
sample_size = 1;
|
||||
break;
|
||||
case SPA_AUDIO_FORMAT_S16_BE:
|
||||
case SPA_AUDIO_FORMAT_S16_LE:
|
||||
case SPA_AUDIO_FORMAT_U16_BE:
|
||||
case SPA_AUDIO_FORMAT_U16_LE:
|
||||
sample_size = 2;
|
||||
break;
|
||||
case SPA_AUDIO_FORMAT_S32_BE:
|
||||
case SPA_AUDIO_FORMAT_S32_LE:
|
||||
case SPA_AUDIO_FORMAT_U32_BE:
|
||||
case SPA_AUDIO_FORMAT_U32_LE:
|
||||
case SPA_AUDIO_FORMAT_F32_BE:
|
||||
case SPA_AUDIO_FORMAT_F32_LE:
|
||||
sample_size = 4;
|
||||
break;
|
||||
default:
|
||||
RARCH_ERR("[PipeWire]: Bad spa_audio_format %d\n", fmt);
|
||||
break;
|
||||
}
|
||||
return sample_size * nchannels;
|
||||
}
|
||||
|
||||
void set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
|
||||
{
|
||||
memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
|
||||
sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
|
||||
|
||||
switch (channels)
|
||||
{
|
||||
case 8:
|
||||
position[6] = SPA_AUDIO_CHANNEL_SL;
|
||||
position[7] = SPA_AUDIO_CHANNEL_SR;
|
||||
/* fallthrough */
|
||||
case 6:
|
||||
position[2] = SPA_AUDIO_CHANNEL_FC;
|
||||
position[3] = SPA_AUDIO_CHANNEL_LFE;
|
||||
position[4] = SPA_AUDIO_CHANNEL_RL;
|
||||
position[5] = SPA_AUDIO_CHANNEL_RR;
|
||||
/* fallthrough */
|
||||
case 2:
|
||||
position[0] = SPA_AUDIO_CHANNEL_FL;
|
||||
position[1] = SPA_AUDIO_CHANNEL_FR;
|
||||
break;
|
||||
case 1:
|
||||
position[0] = SPA_AUDIO_CHANNEL_MONO;
|
||||
break;
|
||||
default:
|
||||
RARCH_ERR("[PipeWire]: Internal error: unsupported channel count %d\n", channels);
|
||||
}
|
||||
}
|
||||
|
||||
void pipewire_wait_resync(pipewire_core_t *pw)
|
||||
void pipewire_core_wait_resync(pipewire_core_t *pw)
|
||||
{
|
||||
retro_assert(pw);
|
||||
pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
|
||||
@@ -127,7 +64,7 @@ void pipewire_wait_resync(pipewire_core_t *pw)
|
||||
}
|
||||
}
|
||||
|
||||
bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active)
|
||||
bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active)
|
||||
{
|
||||
enum pw_stream_state st;
|
||||
const char *error;
|
||||
@@ -144,31 +81,92 @@ bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream,
|
||||
return active ? st == PW_STREAM_STATE_STREAMING : st == PW_STREAM_STATE_PAUSED;
|
||||
}
|
||||
|
||||
bool pipewire_core_init(pipewire_core_t *pw, const char *loop_name)
|
||||
bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events)
|
||||
{
|
||||
retro_assert(pw);
|
||||
retro_assert(!*pw);
|
||||
|
||||
pw->thread_loop = pw_thread_loop_new(loop_name, NULL);
|
||||
if (!pw->thread_loop)
|
||||
*pw = (pipewire_core_t*)calloc(1, sizeof(pipewire_core_t));
|
||||
if (!*pw)
|
||||
return false;
|
||||
|
||||
pw->ctx = pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
|
||||
if (!pw->ctx)
|
||||
(*pw)->devicelist = string_list_new();
|
||||
if (!(*pw)->devicelist)
|
||||
{
|
||||
free(*pw);
|
||||
*pw = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
|
||||
(*pw)->thread_loop = pw_thread_loop_new(loop_name, NULL);
|
||||
if (!(*pw)->thread_loop)
|
||||
return false;
|
||||
|
||||
if (pw_thread_loop_start(pw->thread_loop) < 0)
|
||||
(*pw)->ctx = pw_context_new(pw_thread_loop_get_loop((*pw)->thread_loop), NULL, 0);
|
||||
if (!(*pw)->ctx)
|
||||
return false;
|
||||
|
||||
pw_thread_loop_lock(pw->thread_loop);
|
||||
|
||||
pw->core = pw_context_connect(pw->ctx, NULL, 0);
|
||||
if(!pw->core)
|
||||
if (pw_thread_loop_start((*pw)->thread_loop) < 0)
|
||||
return false;
|
||||
|
||||
if (pw_core_add_listener(pw->core,
|
||||
&pw->core_listener,
|
||||
&core_events, pw) < 0)
|
||||
return false;
|
||||
pw_thread_loop_lock((*pw)->thread_loop);
|
||||
|
||||
(*pw)->core = pw_context_connect((*pw)->ctx, NULL, 0);
|
||||
if (!(*pw)->core)
|
||||
goto unlock;
|
||||
|
||||
if (pw_core_add_listener((*pw)->core,
|
||||
&(*pw)->core_listener,
|
||||
&core_events, *pw) < 0)
|
||||
goto unlock;
|
||||
|
||||
if (events)
|
||||
{
|
||||
(*pw)->registry = pw_core_get_registry((*pw)->core, PW_VERSION_REGISTRY, 0);
|
||||
spa_zero((*pw)->registry_listener);
|
||||
pw_registry_add_listener((*pw)->registry, &(*pw)->registry_listener, events, *pw);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
unlock:
|
||||
pw_thread_loop_unlock((*pw)->thread_loop);
|
||||
return false;
|
||||
}
|
||||
|
||||
void pipewire_core_deinit(pipewire_core_t *pw)
|
||||
{
|
||||
if (!pw)
|
||||
{
|
||||
pw_deinit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (pw->thread_loop)
|
||||
pw_thread_loop_stop(pw->thread_loop);
|
||||
|
||||
if (pw->registry)
|
||||
{
|
||||
spa_hook_remove(&pw->registry_listener);
|
||||
pw_proxy_destroy((struct pw_proxy*)pw->registry);
|
||||
}
|
||||
|
||||
if (pw->core)
|
||||
{
|
||||
spa_hook_remove(&pw->core_listener);
|
||||
pw_core_disconnect(pw->core);
|
||||
}
|
||||
|
||||
if (pw->ctx)
|
||||
pw_context_destroy(pw->ctx);
|
||||
|
||||
if (pw->thread_loop)
|
||||
pw_thread_loop_destroy(pw->thread_loop);
|
||||
|
||||
if (pw->devicelist)
|
||||
string_list_free(pw->devicelist);
|
||||
|
||||
free(pw);
|
||||
pw_deinit();
|
||||
}
|
||||
+10
-11
@@ -21,9 +21,11 @@
|
||||
|
||||
#include <spa/param/audio/format-utils.h>
|
||||
#include <spa/utils/ringbuffer.h>
|
||||
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
#include <lists/string_list.h>
|
||||
|
||||
|
||||
#define PW_RARCH_APPNAME "RetroArch"
|
||||
|
||||
/* String literals are part of the PipeWire specification */
|
||||
@@ -31,34 +33,31 @@
|
||||
#define PW_RARCH_MEDIA_TYPE_VIDEO "Video"
|
||||
#define PW_RARCH_MEDIA_TYPE_MIDI "Midi"
|
||||
#define PW_RARCH_MEDIA_CATEGORY_PLAYBACK "Playback"
|
||||
#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture"
|
||||
#define PW_RARCH_MEDIA_CATEGORY_RECORD "Capture"
|
||||
#define PW_RARCH_MEDIA_ROLE "Game"
|
||||
|
||||
typedef struct pipewire_core
|
||||
{
|
||||
struct pw_thread_loop *thread_loop;
|
||||
struct pw_context *ctx;
|
||||
|
||||
struct pw_core *core;
|
||||
struct spa_hook core_listener;
|
||||
int last_seq, pending_seq;
|
||||
|
||||
struct pw_registry *registry;
|
||||
struct spa_hook registry_listener;
|
||||
struct pw_client *client;
|
||||
struct spa_hook client_listener;
|
||||
|
||||
bool nonblock;
|
||||
struct string_list *devicelist;
|
||||
bool nonblock;
|
||||
} pipewire_core_t;
|
||||
|
||||
size_t calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels);
|
||||
bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events);
|
||||
|
||||
void set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]);
|
||||
void pipewire_core_deinit(pipewire_core_t *pw);
|
||||
|
||||
void pipewire_wait_resync(pipewire_core_t *pipewire);
|
||||
void pipewire_core_wait_resync(pipewire_core_t *pw);
|
||||
|
||||
bool pipewire_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active);
|
||||
|
||||
bool pipewire_core_init(pipewire_core_t *pipewire, const char *loop_name);
|
||||
bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active);
|
||||
|
||||
#endif /* _RETROARCH_PIPEWIRE */
|
||||
@@ -1,735 +0,0 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2011-2017 Daniel De Matteis
|
||||
* Copyright (C) 2023 Jesse Talavera-Greenberg
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "wasapi.h"
|
||||
#ifdef HAVE_MICROPHONE
|
||||
#include "../microphone_driver.h"
|
||||
#endif
|
||||
#include <string/stdstring.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <lists/string_list.h>
|
||||
|
||||
#include "mmdevice_common.h"
|
||||
|
||||
#include "../../configuration.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
const char *hresult_name(HRESULT hr)
|
||||
{
|
||||
switch (hr)
|
||||
{
|
||||
/* Standard error codes */
|
||||
case E_INVALIDARG:
|
||||
return "E_INVALIDARG";
|
||||
case E_NOINTERFACE:
|
||||
return "E_NOINTERFACE";
|
||||
case E_OUTOFMEMORY:
|
||||
return "E_OUTOFMEMORY";
|
||||
case E_POINTER:
|
||||
return "E_POINTER";
|
||||
/* Standard success codes */
|
||||
case S_FALSE:
|
||||
return "S_FALSE";
|
||||
case S_OK:
|
||||
return "S_OK";
|
||||
/* AUDCLNT error codes */
|
||||
case AUDCLNT_E_ALREADY_INITIALIZED:
|
||||
return "AUDCLNT_E_ALREADY_INITIALIZED";
|
||||
case AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL:
|
||||
return "AUDCLNT_E_BUFDURATION_PERIOD_NOT_EQUAL";
|
||||
case AUDCLNT_E_BUFFER_ERROR:
|
||||
return "AUDCLNT_E_BUFFER_ERROR";
|
||||
case AUDCLNT_E_BUFFER_OPERATION_PENDING:
|
||||
return "AUDCLNT_E_BUFFER_OPERATION_PENDING";
|
||||
case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
|
||||
return "AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED";
|
||||
case AUDCLNT_E_BUFFER_SIZE_ERROR:
|
||||
return "AUDCLNT_E_BUFFER_SIZE_ERROR";
|
||||
case AUDCLNT_E_CPUUSAGE_EXCEEDED:
|
||||
return "AUDCLNT_E_CPUUSAGE_EXCEEDED";
|
||||
case AUDCLNT_E_DEVICE_IN_USE:
|
||||
return "AUDCLNT_E_DEVICE_IN_USE";
|
||||
case AUDCLNT_E_DEVICE_INVALIDATED:
|
||||
return "AUDCLNT_E_DEVICE_INVALIDATED";
|
||||
case AUDCLNT_E_ENDPOINT_CREATE_FAILED:
|
||||
return "AUDCLNT_E_ENDPOINT_CREATE_FAILED";
|
||||
case AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED:
|
||||
return "AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED";
|
||||
case AUDCLNT_E_INVALID_DEVICE_PERIOD:
|
||||
return "AUDCLNT_E_INVALID_DEVICE_PERIOD";
|
||||
case AUDCLNT_E_INVALID_SIZE:
|
||||
return "AUDCLNT_E_INVALID_SIZE";
|
||||
case AUDCLNT_E_NOT_INITIALIZED:
|
||||
return "AUDCLNT_E_NOT_INITIALIZED";
|
||||
case AUDCLNT_E_OUT_OF_ORDER:
|
||||
return "AUDCLNT_E_OUT_OF_ORDER";
|
||||
case AUDCLNT_E_SERVICE_NOT_RUNNING:
|
||||
return "AUDCLNT_E_SERVICE_NOT_RUNNING";
|
||||
case AUDCLNT_E_UNSUPPORTED_FORMAT:
|
||||
return "AUDCLNT_E_UNSUPPORTED_FORMAT";
|
||||
case AUDCLNT_E_WRONG_ENDPOINT_TYPE:
|
||||
return "AUDCLNT_E_WRONG_ENDPOINT_TYPE";
|
||||
/* AUDCLNT success codes */
|
||||
case AUDCLNT_S_BUFFER_EMPTY:
|
||||
return "AUDCLNT_S_BUFFER_EMPTY";
|
||||
/* Something else; probably from an API that we started using
|
||||
* after mic support was implemented */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
static const char *wave_subtype_name(const GUID *guid)
|
||||
{
|
||||
if (!memcmp(guid, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)))
|
||||
return "KSDATAFORMAT_SUBTYPE_IEEE_FLOAT";
|
||||
return "<unknown sub-format>";
|
||||
}
|
||||
|
||||
static const char *wave_format_name(const WAVEFORMATEXTENSIBLE *format)
|
||||
{
|
||||
switch (format->Format.wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
return "WAVE_FORMAT_PCM";
|
||||
case WAVE_FORMAT_EXTENSIBLE:
|
||||
return wave_subtype_name(&format->SubFormat);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
const char* wasapi_error(DWORD error)
|
||||
{
|
||||
static char error_message[256];
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
error,
|
||||
MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
|
||||
error_message,
|
||||
sizeof(error_message) - 1,
|
||||
NULL);
|
||||
|
||||
return error_message;
|
||||
}
|
||||
|
||||
static const char* wasapi_data_flow_name(EDataFlow data_flow)
|
||||
{
|
||||
switch (data_flow)
|
||||
{
|
||||
case eCapture:
|
||||
return "eCapture";
|
||||
case eRender:
|
||||
return "eRender";
|
||||
case eAll:
|
||||
return "eAll";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
static void wasapi_set_format(WAVEFORMATEXTENSIBLE *wf,
|
||||
bool float_fmt, unsigned rate, unsigned channels)
|
||||
{
|
||||
WORD wBitsPerSample = float_fmt ? 32 : 16;
|
||||
WORD nBlockAlign = (channels * wBitsPerSample) / 8;
|
||||
DWORD nAvgBytesPerSec = rate * nBlockAlign;
|
||||
|
||||
wf->Format.nChannels = channels;
|
||||
wf->Format.nSamplesPerSec = rate;
|
||||
wf->Format.nAvgBytesPerSec = nAvgBytesPerSec;
|
||||
wf->Format.nBlockAlign = nBlockAlign;
|
||||
wf->Format.wBitsPerSample = wBitsPerSample;
|
||||
|
||||
if (float_fmt)
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wf->Format.cbSize = sizeof(WORD) + sizeof(DWORD) + sizeof(GUID);
|
||||
wf->Samples.wValidBitsPerSample = wBitsPerSample;
|
||||
wf->dwChannelMask = channels == 1 ? KSAUDIO_SPEAKER_MONO : KSAUDIO_SPEAKER_STEREO;
|
||||
wf->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
|
||||
}
|
||||
else
|
||||
{
|
||||
wf->Format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wf->Format.cbSize = 0;
|
||||
wf->Samples.wValidBitsPerSample = 0;
|
||||
wf->dwChannelMask = 0;
|
||||
memset(&wf->SubFormat, 0, sizeof(wf->SubFormat));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] format The format to check.
|
||||
* @return \c true if \c format is suitable for RetroArch.
|
||||
*/
|
||||
static bool wasapi_is_format_suitable(const WAVEFORMATEXTENSIBLE *format)
|
||||
{
|
||||
/* RetroArch only supports mono mic input and stereo speaker output */
|
||||
if (!format || format->Format.nChannels == 0 || format->Format.nChannels > 2)
|
||||
return false;
|
||||
|
||||
switch (format->Format.wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
if (format->Format.wBitsPerSample != 16)
|
||||
/* Integer samples must be 16-bit */
|
||||
return false;
|
||||
break;
|
||||
case WAVE_FORMAT_EXTENSIBLE:
|
||||
if (!(!memcmp(&format->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID))))
|
||||
/* RetroArch doesn't support any other subformat */
|
||||
return false;
|
||||
|
||||
if (format->Format.wBitsPerSample != 32)
|
||||
/* floating-point samples must be 32-bit */
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
/* Other formats are unsupported */
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a sample format suitable for the given device.
|
||||
* @param[in,out] format The place where the chosen format will be written,
|
||||
* as well as the first format checked.
|
||||
* @param[in] client The audio client (i.e. device handle) for which a format will be selected.
|
||||
* @param[in] mode The device mode (shared or exclusive) that \c client will use.
|
||||
* @param[in] channels The number of channels that will constitute one audio frame.
|
||||
* @return \c true if successful, \c false if a suitable format wasn't found or there was an error.
|
||||
* If \c true, the selected format will be written to \c format.
|
||||
* If \c false, the value referred by \c format will be unchanged.
|
||||
*/
|
||||
static bool wasapi_select_device_format(WAVEFORMATEXTENSIBLE *format, IAudioClient *client, AUDCLNT_SHAREMODE mode, unsigned channels)
|
||||
{
|
||||
/* Try the requested sample format first, then try the other one. */
|
||||
WAVEFORMATEXTENSIBLE *suggested_format = NULL;
|
||||
bool result = false;
|
||||
HRESULT hr = _IAudioClient_IsFormatSupported(
|
||||
client, mode,
|
||||
(const WAVEFORMATEX *)format,
|
||||
(WAVEFORMATEX **)&suggested_format);
|
||||
/* The Windows docs say that casting these arguments to WAVEFORMATEX* is okay. */
|
||||
|
||||
switch (hr)
|
||||
{
|
||||
case S_OK:
|
||||
/* The requested format is okay without any changes. */
|
||||
result = true;
|
||||
break;
|
||||
case S_FALSE:
|
||||
/* The requested format is unsupported, but Windows has suggested a similar one. */
|
||||
RARCH_DBG("[WASAPI]: Windows suggests a format of (%s, %u-channel, %uHz).\n",
|
||||
wave_format_name(suggested_format),
|
||||
suggested_format->Format.nChannels,
|
||||
suggested_format->Format.nSamplesPerSec);
|
||||
|
||||
if (wasapi_is_format_suitable(suggested_format))
|
||||
{
|
||||
*format = *suggested_format;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Windows suggested a format, but RetroArch can't use it.\n");
|
||||
}
|
||||
break;
|
||||
case AUDCLNT_E_UNSUPPORTED_FORMAT:
|
||||
{
|
||||
/* The requested format is unsupported
|
||||
* and Windows was unable to suggest another.
|
||||
* Usually happens with exclusive mode.
|
||||
* RetroArch will try selecting a format. */
|
||||
size_t i, j;
|
||||
bool preferred_formats[2];
|
||||
preferred_formats[0] = (format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE);
|
||||
preferred_formats[1] = (format->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE);
|
||||
RARCH_WARN("[WASAPI]: Requested format not supported, and Windows could not suggest one. RetroArch will do so.\n");
|
||||
for (i = 0; i < ARRAY_SIZE(preferred_formats); ++i)
|
||||
{
|
||||
static const unsigned preferred_rates[] = { 48000, 44100, 96000, 192000, 32000 };
|
||||
for (j = 0; j < ARRAY_SIZE(preferred_rates); ++j)
|
||||
{
|
||||
HRESULT format_check_hr;
|
||||
WAVEFORMATEXTENSIBLE possible_format;
|
||||
wasapi_set_format(&possible_format, preferred_formats[i], preferred_rates[j], channels);
|
||||
format_check_hr = _IAudioClient_IsFormatSupported(client, mode, (const WAVEFORMATEX *) &possible_format, NULL);
|
||||
if (SUCCEEDED(format_check_hr))
|
||||
{
|
||||
*format = possible_format;
|
||||
result = true;
|
||||
RARCH_DBG("[WASAPI]: RetroArch suggests a format of (%s, %u-channel, %uHz).\n",
|
||||
wave_format_name(format),
|
||||
format->Format.nChannels,
|
||||
format->Format.nSamplesPerSec);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: No suitable format available.\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* Something else went wrong. */
|
||||
RARCH_ERR("[WASAPI]: Failed to select client format: %s.\n", hresult_name(hr));
|
||||
break;
|
||||
}
|
||||
done:
|
||||
/* IAudioClient::IsFormatSupported allocates a format object. */
|
||||
if (suggested_format)
|
||||
CoTaskMemFree(suggested_format);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static IAudioClient *wasapi_init_client_ex(IMMDevice *device,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE wf;
|
||||
IAudioClient *client = NULL;
|
||||
REFERENCE_TIME minimum_period = 0;
|
||||
REFERENCE_TIME buffer_duration = 0;
|
||||
UINT32 buffer_length = 0;
|
||||
HRESULT hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_GetDevicePeriod(client, NULL, &minimum_period);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get minimum device period of exclusive client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Buffer_duration is in 100ns units. */
|
||||
buffer_duration = latency * 10000.0;
|
||||
if (buffer_duration < minimum_period)
|
||||
buffer_duration = minimum_period;
|
||||
|
||||
wasapi_set_format(&wf, *float_fmt, *rate, channels);
|
||||
RARCH_DBG("[WASAPI]: Requesting exclusive %u-bit %u-channel client with %s samples at %uHz %ums.\n",
|
||||
wf.Format.wBitsPerSample,
|
||||
wf.Format.nChannels,
|
||||
wave_format_name(&wf),
|
||||
wf.Format.nSamplesPerSec,
|
||||
latency);
|
||||
|
||||
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_EXCLUSIVE, channels))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
buffer_duration, buffer_duration, (WAVEFORMATEX*)&wf, NULL);
|
||||
|
||||
if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED)
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: Unaligned buffer size: %s.\n", hresult_name(hr));
|
||||
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get buffer size of client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer_duration = 10000.0 * 1000.0 / (*rate) * buffer_length + 0.5;
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
buffer_duration, buffer_duration, (WAVEFORMATEX*)&wf, NULL);
|
||||
}
|
||||
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
|
||||
{
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI] IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_EXCLUSIVE,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
buffer_duration, buffer_duration, (WAVEFORMATEX*)&wf, NULL);
|
||||
}
|
||||
if (hr != AUDCLNT_E_UNSUPPORTED_FORMAT)
|
||||
{
|
||||
if (hr == AUDCLNT_E_DEVICE_IN_USE)
|
||||
goto error;
|
||||
|
||||
if (hr == AUDCLNT_E_EXCLUSIVE_MODE_NOT_ALLOWED)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
|
||||
*rate = wf.Format.nSamplesPerSec;
|
||||
|
||||
return client;
|
||||
|
||||
error:
|
||||
IFACE_RELEASE(client);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static IAudioClient *wasapi_init_client_sh(IMMDevice *device,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
|
||||
{
|
||||
WAVEFORMATEXTENSIBLE wf;
|
||||
IAudioClient *client = NULL;
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
REFERENCE_TIME default_period = 0;
|
||||
REFERENCE_TIME buffer_duration = 0;
|
||||
HRESULT hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&client);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_GetDevicePeriod(client, &default_period, NULL);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get default device period of shared client: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Use audio latency setting for buffer size if allowed */
|
||||
if ( (sh_buffer_length < WASAPI_SH_BUFFER_DEVICE_PERIOD)
|
||||
|| (sh_buffer_length > WASAPI_SH_BUFFER_CLIENT_BUFFER))
|
||||
{
|
||||
/* Buffer_duration is in 100ns units. */
|
||||
buffer_duration = latency * 10000.0;
|
||||
if (buffer_duration < default_period)
|
||||
buffer_duration = default_period;
|
||||
}
|
||||
|
||||
wasapi_set_format(&wf, *float_fmt, *rate, channels);
|
||||
RARCH_DBG("[WASAPI]: Requesting shared %u-bit %u-channel client with %s samples at %uHz %ums.\n",
|
||||
wf.Format.wBitsPerSample,
|
||||
wf.Format.nChannels,
|
||||
wave_format_name(&wf),
|
||||
wf.Format.nSamplesPerSec,
|
||||
latency);
|
||||
|
||||
if (!wasapi_select_device_format(&wf, client, AUDCLNT_SHAREMODE_SHARED, channels))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to select a suitable device format.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
||||
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
|
||||
if (hr == AUDCLNT_E_ALREADY_INITIALIZED)
|
||||
{
|
||||
IFACE_RELEASE(client);
|
||||
hr = _IMMDevice_Activate(device,
|
||||
IID_IAudioClient,
|
||||
CLSCTX_ALL, NULL, (void**)&client);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IMMDevice::Activate failed: %s.\n", hresult_name(hr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hr = _IAudioClient_Initialize(client, AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
|
||||
buffer_duration, 0, (WAVEFORMATEX*)&wf, NULL);
|
||||
}
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: IAudioClient::Initialize failed: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
*float_fmt = wf.Format.wFormatTag != WAVE_FORMAT_PCM;
|
||||
*rate = wf.Format.nSamplesPerSec;
|
||||
|
||||
return client;
|
||||
|
||||
error:
|
||||
IFACE_RELEASE(client);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow)
|
||||
{
|
||||
HRESULT hr;
|
||||
UINT32 dev_count, i;
|
||||
IMMDeviceEnumerator *enumerator = NULL;
|
||||
IMMDevice *device = NULL;
|
||||
IMMDeviceCollection *collection = NULL;
|
||||
const char *data_flow_name = wasapi_data_flow_name(data_flow);
|
||||
|
||||
if (id)
|
||||
RARCH_DBG("[WASAPI]: Initializing %s device \"%s\"..\n", data_flow_name, id);
|
||||
else
|
||||
RARCH_DBG("[WASAPI]: Initializing default %s device..\n", data_flow_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#else
|
||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
|
||||
&IID_IMMDeviceEnumerator, (void **)&enumerator);
|
||||
#endif
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to create device enumerator: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (id)
|
||||
{
|
||||
/* If a specific device was requested... */
|
||||
int32_t idx_found = -1;
|
||||
struct string_list *list = (struct string_list*)mmdevice_list_new(NULL, data_flow);
|
||||
|
||||
if (!list)
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to allocate %s device list.\n", data_flow_name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (list->elems)
|
||||
{
|
||||
/* If any devices were found... */
|
||||
unsigned d;
|
||||
for (d = 0; d < list->size; d++)
|
||||
{
|
||||
if (string_is_equal(id, list->elems[d].data))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Found device #%d: \"%s\".\n", d, list->elems[d].data);
|
||||
idx_found = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Index was not found yet based on name string,
|
||||
* just assume id is a one-character number index. */
|
||||
if (idx_found == -1 && isdigit(id[0]))
|
||||
{
|
||||
idx_found = strtoul(id, NULL, 0);
|
||||
RARCH_LOG("[WASAPI]: Fallback, %s device index is a single number index instead: %u.\n", data_flow_name, idx_found);
|
||||
}
|
||||
}
|
||||
string_list_free(list);
|
||||
|
||||
if (idx_found == -1)
|
||||
idx_found = 0;
|
||||
|
||||
hr = _IMMDeviceEnumerator_EnumAudioEndpoints(enumerator,
|
||||
data_flow, DEVICE_STATE_ACTIVE, &collection);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to enumerate audio endpoints: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
hr = _IMMDeviceCollection_GetCount(collection, &dev_count);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to count IMMDevices: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < dev_count; ++i)
|
||||
{
|
||||
hr = _IMMDeviceCollection_Item(collection, i, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get IMMDevice #%d: %s.\n", i, hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (i == (UINT32)idx_found)
|
||||
break;
|
||||
|
||||
IFACE_RELEASE(device);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = _IMMDeviceEnumerator_GetDefaultAudioEndpoint(
|
||||
enumerator, data_flow, eConsole, &device);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
RARCH_ERR("[WASAPI]: Failed to get default audio endpoint: %s.\n", hresult_name(hr));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!device)
|
||||
goto error;
|
||||
|
||||
IFACE_RELEASE(collection);
|
||||
IFACE_RELEASE(enumerator);
|
||||
|
||||
return device;
|
||||
|
||||
error:
|
||||
IFACE_RELEASE(collection);
|
||||
IFACE_RELEASE(enumerator);
|
||||
|
||||
if (id)
|
||||
RARCH_WARN("[WASAPI]: Failed to initialize %s device \"%s\".\n", data_flow_name, id);
|
||||
else
|
||||
RARCH_ERR("[WASAPI]: Failed to initialize default %s device.\n", data_flow_name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels)
|
||||
{
|
||||
HRESULT hr;
|
||||
IAudioClient *client;
|
||||
float latency_res;
|
||||
REFERENCE_TIME device_period = 0;
|
||||
REFERENCE_TIME device_period_min = 0;
|
||||
REFERENCE_TIME stream_latency = 0;
|
||||
UINT32 buffer_length = 0;
|
||||
|
||||
if (*exclusive)
|
||||
{
|
||||
client = wasapi_init_client_ex(device, float_fmt, rate, latency, channels);
|
||||
if (!client)
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: Failed to initialize exclusive client, attempting shared client.\n");
|
||||
client = wasapi_init_client_sh(device, float_fmt, rate, latency, channels);
|
||||
if (client)
|
||||
*exclusive = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
client = wasapi_init_client_sh(device, float_fmt, rate, latency, channels);
|
||||
if (!client)
|
||||
{
|
||||
RARCH_WARN("[WASAPI]: Failed to initialize shared client, attempting exclusive client.\n");
|
||||
client = wasapi_init_client_ex(device, float_fmt, rate, latency, channels);
|
||||
if (client)
|
||||
*exclusive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
/* Remaining calls are for logging purposes. */
|
||||
|
||||
hr = _IAudioClient_GetDevicePeriod(client, &device_period, &device_period_min);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
RARCH_DBG("[WASAPI]: Default device period is %.1fms.\n", (float)device_period * 100 / 1e6);
|
||||
RARCH_DBG("[WASAPI]: Minimum device period is %.1fms.\n", (float)device_period_min * 100 / 1e6);
|
||||
}
|
||||
else
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetDevicePeriod failed: %s.\n", hresult_name(hr));
|
||||
|
||||
if (!*exclusive)
|
||||
{
|
||||
hr = _IAudioClient_GetStreamLatency(client, &stream_latency);
|
||||
if (SUCCEEDED(hr))
|
||||
RARCH_DBG("[WASAPI]: Shared stream latency is %.1fms.\n", (float)stream_latency * 100 / 1e6);
|
||||
else
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetStreamLatency failed: %s.\n", hresult_name(hr));
|
||||
}
|
||||
|
||||
hr = _IAudioClient_GetBufferSize(client, &buffer_length);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
size_t num_samples = buffer_length * channels;
|
||||
size_t num_bytes = num_samples * (*float_fmt ? sizeof(float) : sizeof(int16_t));
|
||||
RARCH_DBG("[WASAPI]: Endpoint buffer size is %u frames (%u samples, %u bytes, %.1f ms).\n",
|
||||
buffer_length, num_samples, num_bytes, (float)buffer_length * 1000.0 / *rate);
|
||||
}
|
||||
else
|
||||
RARCH_WARN("[WASAPI]: IAudioClient::GetBufferSize failed: %s.\n", hresult_name(hr));
|
||||
|
||||
if (*exclusive)
|
||||
latency_res = (float)buffer_length * 1000.0 / (*rate);
|
||||
else
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
unsigned sh_buffer_length = settings->uints.audio_wasapi_sh_buffer_length;
|
||||
|
||||
switch (sh_buffer_length)
|
||||
{
|
||||
case WASAPI_SH_BUFFER_AUDIO_LATENCY:
|
||||
case WASAPI_SH_BUFFER_CLIENT_BUFFER:
|
||||
latency_res = (float)buffer_length * 1000.0 / (*rate);
|
||||
break;
|
||||
case WASAPI_SH_BUFFER_DEVICE_PERIOD:
|
||||
latency_res = (float)(stream_latency + device_period) / 10000.0;
|
||||
break;
|
||||
default:
|
||||
latency_res = (float)sh_buffer_length * 1000.0 / (*rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RARCH_LOG("[WASAPI]: Client initialized (%s, %s, %uHz, %.1fms).\n",
|
||||
*exclusive ? "exclusive" : "shared",
|
||||
*float_fmt ? "FLOAT" : "PCM",
|
||||
*rate, latency_res);
|
||||
|
||||
return client;
|
||||
}
|
||||
@@ -17,24 +17,14 @@
|
||||
/**
|
||||
* Contains WASAPI-specific support functions that are used
|
||||
* by the WASAPI audio and microphone drivers.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef RETROARCH_COMMON_WASAPI_H
|
||||
#define RETROARCH_COMMON_WASAPI_H
|
||||
|
||||
#include "mmdevice_common_inline.h"
|
||||
#include <boolean.h>
|
||||
|
||||
/* Shared buffer size replacement placeholders */
|
||||
#define WASAPI_SH_BUFFER_AUDIO_LATENCY 0
|
||||
#define WASAPI_SH_BUFFER_DEVICE_PERIOD 32
|
||||
#define WASAPI_SH_BUFFER_CLIENT_BUFFER 64
|
||||
|
||||
const char *hresult_name(HRESULT hr);
|
||||
const char* wasapi_error(DWORD error);
|
||||
IMMDevice *wasapi_init_device(const char *id, EDataFlow data_flow);
|
||||
IAudioClient *wasapi_init_client(IMMDevice *device, bool *exclusive,
|
||||
bool *float_fmt, unsigned *rate, unsigned latency, unsigned channels);
|
||||
|
||||
#endif /* RETROARCH_COMMON_WASAPI_H */
|
||||
+313
-46
@@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2011-2017 - Daniel De Matteis
|
||||
* Copyright (C) 2023-2025 - Jesse Talavera-Greenberg
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
@@ -20,12 +21,281 @@
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/pcm.h>
|
||||
#include <asm-generic/errno.h>
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../common/alsa.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
#include "../microphone_driver.h"
|
||||
|
||||
#define BYTES_TO_FRAMES(bytes, frame_bits) ((bytes) * 8 / frame_bits)
|
||||
#define FRAMES_TO_BYTES(frames, frame_bits) ((frames) * frame_bits / 8)
|
||||
|
||||
typedef struct alsa_microphone_handle
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
alsa_stream_info_t stream_info;
|
||||
} alsa_microphone_handle_t;
|
||||
|
||||
typedef struct alsa_microphone
|
||||
{
|
||||
bool nonblock;
|
||||
} alsa_microphone_t;
|
||||
|
||||
static void *alsa_microphone_init(void)
|
||||
{
|
||||
alsa_microphone_t *alsa = (alsa_microphone_t*)calloc(1, sizeof(alsa_microphone_t));
|
||||
|
||||
if (!alsa)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to allocate driver context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RARCH_LOG("[ALSA] Using ALSA version %s.\n", snd_asoundlib_version());
|
||||
|
||||
return alsa;
|
||||
}
|
||||
|
||||
static void alsa_microphone_close_mic(void *driver_context, void *mic_context);
|
||||
static void alsa_microphone_free(void *driver_context)
|
||||
{
|
||||
alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context;
|
||||
/* The mic frontend should've closed all mics before calling free(). */
|
||||
|
||||
if (alsa)
|
||||
{
|
||||
snd_config_update_free_global();
|
||||
free(alsa);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alsa_microphone_start_mic(void *driver_context, void *mic_context);
|
||||
|
||||
static int alsa_microphone_read(void *driver_context, void *mic_context, void *s, size_t len)
|
||||
{
|
||||
size_t frames_size;
|
||||
snd_pcm_sframes_t size;
|
||||
snd_pcm_state_t state;
|
||||
alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context;
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
uint8_t *buf = (uint8_t*)s;
|
||||
snd_pcm_sframes_t read = 0;
|
||||
int errnum = 0;
|
||||
|
||||
if (!alsa || !mic || !buf)
|
||||
return -1;
|
||||
|
||||
size = BYTES_TO_FRAMES(len, mic->stream_info.frame_bits);
|
||||
frames_size = mic->stream_info.has_float ? sizeof(float) : sizeof(int16_t);
|
||||
|
||||
state = snd_pcm_state(mic->pcm);
|
||||
if (state != SND_PCM_STATE_RUNNING)
|
||||
{
|
||||
RARCH_WARN("[ALSA] Expected microphone \"%s\" to be in state RUNNING, was in state %s.\n",
|
||||
snd_pcm_name(mic->pcm),
|
||||
snd_pcm_state_name(state));
|
||||
|
||||
errnum = snd_pcm_start(mic->pcm);
|
||||
if (errnum < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to start microphone \"%s\": %s.\n",
|
||||
snd_pcm_name(mic->pcm),
|
||||
snd_strerror(errnum));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (alsa->nonblock)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
snd_pcm_sframes_t frames = snd_pcm_readi(mic->pcm, buf, size);
|
||||
|
||||
if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE)
|
||||
{
|
||||
errnum = snd_pcm_recover(mic->pcm, frames, 0);
|
||||
if (errnum < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to read from microphone: %s.\n", snd_strerror(frames));
|
||||
RARCH_ERR("[ALSA] Additionally, recovery failed with: %s.\n", snd_strerror(errnum));
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (frames == -EAGAIN)
|
||||
break;
|
||||
else if (frames < 0)
|
||||
return -1;
|
||||
|
||||
read += frames;
|
||||
buf += frames_size;
|
||||
size -= frames;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool eagain_retry = true;
|
||||
|
||||
while (size)
|
||||
{
|
||||
snd_pcm_sframes_t frames;
|
||||
int rc = snd_pcm_wait(mic->pcm, -1);
|
||||
|
||||
if (rc == -EPIPE || rc == -ESTRPIPE || rc == -EINTR)
|
||||
{
|
||||
if (snd_pcm_recover(mic->pcm, rc, 1) < 0)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
frames = snd_pcm_readi(mic->pcm, buf, size);
|
||||
|
||||
if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE)
|
||||
{
|
||||
if (snd_pcm_recover(mic->pcm, frames, 1) < 0)
|
||||
return -1;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (frames == -EAGAIN)
|
||||
{
|
||||
/* Definitely not supposed to happen. */
|
||||
if (eagain_retry)
|
||||
{
|
||||
eagain_retry = false;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (frames < 0)
|
||||
return -1;
|
||||
|
||||
read += frames;
|
||||
buf += frames_size;
|
||||
size -= frames;
|
||||
}
|
||||
}
|
||||
|
||||
return FRAMES_TO_BYTES(read, mic->stream_info.frame_bits);
|
||||
}
|
||||
|
||||
static bool alsa_microphone_mic_alive(const void *driver_context, const void *mic_context)
|
||||
{
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
(void)driver_context;
|
||||
|
||||
if (!mic)
|
||||
return false;
|
||||
|
||||
return snd_pcm_state(mic->pcm) == SND_PCM_STATE_RUNNING;
|
||||
}
|
||||
|
||||
static void alsa_microphone_set_nonblock_state(void *driver_context, bool nonblock)
|
||||
{
|
||||
alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context;
|
||||
alsa->nonblock = nonblock;
|
||||
}
|
||||
|
||||
static struct string_list *alsa_microphone_device_list_new(const void *data)
|
||||
{
|
||||
return alsa_device_list_type_new("Input");
|
||||
}
|
||||
|
||||
static void alsa_microphone_device_list_free(const void *driver_context, struct string_list *devices)
|
||||
{
|
||||
(void)driver_context;
|
||||
string_list_free(devices);
|
||||
/* Does nothing if devices is NULL */
|
||||
}
|
||||
|
||||
static void *alsa_microphone_open_mic(void *driver_context,
|
||||
const char *device,
|
||||
unsigned rate,
|
||||
unsigned latency,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
alsa_microphone_t *alsa = (alsa_microphone_t*)driver_context;
|
||||
alsa_microphone_handle_t *mic = NULL;
|
||||
|
||||
if (!alsa) /* If we weren't given a valid ALSA context... */
|
||||
return NULL;
|
||||
|
||||
/* If the microphone context couldn't be allocated... */
|
||||
if (!(mic = calloc(1, sizeof(alsa_microphone_handle_t))))
|
||||
return NULL;
|
||||
|
||||
/* channels hardcoded to 1, because we only support mono mic input */
|
||||
if (alsa_init_pcm(&mic->pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency, 1,
|
||||
&mic->stream_info, new_rate, SND_PCM_NONBLOCK) < 0)
|
||||
goto error;
|
||||
|
||||
return mic;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA] Failed to initialize microphone.\n");
|
||||
|
||||
alsa_microphone_close_mic(alsa, mic);
|
||||
|
||||
return NULL;
|
||||
|
||||
}
|
||||
static void alsa_microphone_close_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
(void)driver_context;
|
||||
|
||||
if (mic)
|
||||
{
|
||||
alsa_free_pcm(mic->pcm);
|
||||
free(mic);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alsa_microphone_start_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
if (!mic)
|
||||
return false;
|
||||
return alsa_start_pcm(mic->pcm);
|
||||
}
|
||||
|
||||
static bool alsa_microphone_stop_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
if (!mic)
|
||||
return false;
|
||||
return alsa_stop_pcm(mic->pcm);
|
||||
}
|
||||
|
||||
static bool alsa_microphone_mic_use_float(const void *driver_context, const void *mic_context)
|
||||
{
|
||||
alsa_microphone_handle_t *mic = (alsa_microphone_handle_t*)mic_context;
|
||||
return mic->stream_info.has_float;
|
||||
}
|
||||
|
||||
microphone_driver_t microphone_alsa = {
|
||||
alsa_microphone_init,
|
||||
alsa_microphone_free,
|
||||
alsa_microphone_read,
|
||||
alsa_microphone_set_nonblock_state,
|
||||
"alsa",
|
||||
alsa_microphone_device_list_new,
|
||||
alsa_microphone_device_list_free,
|
||||
alsa_microphone_open_mic,
|
||||
alsa_microphone_close_mic,
|
||||
alsa_microphone_mic_alive,
|
||||
alsa_microphone_start_mic,
|
||||
alsa_microphone_stop_mic,
|
||||
alsa_microphone_mic_use_float
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct alsa
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
@@ -49,21 +319,20 @@ static void *alsa_init(const char *device, unsigned rate, unsigned latency,
|
||||
|
||||
if (!alsa)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to allocate driver context\n");
|
||||
RARCH_ERR("[ALSA] Failed to allocate driver context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RARCH_LOG("[ALSA]: Using ALSA version %s\n", snd_asoundlib_version());
|
||||
RARCH_LOG("[ALSA] Using ALSA version %s.\n", snd_asoundlib_version());
|
||||
|
||||
if (alsa_init_pcm(&alsa->pcm, device, SND_PCM_STREAM_PLAYBACK, rate, latency, 2, &alsa->stream_info, new_rate, SND_PCM_NONBLOCK) < 0)
|
||||
{
|
||||
if (alsa_init_pcm(&alsa->pcm, device, SND_PCM_STREAM_PLAYBACK, rate,
|
||||
latency, 2, &alsa->stream_info, new_rate, SND_PCM_NONBLOCK) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return alsa;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA]: Failed to initialize...\n");
|
||||
RARCH_ERR("[ALSA] Failed to initialize.\n");
|
||||
|
||||
alsa_free(alsa);
|
||||
|
||||
@@ -73,20 +342,41 @@ error:
|
||||
#define BYTES_TO_FRAMES(bytes, frame_bits) ((bytes) * 8 / frame_bits)
|
||||
#define FRAMES_TO_BYTES(frames, frame_bits) ((frames) * frame_bits / 8)
|
||||
|
||||
static bool alsa_start(void *data, bool is_shutdown);
|
||||
static ssize_t alsa_write(void *data, const void *buf_, size_t size_)
|
||||
static bool alsa_start(void *data, bool is_shutdown)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
snd_pcm_sframes_t written = 0;
|
||||
snd_pcm_sframes_t size = BYTES_TO_FRAMES(size_, alsa->stream_info.frame_bits);
|
||||
size_t frames_size = alsa->stream_info.has_float ? sizeof(float) : sizeof(int16_t);
|
||||
alsa_t *alsa = (alsa_t*)data;
|
||||
if (!alsa->is_paused)
|
||||
return true;
|
||||
|
||||
if ( alsa->stream_info.can_pause
|
||||
&& alsa->is_paused)
|
||||
{
|
||||
int ret = snd_pcm_pause(alsa->pcm, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to unpause: %s.\n",
|
||||
snd_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
alsa->is_paused = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t alsa_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
ssize_t _len = 0;
|
||||
alsa_t *alsa = (alsa_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
snd_pcm_sframes_t size = BYTES_TO_FRAMES(len, alsa->stream_info.frame_bits);
|
||||
size_t frames_size = alsa->stream_info.has_float ? sizeof(float) : sizeof(int16_t);
|
||||
|
||||
/* Workaround buggy menu code.
|
||||
* If a write happens while we're paused, we might never progress. */
|
||||
if (alsa->is_paused)
|
||||
if (!alsa_start(alsa, false))
|
||||
return -1;
|
||||
if (alsa->is_paused && !alsa_start(alsa, false))
|
||||
return -1;
|
||||
|
||||
if (alsa->nonblock)
|
||||
{
|
||||
@@ -106,9 +396,9 @@ static ssize_t alsa_write(void *data, const void *buf_, size_t size_)
|
||||
else if (frames < 0)
|
||||
return -1;
|
||||
|
||||
written += frames;
|
||||
buf += (frames << 1) * frames_size;
|
||||
size -= frames;
|
||||
_len += frames;
|
||||
buf += (frames << 1) * frames_size;
|
||||
size -= frames;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -149,13 +439,13 @@ static ssize_t alsa_write(void *data, const void *buf_, size_t size_)
|
||||
else if (frames < 0)
|
||||
return -1;
|
||||
|
||||
written += frames;
|
||||
buf += (frames << 1) * frames_size;
|
||||
size -= frames;
|
||||
_len += frames;
|
||||
buf += (frames << 1) * frames_size;
|
||||
size -= frames;
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool alsa_alive(void *data)
|
||||
@@ -192,29 +482,6 @@ static void alsa_set_nonblock_state(void *data, bool state)
|
||||
alsa->nonblock = state;
|
||||
}
|
||||
|
||||
static bool alsa_start(void *data, bool is_shutdown)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t*)data;
|
||||
if (!alsa->is_paused)
|
||||
return true;
|
||||
|
||||
if (alsa->stream_info.can_pause
|
||||
&& alsa->is_paused)
|
||||
{
|
||||
int ret = snd_pcm_pause(alsa->pcm, 0);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to unpause: %s.\n",
|
||||
snd_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
alsa->is_paused = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void alsa_free(void *data)
|
||||
{
|
||||
alsa_t *alsa = (alsa_t*)data;
|
||||
|
||||
+35
-36
@@ -64,14 +64,14 @@ static void *alsa_qsa_init(const char *device,
|
||||
if ((err = snd_pcm_open_preferred(&alsa->pcm, &card, &dev,
|
||||
SND_PCM_OPEN_PLAYBACK)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Audio open error: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Audio open error: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_nonblock_mode(alsa->pcm, 1)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Can't set blocking mode: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Can't set blocking mode: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
@@ -80,7 +80,7 @@ static void *alsa_qsa_init(const char *device,
|
||||
pi.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||
if ((err = snd_pcm_channel_info(alsa->pcm, &pi)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: snd_pcm_channel_info failed: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] snd_pcm_channel_info failed: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
@@ -88,27 +88,27 @@ static void *alsa_qsa_init(const char *device,
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.channel = SND_PCM_CHANNEL_PLAYBACK;
|
||||
params.mode = SND_PCM_MODE_BLOCK;
|
||||
params.mode = SND_PCM_MODE_BLOCK;
|
||||
|
||||
params.format.interleave = 1;
|
||||
params.format.format = SND_PCM_SFMT_S16_LE;
|
||||
params.format.rate = DEFAULT_RATE;
|
||||
params.format.voices = 2;
|
||||
params.format.format = SND_PCM_SFMT_S16_LE;
|
||||
params.format.rate = DEFAULT_RATE;
|
||||
params.format.voices = 2;
|
||||
|
||||
params.start_mode = SND_PCM_START_FULL;
|
||||
params.stop_mode = SND_PCM_STOP_STOP;
|
||||
params.stop_mode = SND_PCM_STOP_STOP;
|
||||
|
||||
params.buf.block.frag_size = pi.max_fragment_size;
|
||||
params.buf.block.frags_min = 2;
|
||||
params.buf.block.frags_max = 8;
|
||||
|
||||
RARCH_LOG("Fragment size: %d\n", params.buf.block.frag_size);
|
||||
RARCH_LOG("Min Fragment size: %d\n", params.buf.block.frags_min);
|
||||
RARCH_LOG("Max Fragment size: %d\n", params.buf.block.frags_max);
|
||||
RARCH_LOG("[ALSA QSA] Fragment size: %d.\n", params.buf.block.frag_size);
|
||||
RARCH_LOG("[ALSA QSA] Min Fragment size: %d.\n", params.buf.block.frags_min);
|
||||
RARCH_LOG("[ALSA QSA] Max Fragment size: %d.\n", params.buf.block.frags_max);
|
||||
|
||||
if ((err = snd_pcm_channel_params(alsa->pcm, ¶ms)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Channel Parameter Error: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Channel Parameter Error: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
@@ -117,7 +117,7 @@ static void *alsa_qsa_init(const char *device,
|
||||
|
||||
if ((err = snd_pcm_channel_setup(alsa->pcm, &setup)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Channel Parameter Read Back Error: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Channel Parameter Read Back Error: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
@@ -127,7 +127,7 @@ static void *alsa_qsa_init(const char *device,
|
||||
else
|
||||
alsa->buf_size = next_pow2(32 * latency);
|
||||
|
||||
RARCH_LOG("[ALSA QSA]: buffer size: %u bytes\n", alsa->buf_size);
|
||||
RARCH_LOG("[ALSA QSA] Buffer size: %u bytes.\n", alsa->buf_size);
|
||||
|
||||
alsa->buf_count = (latency * 4 * rate + 500) / 1000;
|
||||
alsa->buf_count = (alsa->buf_count + alsa->buf_size / 2) / alsa->buf_size;
|
||||
@@ -135,7 +135,7 @@ static void *alsa_qsa_init(const char *device,
|
||||
if ((err = snd_pcm_channel_prepare(alsa->pcm,
|
||||
SND_PCM_CHANNEL_PLAYBACK)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Channel Prepare Error: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Channel Prepare Error: %s.\n",
|
||||
snd_strerror(err));
|
||||
goto error;
|
||||
}
|
||||
@@ -153,7 +153,7 @@ static void *alsa_qsa_init(const char *device,
|
||||
|
||||
alsa->has_float = false;
|
||||
alsa->can_pause = true;
|
||||
RARCH_LOG("[ALSA QSA]: Can pause: %s.\n",
|
||||
RARCH_LOG("[ALSA QSA] Can pause: %s.\n",
|
||||
alsa->can_pause ? "yes" : "no");
|
||||
|
||||
return alsa;
|
||||
@@ -175,35 +175,35 @@ static int check_pcm_status(void *data, int channel_type)
|
||||
{
|
||||
if (status.status == SND_PCM_STATUS_UNSECURE)
|
||||
{
|
||||
RARCH_ERR("check_pcm_status got SND_PCM_STATUS_UNSECURE, aborting playback\n");
|
||||
RARCH_ERR("[ALSA QSA] check_pcm_status got SND_PCM_STATUS_UNSECURE, aborting playback.\n");
|
||||
ret = -EPROTO;
|
||||
}
|
||||
else if (status.status == SND_PCM_STATUS_UNDERRUN)
|
||||
{
|
||||
RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_UNDERRUN.\n");
|
||||
RARCH_LOG("[ALSA QSA] check_pcm_status: SNDP_CM_STATUS_UNDERRUN.\n");
|
||||
if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0)
|
||||
{
|
||||
RARCH_ERR("Invalid state detected for underrun on snd_pcm_channel_prepare: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Invalid state detected for underrun on snd_pcm_channel_prepare: %s.\n",
|
||||
snd_strerror(ret));
|
||||
ret = -EPROTO;
|
||||
}
|
||||
}
|
||||
else if (status.status == SND_PCM_STATUS_OVERRUN)
|
||||
{
|
||||
RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_OVERRUN.\n");
|
||||
RARCH_LOG("[ALSA QSA] check_pcm_status: SNDP_CM_STATUS_OVERRUN.\n");
|
||||
if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0)
|
||||
{
|
||||
RARCH_ERR("Invalid state detected for overrun on snd_pcm_channel_prepare: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Invalid state detected for overrun on snd_pcm_channel_prepare: %s.\n",
|
||||
snd_strerror(ret));
|
||||
ret = -EPROTO;
|
||||
}
|
||||
}
|
||||
else if (status.status == SND_PCM_STATUS_CHANGE)
|
||||
{
|
||||
RARCH_LOG("check_pcm_status: SNDP_CM_STATUS_CHANGE.\n");
|
||||
RARCH_LOG("[ALSA QSA] check_pcm_status: SNDP_CM_STATUS_CHANGE.\n");
|
||||
if ((ret = snd_pcm_channel_prepare(alsa->pcm, channel_type)) < 0)
|
||||
{
|
||||
RARCH_ERR("Invalid state detected for change on snd_pcm_channel_prepare: %s\n",
|
||||
RARCH_ERR("[ALSA QSA] Invalid state detected for change on snd_pcm_channel_prepare: %s.\n",
|
||||
snd_strerror(ret));
|
||||
ret = -EPROTO;
|
||||
}
|
||||
@@ -211,7 +211,7 @@ static int check_pcm_status(void *data, int channel_type)
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("check_pcm_status failed: %s\n", snd_strerror(ret));
|
||||
RARCH_ERR("[ALSA QSA] check_pcm_status failed: %s.\n", snd_strerror(ret));
|
||||
if (ret == -ESRCH)
|
||||
ret = -EBADF;
|
||||
}
|
||||
@@ -219,24 +219,24 @@ static int check_pcm_status(void *data, int channel_type)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t alsa_qsa_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t alsa_qsa_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
alsa_qsa_t *alsa = (alsa_qsa_t*)data;
|
||||
snd_pcm_sframes_t written = 0;
|
||||
ssize_t _len = 0;
|
||||
alsa_qsa_t *alsa = (alsa_qsa_t*)data;
|
||||
|
||||
while (size)
|
||||
{
|
||||
size_t avail_write = MIN(alsa->buf_size - alsa->buffer_ptr, size);
|
||||
size_t avail_write = MIN(alsa->buf_size - alsa->buffer_ptr, len);
|
||||
|
||||
if (avail_write)
|
||||
{
|
||||
memcpy(alsa->buffer[alsa->buffer_index] +
|
||||
alsa->buffer_ptr, buf, avail_write);
|
||||
|
||||
alsa->buffer_ptr += avail_write;
|
||||
buf = (void*)((uint8_t*)buf + avail_write);
|
||||
size -= avail_write;
|
||||
written += avail_write;
|
||||
alsa->buffer_ptr += avail_write;
|
||||
buf = (void*)((uint8_t*)buf + avail_write);
|
||||
len -= avail_write;
|
||||
_len += avail_write;
|
||||
}
|
||||
|
||||
if (alsa->buffer_ptr >= alsa->buf_size)
|
||||
@@ -260,10 +260,9 @@ static ssize_t alsa_qsa_write(void *data, const void *buf, size_t size)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool alsa_qsa_stop(void *data)
|
||||
@@ -300,7 +299,7 @@ static bool alsa_qsa_start(void *data, bool is_shutdown)
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA QSA]: Failed to unpause: %s.\n",
|
||||
RARCH_ERR("[ALSA QSA] Failed to unpause: %s.\n",
|
||||
snd_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
@@ -318,7 +317,7 @@ static void alsa_qsa_set_nonblock_state(void *data, bool state)
|
||||
|
||||
if ((err = snd_pcm_nonblock_mode(alsa->pcm, state)) < 0)
|
||||
{
|
||||
RARCH_ERR("Can't set blocking mode to %d: %s\n", state,
|
||||
RARCH_ERR("[ALSA QSA] Can't set blocking mode to %d: %s.\n", state,
|
||||
snd_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
+436
-35
@@ -1,6 +1,7 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
|
||||
* Copyright (C) 2012-2015 - Michael Lelli
|
||||
* Copyright (C) 2023-2025 - Jesse Talavera-Greenberg
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
@@ -15,8 +16,10 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <alsa/pcm.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
@@ -25,9 +28,412 @@
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../common/alsa.h" /* For some common functions/types */
|
||||
#include "../common/alsathread.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
typedef struct alsa_thread_info
|
||||
{
|
||||
snd_pcm_t *pcm;
|
||||
fifo_buffer_t *buffer;
|
||||
sthread_t *worker_thread;
|
||||
slock_t *fifo_lock;
|
||||
scond_t *cond;
|
||||
slock_t *cond_lock;
|
||||
alsa_stream_info_t stream_info;
|
||||
volatile bool thread_dead;
|
||||
} alsa_thread_info_t;
|
||||
|
||||
static void alsa_thread_free_info_members(alsa_thread_info_t *info)
|
||||
{
|
||||
if (info)
|
||||
{
|
||||
if (info->worker_thread)
|
||||
{
|
||||
slock_lock(info->cond_lock);
|
||||
info->thread_dead = true;
|
||||
slock_unlock(info->cond_lock);
|
||||
sthread_join(info->worker_thread);
|
||||
}
|
||||
if (info->buffer)
|
||||
fifo_free(info->buffer);
|
||||
if (info->cond)
|
||||
scond_free(info->cond);
|
||||
if (info->fifo_lock)
|
||||
slock_free(info->fifo_lock);
|
||||
if (info->cond_lock)
|
||||
slock_free(info->cond_lock);
|
||||
if (info->pcm)
|
||||
alsa_free_pcm(info->pcm);
|
||||
}
|
||||
/* Do NOT free() info itself; it's embedded within another struct
|
||||
* that will be freed. */
|
||||
}
|
||||
|
||||
#ifdef HAVE_MICROPHONE
|
||||
#include "../microphone_driver.h"
|
||||
|
||||
typedef struct alsa_thread_microphone_handle
|
||||
{
|
||||
alsa_thread_info_t info;
|
||||
} alsa_thread_microphone_handle_t;
|
||||
|
||||
typedef struct alsa_thread_microphone
|
||||
{
|
||||
bool nonblock;
|
||||
} alsa_thread_microphone_t;
|
||||
|
||||
static void *alsa_thread_microphone_init(void)
|
||||
{
|
||||
alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)calloc(1, sizeof(alsa_thread_microphone_t));
|
||||
|
||||
if (!alsa)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to allocate driver context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RARCH_LOG("[ALSA] Using ALSA version %s\n", snd_asoundlib_version());
|
||||
|
||||
return alsa;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static void alsa_thread_microphone_close_mic(void *driver_context, void *mic_context);
|
||||
|
||||
static void alsa_thread_microphone_free(void *driver_context)
|
||||
{
|
||||
alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context;
|
||||
|
||||
if (alsa)
|
||||
free(alsa);
|
||||
}
|
||||
|
||||
/** @see alsa_thread_read_microphone() */
|
||||
static void alsa_microphone_worker_thread(void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
uint8_t *buf = NULL;
|
||||
uintptr_t thread_id = sthread_get_current_thread_id();
|
||||
|
||||
if (!(buf = (uint8_t *)calloc(1, mic->info.stream_info.period_size)))
|
||||
{
|
||||
RARCH_ERR("[ALSA] [capture thread %p] Failed to allocate audio buffer.\n", thread_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
RARCH_DBG("[ALSA] [capture thread %p] Beginning microphone worker thread.\n", thread_id);
|
||||
RARCH_DBG("[ALSA] [capture thread %p] Microphone \"%s\" is in state %s.\n",
|
||||
thread_id,
|
||||
snd_pcm_name(mic->info.pcm),
|
||||
snd_pcm_state_name(snd_pcm_state(mic->info.pcm)));
|
||||
|
||||
/* Until we're told to stop... */
|
||||
while (!mic->info.thread_dead)
|
||||
{
|
||||
size_t avail;
|
||||
size_t fifo_size;
|
||||
snd_pcm_sframes_t frames;
|
||||
int errnum = 0;
|
||||
|
||||
/* Lock the incoming sample queue (the main thread may block) */
|
||||
slock_lock(mic->info.fifo_lock);
|
||||
|
||||
/* Fill the incoming sample queue with whatever we recently read */
|
||||
avail = FIFO_WRITE_AVAIL(mic->info.buffer);
|
||||
fifo_size = MIN(mic->info.stream_info.period_size, avail);
|
||||
fifo_write(mic->info.buffer, buf, fifo_size);
|
||||
|
||||
/* Tell the main thread that it's okay to query the mic again */
|
||||
scond_signal(mic->info.cond);
|
||||
|
||||
/* Unlock the incoming sample queue (the main thread may resume) */
|
||||
slock_unlock(mic->info.fifo_lock);
|
||||
|
||||
/* If underrun, fill rest with silence. */
|
||||
memset(buf + fifo_size, 0, mic->info.stream_info.period_size - fifo_size);
|
||||
|
||||
errnum = snd_pcm_wait(mic->info.pcm, 33);
|
||||
|
||||
if (errnum == 0)
|
||||
{
|
||||
RARCH_DBG("[ALSA] [capture thread %p] Timeout after 33ms waiting for input.\n", thread_id);
|
||||
continue;
|
||||
}
|
||||
else if (errnum == -EPIPE || errnum == -ESTRPIPE || errnum == -EINTR)
|
||||
{
|
||||
RARCH_WARN("[ALSA] [capture thread %p] Wait error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(errnum));
|
||||
|
||||
if ((errnum = snd_pcm_recover(mic->info.pcm, errnum, false)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [capture thread %p] Failed to recover from prior wait error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(errnum));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
frames = snd_pcm_readi(mic->info.pcm, buf, mic->info.stream_info.period_frames);
|
||||
|
||||
if (frames == -EPIPE || frames == -EINTR || frames == -ESTRPIPE)
|
||||
{
|
||||
RARCH_WARN("[ALSA] [capture thread %p] Read error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(frames));
|
||||
|
||||
if ((errnum = snd_pcm_recover(mic->info.pcm, frames, false)) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [capture thread %p] Failed to recover from prior read error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(errnum));
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (frames < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [capture thread %p] Read error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(frames));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
slock_lock(mic->info.cond_lock);
|
||||
mic->info.thread_dead = true;
|
||||
scond_signal(mic->info.cond);
|
||||
slock_unlock(mic->info.cond_lock);
|
||||
free(buf);
|
||||
RARCH_DBG("[ALSA] [capture thread %p] Ending microphone worker thread.\n", thread_id);
|
||||
}
|
||||
|
||||
static int alsa_thread_microphone_read(void *driver_context, void *mic_context, void *sv, size_t len)
|
||||
{
|
||||
snd_pcm_state_t state;
|
||||
size_t _len = 0;
|
||||
uint8_t *s = (uint8_t*)sv;
|
||||
alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context;
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
|
||||
if (!alsa || !mic || !s) /* If any of the parameters were invalid... */
|
||||
return -1;
|
||||
|
||||
if (mic->info.thread_dead) /* If the mic thread is shutting down... */
|
||||
return -1;
|
||||
|
||||
state = snd_pcm_state(mic->info.pcm);
|
||||
if (state != SND_PCM_STATE_RUNNING)
|
||||
{
|
||||
int errnum;
|
||||
RARCH_WARN("[ALSA] Expected microphone \"%s\" to be in state RUNNING, was in state %s.\n",
|
||||
snd_pcm_name(mic->info.pcm), snd_pcm_state_name(state));
|
||||
|
||||
errnum = snd_pcm_start(mic->info.pcm);
|
||||
if (errnum < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to start microphone \"%s\": %s.\n",
|
||||
snd_pcm_name(mic->info.pcm), snd_strerror(errnum));
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If driver interactions shouldn't block... */
|
||||
if (alsa->nonblock)
|
||||
{
|
||||
size_t avail;
|
||||
|
||||
/* "Hey, I'm gonna borrow the queue." */
|
||||
slock_lock(mic->info.fifo_lock);
|
||||
|
||||
avail = FIFO_READ_AVAIL(mic->info.buffer);
|
||||
_len = MIN(avail, len);
|
||||
|
||||
/* "It's okay if you don't have any new samples, I'll just check in on you later." */
|
||||
fifo_read(mic->info.buffer, s, _len);
|
||||
|
||||
/* "Here, take this queue back." */
|
||||
slock_unlock(mic->info.fifo_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Until we've read all requested samples (or we're told to stop)... */
|
||||
while (_len < len && !mic->info.thread_dead)
|
||||
{
|
||||
size_t avail;
|
||||
|
||||
/* "Hey, I'm gonna borrow the queue." */
|
||||
slock_lock(mic->info.fifo_lock);
|
||||
|
||||
avail = FIFO_READ_AVAIL(mic->info.buffer);
|
||||
|
||||
if (avail == 0)
|
||||
{ /* "Oh, wait, it's empty." */
|
||||
|
||||
/* "Here, take it back..." */
|
||||
slock_unlock(mic->info.fifo_lock);
|
||||
|
||||
/* "...I'll just wait right here." */
|
||||
slock_lock(mic->info.cond_lock);
|
||||
|
||||
/* "Unless we're closing up shop..." */
|
||||
if (!mic->info.thread_dead)
|
||||
/* "...let me know when you've produced some samples." */
|
||||
scond_wait(mic->info.cond, mic->info.cond_lock);
|
||||
|
||||
/* "Oh, you're ready? Okay, I'm gonna continue." */
|
||||
slock_unlock(mic->info.cond_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t read_amt = MIN(len - _len, avail);
|
||||
|
||||
/* "I'll just go ahead and consume all these samples..."
|
||||
* (As many as will fit in s, or as many as are available.) */
|
||||
fifo_read(mic->info.buffer,s + _len, read_amt);
|
||||
|
||||
/* "I'm done, you can take the queue back now." */
|
||||
slock_unlock(mic->info.fifo_lock);
|
||||
_len += read_amt;
|
||||
}
|
||||
/* "I'll be right back..." */
|
||||
}
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *mic_context);
|
||||
|
||||
static void *alsa_thread_microphone_open_mic(void *driver_context,
|
||||
const char *device, unsigned rate, unsigned latency, unsigned *new_rate)
|
||||
{
|
||||
alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context;
|
||||
alsa_thread_microphone_handle_t *mic = NULL;
|
||||
|
||||
if (!alsa) /* If we weren't given a valid ALSA context... */
|
||||
return NULL;
|
||||
|
||||
/* If the microphone context couldn't be allocated... */
|
||||
if (!(mic = calloc(1, sizeof(alsa_thread_microphone_handle_t))))
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to allocate microphone context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (alsa_init_pcm(&mic->info.pcm, device, SND_PCM_STREAM_CAPTURE, rate, latency,
|
||||
1, &mic->info.stream_info, new_rate, 0) < 0)
|
||||
goto error;
|
||||
|
||||
mic->info.fifo_lock = slock_new();
|
||||
mic->info.cond_lock = slock_new();
|
||||
mic->info.cond = scond_new();
|
||||
mic->info.buffer = fifo_new(mic->info.stream_info.buffer_size);
|
||||
if (!mic->info.fifo_lock || !mic->info.cond_lock || !mic->info.cond || !mic->info.buffer || !mic->info.pcm)
|
||||
goto error;
|
||||
|
||||
mic->info.worker_thread = sthread_create(alsa_microphone_worker_thread, mic);
|
||||
if (!mic->info.worker_thread)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to initialize microphone worker thread.\n");
|
||||
goto error;
|
||||
}
|
||||
RARCH_DBG("[ALSA] Initialized microphone worker thread.\n");
|
||||
|
||||
return mic;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA] Failed to initialize microphone.\n");
|
||||
|
||||
if (mic)
|
||||
{
|
||||
if (mic->info.pcm)
|
||||
snd_pcm_close(mic->info.pcm);
|
||||
|
||||
alsa_thread_microphone_close_mic(alsa, mic);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void alsa_thread_microphone_close_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
if (mic)
|
||||
{
|
||||
alsa_thread_free_info_members(&mic->info);
|
||||
free(mic);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alsa_thread_microphone_mic_alive(const void *driver_context, const void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t *)mic_context;
|
||||
if (!mic)
|
||||
return false;
|
||||
return snd_pcm_state(mic->info.pcm) == SND_PCM_STATE_RUNNING;
|
||||
}
|
||||
|
||||
static void alsa_thread_microphone_set_nonblock_state(void *driver_context, bool state)
|
||||
{
|
||||
alsa_thread_microphone_t *alsa = (alsa_thread_microphone_t*)driver_context;
|
||||
alsa->nonblock = state;
|
||||
}
|
||||
|
||||
static struct string_list *alsa_thread_microphone_device_list_new(const void *data)
|
||||
{
|
||||
return alsa_device_list_type_new("Input");
|
||||
}
|
||||
|
||||
static void alsa_thread_microphone_device_list_free(const void *driver_context, struct string_list *devices)
|
||||
{
|
||||
string_list_free(devices);
|
||||
/* Does nothing if devices is NULL */
|
||||
}
|
||||
|
||||
static bool alsa_thread_microphone_start_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
if (!mic)
|
||||
return false;
|
||||
return alsa_start_pcm(mic->info.pcm);
|
||||
}
|
||||
|
||||
static bool alsa_thread_microphone_stop_mic(void *driver_context, void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
if (!mic)
|
||||
return false;
|
||||
return alsa_stop_pcm(mic->info.pcm);
|
||||
}
|
||||
|
||||
static bool alsa_thread_microphone_mic_use_float(const void *driver_context, const void *mic_context)
|
||||
{
|
||||
alsa_thread_microphone_handle_t *mic = (alsa_thread_microphone_handle_t*)mic_context;
|
||||
return mic->info.stream_info.has_float;
|
||||
}
|
||||
|
||||
microphone_driver_t microphone_alsathread = {
|
||||
alsa_thread_microphone_init,
|
||||
alsa_thread_microphone_free,
|
||||
alsa_thread_microphone_read,
|
||||
alsa_thread_microphone_set_nonblock_state,
|
||||
"alsathread",
|
||||
alsa_thread_microphone_device_list_new,
|
||||
alsa_thread_microphone_device_list_free,
|
||||
alsa_thread_microphone_open_mic,
|
||||
alsa_thread_microphone_close_mic,
|
||||
alsa_thread_microphone_mic_alive,
|
||||
alsa_thread_microphone_start_mic,
|
||||
alsa_thread_microphone_stop_mic,
|
||||
alsa_thread_microphone_mic_use_float
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct alsa_thread
|
||||
{
|
||||
alsa_thread_info_t info;
|
||||
@@ -43,11 +449,11 @@ static void alsa_worker_thread(void *data)
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [playback thread %u]: Failed to allocate audio buffer\n", thread_id);
|
||||
RARCH_ERR("[ALSA] [playback thread %u] Failed to allocate audio buffer.\n", thread_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
RARCH_DBG("[ALSA] [playback thread %p]: Beginning playback worker thread\n", thread_id);
|
||||
RARCH_DBG("[ALSA] [playback thread %p] Beginning playback worker thread.\n", thread_id);
|
||||
while (!alsa->info.thread_dead)
|
||||
{
|
||||
size_t avail;
|
||||
@@ -65,12 +471,13 @@ static void alsa_worker_thread(void *data)
|
||||
|
||||
frames = snd_pcm_writei(alsa->info.pcm, buf, alsa->info.stream_info.period_frames);
|
||||
|
||||
if (frames == -EPIPE || frames == -EINTR ||
|
||||
frames == -ESTRPIPE)
|
||||
if ( frames == -EPIPE
|
||||
|| frames == -EINTR
|
||||
|| frames == -ESTRPIPE)
|
||||
{
|
||||
if (snd_pcm_recover(alsa->info.pcm, frames, false) < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [playback thread %u]: Failed to recover from error: %s\n",
|
||||
RARCH_ERR("[ALSA] [playback thread %u] Failed to recover from error: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(frames));
|
||||
break;
|
||||
@@ -80,7 +487,7 @@ static void alsa_worker_thread(void *data)
|
||||
}
|
||||
else if (frames < 0)
|
||||
{
|
||||
RARCH_ERR("[ALSA] [playback thread %u]: Error writing audio to device: %s\n",
|
||||
RARCH_ERR("[ALSA] [playback thread %u] Error writing audio to device: %s.\n",
|
||||
thread_id,
|
||||
snd_strerror(frames));
|
||||
break;
|
||||
@@ -93,7 +500,7 @@ end:
|
||||
scond_signal(alsa->info.cond);
|
||||
slock_unlock(alsa->info.cond_lock);
|
||||
free(buf);
|
||||
RARCH_DBG("[ALSA] [playback thread %p]: Ending playback worker thread\n", thread_id);
|
||||
RARCH_DBG("[ALSA] [playback thread %p] Ending playback worker thread...\n", thread_id);
|
||||
}
|
||||
|
||||
static bool alsa_thread_use_float(void *data)
|
||||
@@ -122,43 +529,43 @@ static void *alsa_thread_init(const char *device,
|
||||
|
||||
if (!alsa)
|
||||
{
|
||||
RARCH_ERR("[ALSA] Failed to allocate driver context\n");
|
||||
RARCH_ERR("[ALSA] Failed to allocate driver context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RARCH_LOG("[ALSA] Using ALSA version %s\n", snd_asoundlib_version());
|
||||
RARCH_LOG("[ALSA] Using ALSA version %s.\n", snd_asoundlib_version());
|
||||
|
||||
if (alsa_init_pcm(&alsa->info.pcm, device, SND_PCM_STREAM_PLAYBACK, rate, latency, 2, &alsa->info.stream_info, new_rate, 0) < 0)
|
||||
{
|
||||
if (alsa_init_pcm(&alsa->info.pcm, device, SND_PCM_STREAM_PLAYBACK, rate,
|
||||
latency, 2, &alsa->info.stream_info, new_rate, 0) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
alsa->info.fifo_lock = slock_new();
|
||||
alsa->info.cond_lock = slock_new();
|
||||
alsa->info.cond = scond_new();
|
||||
alsa->info.buffer = fifo_new(alsa->info.stream_info.buffer_size);
|
||||
alsa->info.cond = scond_new();
|
||||
alsa->info.buffer = fifo_new(alsa->info.stream_info.buffer_size);
|
||||
if (!alsa->info.fifo_lock || !alsa->info.cond_lock || !alsa->info.cond || !alsa->info.buffer)
|
||||
goto error;
|
||||
|
||||
alsa->info.worker_thread = sthread_create(alsa_worker_thread, alsa);
|
||||
if (!alsa->info.worker_thread)
|
||||
{
|
||||
RARCH_ERR("[ALSA]: Failed to initialize worker thread\n");
|
||||
RARCH_ERR("[ALSA] Failed to initialize worker thread.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return alsa;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[ALSA]: Failed to initialize...\n");
|
||||
RARCH_ERR("[ALSA] Failed to initialize.\n");
|
||||
|
||||
alsa_thread_free(alsa);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t alsa_thread_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t alsa_thread_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ssize_t _len = 0;
|
||||
alsa_thread_t *alsa = (alsa_thread_t*)data;
|
||||
|
||||
if (alsa->info.thread_dead)
|
||||
@@ -167,21 +574,17 @@ static ssize_t alsa_thread_write(void *data, const void *buf, size_t size)
|
||||
if (alsa->nonblock)
|
||||
{
|
||||
size_t avail;
|
||||
size_t write_amt;
|
||||
|
||||
slock_lock(alsa->info.fifo_lock);
|
||||
avail = FIFO_WRITE_AVAIL(alsa->info.buffer);
|
||||
write_amt = MIN(avail, size);
|
||||
avail = FIFO_WRITE_AVAIL(alsa->info.buffer);
|
||||
_len = MIN(avail, len);
|
||||
|
||||
fifo_write(alsa->info.buffer, buf, write_amt);
|
||||
fifo_write(alsa->info.buffer, s, _len);
|
||||
slock_unlock(alsa->info.fifo_lock);
|
||||
|
||||
return write_amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t written = 0;
|
||||
while (written < size && !alsa->info.thread_dead)
|
||||
while (_len < (ssize_t)len && !alsa->info.thread_dead)
|
||||
{
|
||||
size_t avail;
|
||||
slock_lock(alsa->info.fifo_lock);
|
||||
@@ -197,15 +600,15 @@ static ssize_t alsa_thread_write(void *data, const void *buf, size_t size)
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t write_amt = MIN(size - written, avail);
|
||||
size_t write_amt = MIN(len - _len, avail);
|
||||
fifo_write(alsa->info.buffer,
|
||||
(const char*)buf + written, write_amt);
|
||||
(const char*)s + _len, write_amt);
|
||||
slock_unlock(alsa->info.fifo_lock);
|
||||
written += write_amt;
|
||||
_len += write_amt;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool alsa_thread_alive(void *data)
|
||||
@@ -219,7 +622,6 @@ static bool alsa_thread_alive(void *data)
|
||||
static bool alsa_thread_stop(void *data)
|
||||
{
|
||||
alsa_thread_t *alsa = (alsa_thread_t*)data;
|
||||
|
||||
if (alsa)
|
||||
alsa->is_paused = true;
|
||||
return true;
|
||||
@@ -242,15 +644,14 @@ static bool alsa_thread_start(void *data, bool is_shutdown)
|
||||
|
||||
static size_t alsa_thread_write_avail(void *data)
|
||||
{
|
||||
size_t _len;
|
||||
alsa_thread_t *alsa = (alsa_thread_t*)data;
|
||||
size_t val;
|
||||
|
||||
if (alsa->info.thread_dead)
|
||||
return 0;
|
||||
slock_lock(alsa->info.fifo_lock);
|
||||
val = FIFO_WRITE_AVAIL(alsa->info.buffer);
|
||||
_len = FIFO_WRITE_AVAIL(alsa->info.buffer);
|
||||
slock_unlock(alsa->info.fifo_lock);
|
||||
return val;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static size_t alsa_thread_buffer_size(void *data)
|
||||
|
||||
+17
-21
@@ -33,12 +33,11 @@
|
||||
#define DEFAULT_DEV "/dev/audio"
|
||||
|
||||
static void *audioio_init(const char *device, unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_out_rate)
|
||||
unsigned block_frames, unsigned *new_out_rate)
|
||||
{
|
||||
struct audio_info info;
|
||||
const char *audiodev = device ? device : DEFAULT_DEV;
|
||||
int *fd = (int*)calloc(1, sizeof(int));
|
||||
const char *audiodev = device ? device : DEFAULT_DEV;
|
||||
int *fd = (int*)calloc(1, sizeof(int));
|
||||
|
||||
if (!fd)
|
||||
return NULL;
|
||||
@@ -46,17 +45,17 @@ static void *audioio_init(const char *device, unsigned rate, unsigned latency,
|
||||
AUDIO_INITINFO(&info);
|
||||
|
||||
#ifdef AUMODE_PLAY_ALL
|
||||
info.mode = AUMODE_PLAY_ALL;
|
||||
info.mode = AUMODE_PLAY_ALL;
|
||||
#elif defined(AUMODE_PLAY)
|
||||
info.mode = AUMODE_PLAY;
|
||||
info.mode = AUMODE_PLAY;
|
||||
#endif
|
||||
info.play.sample_rate = rate;
|
||||
info.play.channels = 2;
|
||||
info.play.precision = 16;
|
||||
info.play.channels = 2;
|
||||
info.play.precision = 16;
|
||||
#ifdef AUDIO_ENCODING_SLINEAR
|
||||
info.play.encoding = AUDIO_ENCODING_SLINEAR;
|
||||
info.play.encoding = AUDIO_ENCODING_SLINEAR;
|
||||
#else
|
||||
info.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
info.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
#endif
|
||||
|
||||
if ((*fd = open(audiodev, O_WRONLY)) < 0)
|
||||
@@ -82,15 +81,15 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t audioio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t audioio_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
ssize_t _len;
|
||||
int *fd = (int*)data;
|
||||
|
||||
if (size == 0)
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if ((ret = write(*fd, buf, size)) < 0)
|
||||
if ((_len = write(*fd, s, len)) < 0)
|
||||
{
|
||||
if (errno == EAGAIN && (fcntl(*fd, F_GETFL) & O_NONBLOCK))
|
||||
return 0;
|
||||
@@ -98,7 +97,7 @@ static ssize_t audioio_write(void *data, const void *buf, size_t size)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool audioio_stop(void *data)
|
||||
@@ -158,7 +157,7 @@ static void audioio_set_nonblock_state(void *data, bool state)
|
||||
else
|
||||
rc = fcntl(*fd, F_SETFL, fcntl(*fd, F_GETFL) & (~O_NONBLOCK));
|
||||
if (rc != 0)
|
||||
RARCH_WARN("Could not set nonblocking on audio file descriptor. Will not be able to fast-forward.\n");
|
||||
RARCH_WARN("[AudioIO] Could not set nonblocking on audio file descriptor. Will not be able to fast-forward.\n");
|
||||
}
|
||||
|
||||
static void audioio_free(void *data)
|
||||
@@ -189,11 +188,8 @@ static size_t audioio_write_avail(void *data)
|
||||
return audioio_buffer_size(data);
|
||||
}
|
||||
|
||||
static bool audioio_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
/* TODO/FIXME - implement? */
|
||||
static bool audioio_use_float(void *data) { return false; }
|
||||
|
||||
audio_driver_t audio_audioio = {
|
||||
audioio_init,
|
||||
|
||||
@@ -0,0 +1,537 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2025 - OlyB
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with RetroArch.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <boolean.h>
|
||||
|
||||
#include <emscripten/wasm_worker.h>
|
||||
#include <emscripten/webaudio.h>
|
||||
#include <emscripten/atomic.h>
|
||||
#include "../../frontend/drivers/platform_emscripten.h"
|
||||
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <retro_timers.h>
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
#define WORKLET_STACK_SIZE 4096
|
||||
|
||||
/* additional buffer size (for EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK only) */
|
||||
/* if this is too small, frames may be dropped and content could run too fast. */
|
||||
/* very large slow-motion rate values may be too large for this; avoid anything higher than 6 or 7. */
|
||||
#define EXTERNAL_BLOCK_BUFFER_MS 128
|
||||
|
||||
typedef struct audioworklet_data
|
||||
{
|
||||
uint8_t *worklet_stack;
|
||||
uint32_t write_avail_bytes; /* atomic */
|
||||
size_t visible_buffer_size;
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
size_t write_avail_diff;
|
||||
#endif
|
||||
#ifdef PROXY_TO_PTHREAD
|
||||
emscripten_lock_t trywrite_lock;
|
||||
emscripten_condvar_t trywrite_cond;
|
||||
#endif
|
||||
emscripten_lock_t buffer_lock;
|
||||
EMSCRIPTEN_WEBAUDIO_T context;
|
||||
float *tmpbuf;
|
||||
fifo_buffer_t *buffer;
|
||||
unsigned rate;
|
||||
unsigned latency;
|
||||
bool nonblock;
|
||||
bool initing;
|
||||
#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK
|
||||
bool block_requested;
|
||||
#endif
|
||||
volatile bool running; /* currently only used by RetroArch */
|
||||
volatile bool driver_running; /* whether the driver is running (buffer allocated) */
|
||||
volatile bool context_running; /* whether the AudioContext is running */
|
||||
volatile bool init_done;
|
||||
volatile bool init_error;
|
||||
} audioworklet_data_t;
|
||||
|
||||
/* We only ever want to create 1 worklet, so we need to keep its data even if the driver is inactive. */
|
||||
static audioworklet_data_t *audioworklet_static_data = NULL;
|
||||
|
||||
/* Note that we cannot allocate any heap in here. */
|
||||
static bool audioworklet_process_cb(int numInputs, const AudioSampleFrame *inputs,
|
||||
int numOutputs, AudioSampleFrame *outputs,
|
||||
int numParams, const AudioParamFrame *params,
|
||||
void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
size_t avail;
|
||||
size_t max_read;
|
||||
unsigned writing_frames = 0;
|
||||
int i;
|
||||
|
||||
/* TODO: do we need to pay attention to audioworklet->running here too? */
|
||||
if (audioworklet->driver_running)
|
||||
{
|
||||
/* can't use Atomics.wait in AudioWorklet */
|
||||
/* busyspin is safe as of emscripten 4.0.4 */
|
||||
if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 2.5))
|
||||
{
|
||||
printf("[WARN] [AudioWorklet] Worklet: could not acquire lock\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
avail = FIFO_READ_AVAIL(audioworklet->buffer);
|
||||
max_read = MIN(avail, outputs[0].samplesPerChannel * 2 * sizeof(float));
|
||||
|
||||
if (max_read)
|
||||
{
|
||||
fifo_read(audioworklet->buffer, audioworklet->tmpbuf, max_read);
|
||||
emscripten_atomic_add_u32(&audioworklet->write_avail_bytes, max_read);
|
||||
}
|
||||
emscripten_lock_release(&audioworklet->buffer_lock);
|
||||
#ifdef PROXY_TO_PTHREAD
|
||||
emscripten_condvar_signal(&audioworklet->trywrite_cond, 1);
|
||||
#endif
|
||||
|
||||
writing_frames = max_read / 2 / sizeof(float);
|
||||
for (i = 0; i < writing_frames; i++)
|
||||
{
|
||||
outputs[0].data[i] = audioworklet->tmpbuf[i * 2];
|
||||
outputs[0].data[outputs[0].samplesPerChannel + i] = audioworklet->tmpbuf[i * 2 + 1];
|
||||
}
|
||||
}
|
||||
|
||||
if (writing_frames < outputs[0].samplesPerChannel)
|
||||
{
|
||||
int zero_frames = outputs[0].samplesPerChannel - writing_frames;
|
||||
memset(outputs[0].data + writing_frames, 0, zero_frames * sizeof(float));
|
||||
memset(outputs[0].data + writing_frames + outputs[0].samplesPerChannel, 0, zero_frames * sizeof(float));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void audioworklet_processor_inited_cb(EMSCRIPTEN_WEBAUDIO_T context, bool success, void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
int outputChannelCounts[1] = { 2 };
|
||||
EmscriptenAudioWorkletNodeCreateOptions opts = { 0, 1, outputChannelCounts };
|
||||
EMSCRIPTEN_AUDIO_WORKLET_NODE_T worklet_node;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
RARCH_ERR("[AudioWorklet] Failed to init AudioWorkletProcessor.\n");
|
||||
audioworklet->init_error = true;
|
||||
audioworklet->init_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
worklet_node = emscripten_create_wasm_audio_worklet_node(context, "retroarch", &opts, audioworklet_process_cb, audioworklet);
|
||||
emscripten_audio_node_connect(worklet_node, context, 0, 0);
|
||||
|
||||
audioworklet->init_done = true;
|
||||
}
|
||||
|
||||
static void audioworklet_thread_inited_cb(EMSCRIPTEN_WEBAUDIO_T context, bool success, void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
WebAudioWorkletProcessorCreateOptions opts = { "retroarch", 0 };
|
||||
|
||||
if (success)
|
||||
emscripten_create_wasm_audio_worklet_processor_async(context, &opts,
|
||||
audioworklet_processor_inited_cb, audioworklet);
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[AudioWorklet] Failed to init worklet thread! Is the worklet file in the right place?\n");
|
||||
audioworklet->init_error = true;
|
||||
audioworklet->init_done = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void audioworklet_ctx_statechange_cb(void *data, bool state)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
audioworklet->context_running = state;
|
||||
}
|
||||
|
||||
static void audioworklet_ctx_create(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
audioworklet->context = emscripten_create_audio_context(0);
|
||||
|
||||
audioworklet->tmpbuf = memalign(16, emscripten_audio_context_quantum_size(audioworklet->context) * 2 * sizeof(float));
|
||||
audioworklet->rate = EM_ASM_INT({
|
||||
return emscriptenGetAudioObject($0).sampleRate;
|
||||
}, audioworklet->context);
|
||||
audioworklet->context_running = EM_ASM_INT({
|
||||
let ac = emscriptenGetAudioObject($0);
|
||||
ac.addEventListener("statechange", function() {
|
||||
getWasmTableEntry($2)($1, ac.state == "running");
|
||||
});
|
||||
return ac.state == "running";
|
||||
}, audioworklet->context, audioworklet, audioworklet_ctx_statechange_cb);
|
||||
|
||||
emscripten_start_wasm_audio_worklet_thread_async(audioworklet->context,
|
||||
audioworklet->worklet_stack, WORKLET_STACK_SIZE, audioworklet_thread_inited_cb, audioworklet);
|
||||
}
|
||||
|
||||
static void audioworklet_alloc_buffer(void *data)
|
||||
{
|
||||
size_t buffer_size;
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
audioworklet->visible_buffer_size = (audioworklet->latency * audioworklet->rate * 2 * sizeof(float)) / 1000;
|
||||
buffer_size = audioworklet->visible_buffer_size;
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
audioworklet->write_avail_diff = (EXTERNAL_BLOCK_BUFFER_MS * audioworklet->rate * 2 * sizeof(float)) / 1000;
|
||||
buffer_size += audioworklet->write_avail_diff;
|
||||
#endif
|
||||
audioworklet->buffer = fifo_new(buffer_size);
|
||||
emscripten_atomic_store_u32(&audioworklet->write_avail_bytes, buffer_size);
|
||||
RARCH_LOG("[AudioWorklet] Buffer size: %lu bytes.\n", audioworklet->visible_buffer_size);
|
||||
}
|
||||
|
||||
static void audioworklet_init_error(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
RARCH_ERR("[AudioWorklet] Failed to initialize driver.\n");
|
||||
free(audioworklet->worklet_stack);
|
||||
free(audioworklet->tmpbuf);
|
||||
free(audioworklet);
|
||||
}
|
||||
|
||||
static bool audioworklet_resume_ctx(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
if (!audioworklet->context_running)
|
||||
{
|
||||
MAIN_THREAD_ASYNC_EM_ASM({
|
||||
emscriptenGetAudioObject($0).resume();
|
||||
}, audioworklet->context);
|
||||
}
|
||||
return audioworklet->context_running;
|
||||
}
|
||||
|
||||
static void *audioworklet_init(const char *device, unsigned rate,
|
||||
unsigned latency, unsigned block_frames, unsigned *new_rate)
|
||||
{
|
||||
audioworklet_data_t *audioworklet;
|
||||
if (audioworklet_static_data)
|
||||
{
|
||||
if (audioworklet_static_data->driver_running || audioworklet_static_data->initing)
|
||||
{
|
||||
RARCH_ERR("[AudioWorklet] Tried to start already running driver.\n");
|
||||
return NULL;
|
||||
}
|
||||
RARCH_LOG("[AudioWorklet] Reusing old context.\n");
|
||||
audioworklet = audioworklet_static_data;
|
||||
audioworklet->latency = latency;
|
||||
*new_rate = audioworklet->rate;
|
||||
RARCH_LOG("[AudioWorklet] Device rate: %d Hz.\n", *new_rate);
|
||||
audioworklet_alloc_buffer(audioworklet);
|
||||
audioworklet_resume_ctx(audioworklet);
|
||||
audioworklet->driver_running = true;
|
||||
return audioworklet;
|
||||
}
|
||||
|
||||
audioworklet = (audioworklet_data_t*)calloc(1, sizeof(audioworklet_data_t));
|
||||
if (!audioworklet)
|
||||
return NULL;
|
||||
audioworklet->worklet_stack = memalign(16, WORKLET_STACK_SIZE);
|
||||
if (!audioworklet->worklet_stack)
|
||||
return NULL;
|
||||
audioworklet_static_data = audioworklet;
|
||||
|
||||
audioworklet->latency = latency;
|
||||
platform_emscripten_run_on_browser_thread_sync(audioworklet_ctx_create, audioworklet);
|
||||
*new_rate = audioworklet->rate;
|
||||
RARCH_LOG("[AudioWorklet] Device rate: %d Hz.\n", *new_rate);
|
||||
audioworklet->initing = true;
|
||||
audioworklet_alloc_buffer(audioworklet);
|
||||
emscripten_lock_init(&audioworklet->buffer_lock);
|
||||
#ifdef PROXY_TO_PTHREAD
|
||||
emscripten_lock_init(&audioworklet->trywrite_lock);
|
||||
emscripten_condvar_init(&audioworklet->trywrite_cond);
|
||||
#endif
|
||||
|
||||
#ifndef EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK
|
||||
/* TODO: can MIN_ASYNCIFY block here too? */
|
||||
while (!audioworklet->init_done)
|
||||
retro_sleep(1);
|
||||
audioworklet->initing = false;
|
||||
if (audioworklet->init_error)
|
||||
{
|
||||
audioworklet_init_error(audioworklet);
|
||||
return NULL;
|
||||
}
|
||||
audioworklet->driver_running = true;
|
||||
#elif defined(EMSCRIPTEN_AUDIO_FAKE_BLOCK)
|
||||
audioworklet->block_requested = true;
|
||||
platform_emscripten_enter_fake_block(1);
|
||||
#endif
|
||||
/* external block: will be handled later */
|
||||
|
||||
return audioworklet;
|
||||
}
|
||||
|
||||
static ssize_t audioworklet_write(void *data, const void *s, size_t ss)
|
||||
{
|
||||
size_t avail;
|
||||
size_t max_write;
|
||||
size_t to_write_frames;
|
||||
size_t to_write_bytes;
|
||||
size_t _len = 0;
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
const float *samples = (const float*)s;
|
||||
size_t num_frames = ss / 2 / sizeof(float);
|
||||
|
||||
/* too early! might happen with external blocking */
|
||||
if (!audioworklet->driver_running)
|
||||
return 0;
|
||||
|
||||
/* don't write audio if the context isn't running, just try to start it */
|
||||
if (!audioworklet_resume_ctx(audioworklet))
|
||||
return 0;
|
||||
|
||||
while (num_frames)
|
||||
{
|
||||
#ifdef PROXY_TO_PTHREAD
|
||||
if (!emscripten_lock_wait_acquire(&audioworklet->buffer_lock, 2500000))
|
||||
#else
|
||||
if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 2.5))
|
||||
#endif
|
||||
{
|
||||
RARCH_WARN("[AudioWorklet] Main thread: could not acquire lock.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
avail = FIFO_WRITE_AVAIL(audioworklet->buffer);
|
||||
max_write = avail;
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
/* make sure we don't write into the blocking buffer for nonblock */
|
||||
if (audioworklet->nonblock)
|
||||
{
|
||||
if (max_write > audioworklet->write_avail_diff)
|
||||
max_write -= audioworklet->write_avail_diff;
|
||||
else
|
||||
max_write = 0;
|
||||
}
|
||||
#endif
|
||||
to_write_frames = MIN(num_frames, max_write / 2 / sizeof(float));
|
||||
if (to_write_frames)
|
||||
{
|
||||
to_write_bytes = to_write_frames * 2 * sizeof(float);
|
||||
avail -= to_write_bytes;
|
||||
fifo_write(audioworklet->buffer, samples, to_write_bytes);
|
||||
emscripten_atomic_store_u32(&audioworklet->write_avail_bytes, (uint32_t)avail);
|
||||
num_frames -= to_write_frames;
|
||||
samples += (to_write_frames * 2);
|
||||
_len += to_write_frames;
|
||||
}
|
||||
|
||||
emscripten_lock_release(&audioworklet->buffer_lock);
|
||||
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK
|
||||
/* see if we're over the threshold to go to fake block */
|
||||
if (avail < audioworklet->write_avail_diff)
|
||||
{
|
||||
audioworklet->block_requested = true;
|
||||
platform_emscripten_enter_fake_block(1);
|
||||
}
|
||||
#endif
|
||||
if (num_frames && !audioworklet->nonblock)
|
||||
RARCH_WARN("[AudioWorklet] Dropping %lu frames.\n", num_frames);
|
||||
break;
|
||||
#endif
|
||||
if (audioworklet->nonblock || !num_frames)
|
||||
break;
|
||||
#if defined(PROXY_TO_PTHREAD)
|
||||
emscripten_condvar_wait(&audioworklet->trywrite_cond, &audioworklet->trywrite_lock, 3000000);
|
||||
#elif defined(EMSCRIPTEN_FULL_ASYNCIFY)
|
||||
retro_sleep(1);
|
||||
#else /* equivalent to defined(EMSCRIPTEN_AUDIO_BUSYWAIT) */
|
||||
while (emscripten_atomic_load_u32(&audioworklet->write_avail_bytes) < 2 * sizeof(float))
|
||||
audioworklet_resume_ctx(audioworklet);
|
||||
#endif
|
||||
/* try resuming, on the off chance that the context was interrupted while blocking */
|
||||
audioworklet_resume_ctx(audioworklet);
|
||||
}
|
||||
|
||||
return _len;
|
||||
}
|
||||
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_BLOCK
|
||||
/* returns true if fake block should continue */
|
||||
bool audioworklet_external_block(void)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = audioworklet_static_data;
|
||||
|
||||
if (audioworklet)
|
||||
{
|
||||
#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK
|
||||
if (!audioworklet->block_requested)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
while (audioworklet->initing && !audioworklet->init_done)
|
||||
#ifdef EMSCRIPTEN_AUDIO_ASYNC_BLOCK
|
||||
retro_sleep(1);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
if (audioworklet->init_done && !audioworklet->driver_running)
|
||||
{
|
||||
audioworklet->initing = false;
|
||||
if (audioworklet->init_error)
|
||||
{
|
||||
audioworklet_init_error(audioworklet);
|
||||
abort();
|
||||
return false;
|
||||
}
|
||||
audioworklet->driver_running = true;
|
||||
}
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
if (!audioworklet->driver_running)
|
||||
return false;
|
||||
|
||||
while (emscripten_atomic_load_u32(&audioworklet->write_avail_bytes) < audioworklet->write_avail_diff)
|
||||
{
|
||||
audioworklet_resume_ctx(audioworklet);
|
||||
#ifdef EMSCRIPTEN_AUDIO_ASYNC_BLOCK
|
||||
retro_sleep(1);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef EMSCRIPTEN_AUDIO_FAKE_BLOCK
|
||||
audioworklet->block_requested = false;
|
||||
platform_emscripten_exit_fake_block();
|
||||
return true; /* return to RAF if needed */
|
||||
#endif
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* called on program exit */
|
||||
void audioworklet_close(void)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = audioworklet_static_data;
|
||||
|
||||
if (!audioworklet)
|
||||
return;
|
||||
|
||||
MAIN_THREAD_EM_ASM({
|
||||
emscriptenGetAudioObject($0).close();
|
||||
}, audioworklet->context);
|
||||
}
|
||||
|
||||
static bool audioworklet_stop(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
audioworklet->running = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool audioworklet_start(void *data, bool is_shutdown)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
audioworklet->running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool audioworklet_alive(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
return audioworklet->running;
|
||||
}
|
||||
|
||||
static void audioworklet_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
audioworklet->nonblock = state;
|
||||
}
|
||||
|
||||
static void audioworklet_free(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
/* that's not good... this shouldn't happen? */
|
||||
if (!audioworklet->driver_running)
|
||||
{
|
||||
RARCH_ERR("[AudioWorklet] Tried to free before done initing.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef PROXY_TO_PTHREAD
|
||||
if (!emscripten_lock_wait_acquire(&audioworklet->buffer_lock, 10000000))
|
||||
#else
|
||||
if (!emscripten_lock_busyspin_wait_acquire(&audioworklet->buffer_lock, 10))
|
||||
#endif
|
||||
{
|
||||
RARCH_ERR("[AudioWorklet] Main thread: could not acquire lock to free buffer.\n");
|
||||
return;
|
||||
}
|
||||
audioworklet->driver_running = false;
|
||||
fifo_free(audioworklet->buffer);
|
||||
emscripten_lock_release(&audioworklet->buffer_lock);
|
||||
MAIN_THREAD_ASYNC_EM_ASM({
|
||||
emscriptenGetAudioObject($0).suspend();
|
||||
}, audioworklet->context);
|
||||
}
|
||||
|
||||
static size_t audioworklet_write_avail(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
|
||||
#ifdef EMSCRIPTEN_AUDIO_EXTERNAL_WRITE_BLOCK
|
||||
size_t avail = emscripten_atomic_load_u32(&audioworklet->write_avail_bytes);
|
||||
if (avail > audioworklet->write_avail_diff)
|
||||
return avail - audioworklet->write_avail_diff;
|
||||
return 0;
|
||||
#else
|
||||
return emscripten_atomic_load_u32(&audioworklet->write_avail_bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t audioworklet_buffer_size(void *data)
|
||||
{
|
||||
audioworklet_data_t *audioworklet = (audioworklet_data_t*)data;
|
||||
return audioworklet->visible_buffer_size;
|
||||
}
|
||||
|
||||
static bool audioworklet_use_float(void *data) { return true; }
|
||||
|
||||
audio_driver_t audio_audioworklet = {
|
||||
audioworklet_init,
|
||||
audioworklet_write,
|
||||
audioworklet_stop,
|
||||
audioworklet_start,
|
||||
audioworklet_alive,
|
||||
audioworklet_set_nonblock_state,
|
||||
audioworklet_free,
|
||||
audioworklet_use_float,
|
||||
"audioworklet",
|
||||
NULL,
|
||||
NULL,
|
||||
audioworklet_write_avail,
|
||||
audioworklet_buffer_size
|
||||
};
|
||||
+62
-69
@@ -78,7 +78,7 @@ static void coreaudio_free(void *data)
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static OSStatus audio_write_cb(void *userdata,
|
||||
static OSStatus coreaudio_audio_write_cb(void *userdata,
|
||||
AudioUnitRenderActionFlags *action_flags,
|
||||
const AudioTimeStamp *time_stamp, UInt32 bus_number,
|
||||
UInt32 number_frames, AudioBufferList *io_data)
|
||||
@@ -102,31 +102,24 @@ static OSStatus audio_write_cb(void *userdata,
|
||||
if (FIFO_READ_AVAIL(dev->buffer) < write_avail)
|
||||
{
|
||||
*action_flags = kAudioUnitRenderAction_OutputIsSilence;
|
||||
|
||||
/* Seems to be needed. */
|
||||
memset(outbuf, 0, write_avail);
|
||||
|
||||
slock_unlock(dev->lock);
|
||||
|
||||
/* Technically possible to deadlock without. */
|
||||
scond_signal(dev->cond);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
fifo_read(dev->buffer, outbuf, write_avail);
|
||||
else
|
||||
fifo_read(dev->buffer, outbuf, write_avail);
|
||||
slock_unlock(dev->lock);
|
||||
scond_signal(dev->cond);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
static void choose_output_device(coreaudio_t *dev, const char* device)
|
||||
static void coreaudio_choose_output_device(coreaudio_t *dev, const char* device)
|
||||
{
|
||||
int i;
|
||||
UInt32 deviceCount;
|
||||
UInt32 device_count;
|
||||
AudioObjectPropertyAddress propaddr;
|
||||
AudioDeviceID *devices = NULL;
|
||||
UInt32 size = 0;
|
||||
AudioDeviceID *devices = NULL;
|
||||
UInt32 size = 0;
|
||||
|
||||
propaddr.mSelector = kAudioHardwarePropertyDevices;
|
||||
#if HAS_MACOSX_10_12
|
||||
@@ -140,36 +133,35 @@ static void choose_output_device(coreaudio_t *dev, const char* device)
|
||||
&propaddr, 0, 0, &size) != noErr)
|
||||
return;
|
||||
|
||||
deviceCount = size / sizeof(AudioDeviceID);
|
||||
devices = (AudioDeviceID*)malloc(size);
|
||||
|
||||
if (!devices || AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&propaddr, 0, 0, &size, devices) != noErr)
|
||||
goto done;
|
||||
device_count = size / sizeof(AudioDeviceID);
|
||||
devices = (AudioDeviceID*)malloc(size);
|
||||
|
||||
if (devices && AudioObjectGetPropertyData(kAudioObjectSystemObject,
|
||||
&propaddr, 0, 0, &size, devices) == noErr)
|
||||
{
|
||||
#if HAS_MACOSX_10_12
|
||||
#else
|
||||
propaddr.mScope = kAudioDevicePropertyScopeOutput;
|
||||
propaddr.mScope = kAudioDevicePropertyScopeOutput;
|
||||
#endif
|
||||
propaddr.mSelector = kAudioDevicePropertyDeviceName;
|
||||
propaddr.mSelector = kAudioDevicePropertyDeviceName;
|
||||
|
||||
for (i = 0; i < (int)deviceCount; i ++)
|
||||
{
|
||||
char device_name[1024];
|
||||
device_name[0] = 0;
|
||||
size = 1024;
|
||||
|
||||
if (AudioObjectGetPropertyData(devices[i],
|
||||
&propaddr, 0, 0, &size, device_name) == noErr
|
||||
&& string_is_equal(device_name, device))
|
||||
for (i = 0; i < (int)device_count; i ++)
|
||||
{
|
||||
AudioUnitSetProperty(dev->dev, kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioUnitScope_Global, 0, &devices[i], sizeof(AudioDeviceID));
|
||||
goto done;
|
||||
char device_name[1024];
|
||||
device_name[0] = 0;
|
||||
size = 1024;
|
||||
|
||||
if (AudioObjectGetPropertyData(devices[i],
|
||||
&propaddr, 0, 0, &size, device_name) == noErr
|
||||
&& string_is_equal(device_name, device))
|
||||
{
|
||||
AudioUnitSetProperty(dev->dev, kAudioOutputUnitProperty_CurrentDevice,
|
||||
kAudioUnitScope_Global, 0, &devices[i], sizeof(AudioDeviceID));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
free(devices);
|
||||
}
|
||||
#endif
|
||||
@@ -232,7 +224,7 @@ static void *coreaudio_init(const char *device,
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (device)
|
||||
choose_output_device(dev, device);
|
||||
coreaudio_choose_output_device(dev, device);
|
||||
#endif
|
||||
|
||||
dev->dev_alive = true;
|
||||
@@ -245,9 +237,11 @@ static void *coreaudio_init(const char *device,
|
||||
stream_desc.mBytesPerFrame = 2 * sizeof(float);
|
||||
stream_desc.mFramesPerPacket = 1;
|
||||
stream_desc.mFormatID = kAudioFormatLinearPCM;
|
||||
stream_desc.mFormatFlags = kAudioFormatFlagIsFloat |
|
||||
kAudioFormatFlagIsPacked | (is_little_endian() ?
|
||||
0 : kAudioFormatFlagIsBigEndian);
|
||||
stream_desc.mFormatFlags = kAudioFormatFlagIsFloat
|
||||
| kAudioFormatFlagIsPacked;
|
||||
|
||||
if (!is_little_endian())
|
||||
stream_desc.mFormatFlags |= kAudioFormatFlagIsBigEndian;
|
||||
|
||||
if (AudioUnitSetProperty(dev->dev, kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input, 0, &stream_desc, sizeof(stream_desc)) != noErr)
|
||||
@@ -268,7 +262,7 @@ static void *coreaudio_init(const char *device,
|
||||
if (real_desc.mFormatID != stream_desc.mFormatID)
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[CoreAudio]: Using output sample rate of %.1f Hz\n",
|
||||
RARCH_LOG("[CoreAudio] Using output sample rate of %.1f Hz.\n",
|
||||
(float)real_desc.mSampleRate);
|
||||
*new_rate = real_desc.mSampleRate;
|
||||
|
||||
@@ -281,7 +275,7 @@ static void *coreaudio_init(const char *device,
|
||||
#endif
|
||||
|
||||
/* Set callbacks and finish up. */
|
||||
cb.inputProc = audio_write_cb;
|
||||
cb.inputProc = coreaudio_audio_write_cb;
|
||||
cb.inputProcRefCon = dev;
|
||||
|
||||
if (AudioUnitSetProperty(dev->dev, kAudioUnitProperty_SetRenderCallback,
|
||||
@@ -298,7 +292,7 @@ static void *coreaudio_init(const char *device,
|
||||
if (!(dev->buffer = fifo_new(fifo_size)))
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[CoreAudio]: Using buffer size of %u bytes: (latency = %u ms)\n",
|
||||
RARCH_LOG("[CoreAudio] Using buffer size of %u bytes: (latency = %u ms).\n",
|
||||
(unsigned)fifo_size, latency);
|
||||
|
||||
if (AudioOutputUnitStart(dev->dev) != noErr)
|
||||
@@ -307,31 +301,31 @@ static void *coreaudio_init(const char *device,
|
||||
return dev;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[CoreAudio]: Failed to initialize driver ...\n");
|
||||
RARCH_ERR("[CoreAudio] Failed to initialize driver.\n");
|
||||
coreaudio_free(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t coreaudio_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t coreaudio_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
coreaudio_t *dev = (coreaudio_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
size_t written = 0;
|
||||
size_t _len = 0;
|
||||
|
||||
while (!dev->is_paused && size > 0)
|
||||
while (!dev->is_paused && len > 0)
|
||||
{
|
||||
size_t write_avail;
|
||||
|
||||
slock_lock(dev->lock);
|
||||
|
||||
write_avail = FIFO_WRITE_AVAIL(dev->buffer);
|
||||
if (write_avail > size)
|
||||
write_avail = size;
|
||||
if (write_avail > len)
|
||||
write_avail = len;
|
||||
|
||||
fifo_write(dev->buffer, buf, write_avail);
|
||||
buf += write_avail;
|
||||
written += write_avail;
|
||||
size -= write_avail;
|
||||
_len += write_avail;
|
||||
len -= write_avail;
|
||||
|
||||
if (dev->nonblock)
|
||||
{
|
||||
@@ -353,7 +347,7 @@ static ssize_t coreaudio_write(void *data, const void *buf_, size_t size)
|
||||
slock_unlock(dev->lock);
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static void coreaudio_set_nonblock_state(void *data, bool state)
|
||||
@@ -374,19 +368,25 @@ static bool coreaudio_alive(void *data)
|
||||
static bool coreaudio_stop(void *data)
|
||||
{
|
||||
coreaudio_t *dev = (coreaudio_t*)data;
|
||||
if (!dev)
|
||||
return false;
|
||||
dev->is_paused = (AudioOutputUnitStop(dev->dev) == noErr) ? true : false;
|
||||
return dev->is_paused ? true : false;
|
||||
if (dev)
|
||||
{
|
||||
dev->is_paused = (AudioOutputUnitStop(dev->dev) == noErr) ? true : false;
|
||||
if (dev->is_paused)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool coreaudio_start(void *data, bool is_shutdown)
|
||||
{
|
||||
coreaudio_t *dev = (coreaudio_t*)data;
|
||||
if (!dev)
|
||||
return false;
|
||||
dev->is_paused = (AudioOutputUnitStart(dev->dev) == noErr) ? false : true;
|
||||
return dev->is_paused ? false : true;
|
||||
if (dev)
|
||||
{
|
||||
dev->is_paused = (AudioOutputUnitStart(dev->dev) == noErr) ? false : true;
|
||||
if (!dev->is_paused)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool coreaudio_use_float(void *data) { return true; }
|
||||
@@ -409,16 +409,9 @@ static size_t coreaudio_buffer_size(void *data)
|
||||
return dev->buffer_size;
|
||||
}
|
||||
|
||||
static void *coreaudio_device_list_new(void *data)
|
||||
{
|
||||
/* TODO/FIXME */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void coreaudio_device_list_free(void *data, void *array_list_data)
|
||||
{
|
||||
/* TODO/FIXME */
|
||||
}
|
||||
/* TODO/FIXME - implement */
|
||||
static void *coreaudio_device_list_new(void *data) { return NULL; }
|
||||
static void coreaudio_device_list_free(void *data, void *array_list_data) { }
|
||||
|
||||
audio_driver_t audio_coreaudio = {
|
||||
coreaudio_init,
|
||||
|
||||
+17
-23
@@ -27,6 +27,9 @@
|
||||
|
||||
#pragma mark - ringbuffer
|
||||
|
||||
#define UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#define LIKELY(x) __builtin_expect((x), 1)
|
||||
|
||||
typedef struct ringbuffer
|
||||
{
|
||||
float *buffer;
|
||||
@@ -93,9 +96,6 @@ static void rb_free(ringbuffer_h r)
|
||||
memset(r, 0, sizeof(*r));
|
||||
}
|
||||
|
||||
#define UNLIKELY(x) __builtin_expect((x), 0)
|
||||
#define LIKELY(x) __builtin_expect((x), 1)
|
||||
|
||||
static void rb_write_data(ringbuffer_h r, const float *data, size_t len)
|
||||
{
|
||||
size_t avail = rb_avail(r);
|
||||
@@ -109,8 +109,8 @@ static void rb_write_data(ringbuffer_h r, const float *data, size_t len)
|
||||
rest_write = n - first_write;
|
||||
}
|
||||
|
||||
memcpy(r->buffer + r->write_ptr, data, first_write*sizeof(float));
|
||||
memcpy(r->buffer, data + first_write, rest_write*sizeof(float));
|
||||
memcpy(r->buffer + r->write_ptr, data, first_write * sizeof(float));
|
||||
memcpy(r->buffer, data + first_write, rest_write * sizeof(float));
|
||||
|
||||
rb_advance_write_n(r, n);
|
||||
rb_len_add(r, (int)n);
|
||||
@@ -155,7 +155,7 @@ static void rb_read_data(ringbuffer_h r,
|
||||
|
||||
#pragma mark - CoreAudio3
|
||||
|
||||
static bool g_interrupted;
|
||||
static bool coreaudio3_g_interrupted;
|
||||
|
||||
@interface CoreAudio3 : NSObject {
|
||||
ringbuffer_t _rb;
|
||||
@@ -227,7 +227,7 @@ static bool g_interrupted;
|
||||
|
||||
_au = au;
|
||||
|
||||
RARCH_LOG("[CoreAudio3]: Using buffer size of %u bytes: (latency = %u ms)\n", (unsigned)self.bufferSizeInBytes, latency);
|
||||
RARCH_LOG("[CoreAudio3] Using buffer size of %u bytes: (latency = %u ms).\n", (unsigned)self.bufferSizeInBytes, latency);
|
||||
|
||||
[self start];
|
||||
}
|
||||
@@ -260,8 +260,8 @@ static bool g_interrupted;
|
||||
}
|
||||
|
||||
- (ssize_t)writeFloat:(const float *)data samples:(size_t)samples {
|
||||
size_t written = 0;
|
||||
while (!g_interrupted && samples > 0)
|
||||
size_t _len = 0;
|
||||
while (!coreaudio3_g_interrupted && samples > 0)
|
||||
{
|
||||
size_t write_avail = rb_avail(&_rb);
|
||||
if (write_avail > samples)
|
||||
@@ -269,7 +269,7 @@ static bool g_interrupted;
|
||||
|
||||
rb_write_data(&_rb, data, write_avail);
|
||||
data += write_avail;
|
||||
written += write_avail;
|
||||
_len += write_avail;
|
||||
samples -= write_avail;
|
||||
|
||||
if (_nonBlock)
|
||||
@@ -279,7 +279,7 @@ static bool g_interrupted;
|
||||
dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -307,12 +307,11 @@ static void *coreaudio3_init(const char *device,
|
||||
return (__bridge_retained void *)dev;
|
||||
}
|
||||
|
||||
static ssize_t coreaudio3_write(void *data,
|
||||
const void *buf_, size_t size)
|
||||
static ssize_t coreaudio3_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
CoreAudio3 *dev = (__bridge CoreAudio3 *)data;
|
||||
return [dev writeFloat:(const float *)
|
||||
buf_ samples:size/sizeof(float)] * sizeof(float);
|
||||
buf_ samples:len / sizeof(float)] * sizeof(float);
|
||||
}
|
||||
|
||||
static void coreaudio3_set_nonblock_state(void *data, bool state)
|
||||
@@ -328,8 +327,7 @@ static bool coreaudio3_alive(void *data)
|
||||
{
|
||||
CoreAudio3 *dev = (__bridge CoreAudio3 *)data;
|
||||
if (dev == nil)
|
||||
return NO;
|
||||
|
||||
return false;
|
||||
return !dev.paused;
|
||||
}
|
||||
|
||||
@@ -337,8 +335,7 @@ static bool coreaudio3_stop(void *data)
|
||||
{
|
||||
CoreAudio3 *dev = (__bridge CoreAudio3 *)data;
|
||||
if (dev == nil)
|
||||
return NO;
|
||||
|
||||
return false;
|
||||
[dev stop];
|
||||
return dev.paused;
|
||||
}
|
||||
@@ -347,16 +344,13 @@ static bool coreaudio3_start(void *data, bool is_shutdown)
|
||||
{
|
||||
CoreAudio3 *dev = (__bridge CoreAudio3 *)data;
|
||||
if (dev == nil)
|
||||
return NO;
|
||||
return false;
|
||||
|
||||
[dev start];
|
||||
return !dev.paused;
|
||||
}
|
||||
|
||||
static bool coreaudio3_use_float(void *data)
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
static bool coreaudio3_use_float(void *data) { return true; }
|
||||
|
||||
static size_t coreaudio3_write_avail(void *data)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,476 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2025 - Joseph Mattiello
|
||||
*
|
||||
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#include "audio/microphone_driver.h"
|
||||
#include "queues/fifo_queue.h"
|
||||
#include "verbosity.h"
|
||||
#include <memory.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "audio/audio_driver.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
typedef struct coreaudio_microphone
|
||||
{
|
||||
AudioUnit audio_unit; /* CoreAudio audio unit */
|
||||
AudioStreamBasicDescription format; /* Audio format */
|
||||
fifo_buffer_t *sample_buffer; /* Sample buffer */
|
||||
bool is_running; /* Whether the microphone is running */
|
||||
bool nonblock; /* Non-blocking mode flag */
|
||||
int sample_rate; /* Current sample rate */
|
||||
bool use_float; /* Whether to use float format */
|
||||
} coreaudio_microphone_t;
|
||||
|
||||
/* Callback for receiving audio samples */
|
||||
static OSStatus coreaudio_input_callback(
|
||||
void *inRefCon,
|
||||
AudioUnitRenderActionFlags *ioActionFlags,
|
||||
const AudioTimeStamp *inTimeStamp,
|
||||
UInt32 inBusNumber,
|
||||
UInt32 inNumberFrames,
|
||||
AudioBufferList *ioData)
|
||||
{
|
||||
OSStatus status;
|
||||
AudioBufferList bufferList;
|
||||
void *tempBuffer = NULL;
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)inRefCon;
|
||||
/* Calculate required buffer size */
|
||||
size_t bufferSize = inNumberFrames * microphone->format.mBytesPerFrame;
|
||||
if (bufferSize == 0)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Invalid buffer size calculation.\n");
|
||||
return kAudio_ParamError;
|
||||
}
|
||||
|
||||
/* Allocate temporary buffer */
|
||||
tempBuffer = malloc(bufferSize);
|
||||
if (!tempBuffer)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to allocate temporary buffer.\n");
|
||||
return kAudio_MemFullError;
|
||||
}
|
||||
|
||||
/* Set up buffer list */
|
||||
bufferList.mNumberBuffers = 1;
|
||||
bufferList.mBuffers[0].mDataByteSize = (UInt32)bufferSize;
|
||||
bufferList.mBuffers[0].mData = tempBuffer;
|
||||
|
||||
/* Render audio data */
|
||||
status = AudioUnitRender(microphone->audio_unit,
|
||||
ioActionFlags,
|
||||
inTimeStamp,
|
||||
inBusNumber,
|
||||
inNumberFrames,
|
||||
&bufferList);
|
||||
|
||||
/* Write to FIFO buffer */
|
||||
if (status == noErr)
|
||||
fifo_write(microphone->sample_buffer,
|
||||
bufferList.mBuffers[0].mData,
|
||||
bufferList.mBuffers[0].mDataByteSize);
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to render audio: %d.\n", status);
|
||||
}
|
||||
|
||||
/* Clean up temporary buffer */
|
||||
free(tempBuffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Initialize CoreAudio microphone driver */
|
||||
static void *coreaudio_microphone_init(void)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)calloc(1, sizeof(*microphone));
|
||||
if (!microphone)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to allocate microphone driver.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Default sample rate will be set during open_mic */
|
||||
microphone->sample_rate = 0;
|
||||
microphone->nonblock = false;
|
||||
microphone->use_float = false;
|
||||
|
||||
return microphone;
|
||||
}
|
||||
|
||||
/* Free CoreAudio microphone driver */
|
||||
static void coreaudio_microphone_free(void *driver_context)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)driver_context;
|
||||
if (microphone)
|
||||
{
|
||||
if (microphone->audio_unit && microphone->is_running)
|
||||
{
|
||||
AudioOutputUnitStop(microphone->audio_unit);
|
||||
microphone->is_running = false;
|
||||
}
|
||||
|
||||
/* TODO: This crashes, though we protect calls around `audio_unit` nil! */
|
||||
#if 0
|
||||
if (microphone->audio_unit)
|
||||
{
|
||||
AudioComponentInstanceDispose(microphone->audio_unit);
|
||||
microphone->audio_unit = nil;
|
||||
}
|
||||
#endif
|
||||
if (microphone->sample_buffer)
|
||||
fifo_free(microphone->sample_buffer);
|
||||
free(microphone);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read samples from microphone */
|
||||
static int coreaudio_microphone_read(void *driver_context,
|
||||
void *microphone_context, void *buf, size_t size)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)driver_context;
|
||||
size_t avail, read_amt;
|
||||
|
||||
if (!microphone || !buf)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Invalid parameters in read.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
avail = FIFO_READ_AVAIL(microphone->sample_buffer);
|
||||
read_amt = MIN(avail, size);
|
||||
|
||||
if (microphone->nonblock && read_amt == 0)
|
||||
return 0; /* Return immediately in non-blocking mode */
|
||||
|
||||
if (read_amt > 0)
|
||||
{
|
||||
fifo_read(microphone->sample_buffer, buf, read_amt);
|
||||
#if DEBUG
|
||||
RARCH_LOG("[CoreAudio] Read %zu bytes from microphone.\n", read_amt);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (int)read_amt;
|
||||
}
|
||||
|
||||
/* Set non-blocking state */
|
||||
static void coreaudio_microphone_set_nonblock_state(void *driver_context, bool state)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)driver_context;
|
||||
if (microphone)
|
||||
microphone->nonblock = state;
|
||||
}
|
||||
|
||||
/* Helper method to set audio format */
|
||||
static void coreaudio_microphone_set_format(coreaudio_microphone_t *microphone, bool use_float)
|
||||
{
|
||||
microphone->use_float = use_float; /* Store the format choice */
|
||||
microphone->format.mSampleRate = microphone->sample_rate;
|
||||
microphone->format.mFormatID = kAudioFormatLinearPCM;
|
||||
microphone->format.mFormatFlags = use_float
|
||||
? (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked)
|
||||
: (kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked);
|
||||
microphone->format.mFramesPerPacket = 1;
|
||||
microphone->format.mChannelsPerFrame = 1;
|
||||
microphone->format.mBitsPerChannel = use_float ? 32 : 16;
|
||||
microphone->format.mBytesPerFrame = microphone->format.mChannelsPerFrame * microphone->format.mBitsPerChannel / 8;
|
||||
microphone->format.mBytesPerPacket = microphone->format.mBytesPerFrame * microphone->format.mFramesPerPacket;
|
||||
|
||||
RARCH_LOG("[CoreAudio] Format setup: sample_rate=%d, bits=%d, bytes_per_frame=%d.\n",
|
||||
(int)microphone->format.mSampleRate,
|
||||
microphone->format.mBitsPerChannel,
|
||||
microphone->format.mBytesPerFrame);
|
||||
}
|
||||
|
||||
/* Open microphone device */
|
||||
static void *coreaudio_microphone_open_mic(void *driver_context,
|
||||
const char *device,
|
||||
unsigned rate,
|
||||
unsigned latency,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)driver_context;
|
||||
if (!microphone)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Invalid driver context.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize handle fields */
|
||||
microphone->sample_rate = rate;
|
||||
microphone->use_float = false; /* Default to integer format */
|
||||
|
||||
/* Validate requested sample rate */
|
||||
if (rate != 44100 && rate != 48000)
|
||||
{
|
||||
RARCH_WARN("[CoreAudio] Requested sample rate %u not supported, defaulting to 48000.\n", rate);
|
||||
rate = 48000;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
/* Configure audio session */
|
||||
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
|
||||
NSError *error = nil;
|
||||
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
|
||||
if (error)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to set audio session category: %s.\n", [[error localizedDescription] UTF8String]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*/ Set preferred sample rate */
|
||||
[audioSession setPreferredSampleRate:rate error:&error];
|
||||
if (error)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to set preferred sample rate: %s.\n", [[error localizedDescription] UTF8String]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get actual sample rate */
|
||||
Float64 actualRate = [audioSession sampleRate];
|
||||
if (new_rate)
|
||||
*new_rate = (unsigned)actualRate;
|
||||
microphone->sample_rate = (int)actualRate;
|
||||
|
||||
RARCH_LOG("[CoreAudio] Using sample rate: %d Hz.\n", microphone->sample_rate);
|
||||
#else
|
||||
|
||||
#endif
|
||||
|
||||
/* Set format using helper method */
|
||||
coreaudio_microphone_set_format(microphone, false); /* Default to 16-bit integer */
|
||||
|
||||
/* Calculate FIFO buffer size */
|
||||
size_t fifoBufferSize = (latency * microphone->sample_rate * microphone->format.mBytesPerFrame) / 1000;
|
||||
if (fifoBufferSize == 0)
|
||||
{
|
||||
RARCH_WARN("[CoreAudio] Calculated FIFO buffer size is 0 for latency: %u, sample_rate: %d, bytes_per_frame: %d.\n",
|
||||
latency, microphone->sample_rate, microphone->format.mBytesPerFrame);
|
||||
fifoBufferSize = 1024; /* Default to a reasonable buffer size */
|
||||
}
|
||||
|
||||
RARCH_LOG("[CoreAudio] FIFO buffer size: %zu bytes.\n", fifoBufferSize);
|
||||
|
||||
/* Create sample buffer */
|
||||
microphone->sample_buffer = fifo_new(fifoBufferSize);
|
||||
if (!microphone->sample_buffer)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to create sample buffer.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize audio unit */
|
||||
AudioComponentDescription desc = {
|
||||
.componentType = kAudioUnitType_Output,
|
||||
#if TARGET_OS_IPHONE
|
||||
.componentSubType = kAudioUnitSubType_RemoteIO,
|
||||
#else
|
||||
.componentSubType = kAudioUnitSubType_HALOutput,
|
||||
#endif
|
||||
.componentManufacturer = kAudioUnitManufacturer_Apple,
|
||||
.componentFlags = 0,
|
||||
.componentFlagsMask = 0
|
||||
};
|
||||
|
||||
AudioComponent comp = AudioComponentFindNext(NULL, &desc);
|
||||
OSStatus status = AudioComponentInstanceNew(comp, µphone->audio_unit);
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to create audio unit.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Enable input */
|
||||
UInt32 flag = 1;
|
||||
status = AudioUnitSetProperty(microphone->audio_unit,
|
||||
kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitScope_Input,
|
||||
1, /* Input bus */
|
||||
&flag,
|
||||
sizeof(flag));
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to enable input.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set format using helper method */
|
||||
coreaudio_microphone_set_format(microphone, false); /* Default to 16-bit integer */
|
||||
status = AudioUnitSetProperty(microphone->audio_unit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Output,
|
||||
1, /* Input bus */
|
||||
µphone->format,
|
||||
sizeof(microphone->format));
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to set format: %d.\n", status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Set callback */
|
||||
AURenderCallbackStruct callback = { coreaudio_input_callback, microphone };
|
||||
status = AudioUnitSetProperty(microphone->audio_unit,
|
||||
kAudioOutputUnitProperty_SetInputCallback,
|
||||
kAudioUnitScope_Global,
|
||||
1, /* Input bus */
|
||||
&callback,
|
||||
sizeof(callback));
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to set callback.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Initialize audio unit */
|
||||
status = AudioUnitInitialize(microphone->audio_unit);
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to initialize audio unit: %d.\n", status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Start audio unit */
|
||||
status = AudioOutputUnitStart(microphone->audio_unit);
|
||||
if (status != noErr)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to start audio unit: %d.\n", status);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return microphone;
|
||||
|
||||
error:
|
||||
if (microphone)
|
||||
{
|
||||
if (microphone->audio_unit)
|
||||
{
|
||||
AudioComponentInstanceDispose(microphone->audio_unit);
|
||||
microphone->audio_unit = nil;
|
||||
}
|
||||
free(microphone);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Close microphone */
|
||||
static void coreaudio_microphone_close_mic(void *driver_context, void *microphone_context)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)microphone_context;
|
||||
if (microphone)
|
||||
{
|
||||
if (microphone->is_running)
|
||||
AudioOutputUnitStop(microphone->audio_unit);
|
||||
|
||||
if (microphone->audio_unit)
|
||||
{
|
||||
AudioComponentInstanceDispose(microphone->audio_unit);
|
||||
microphone->audio_unit = nil;
|
||||
}
|
||||
if (microphone->sample_buffer)
|
||||
fifo_free(microphone->sample_buffer);
|
||||
free(microphone);
|
||||
}
|
||||
else
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to close microphone.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Start microphone */
|
||||
static bool coreaudio_microphone_start_mic(void *driver_context, void *microphone_context)
|
||||
{
|
||||
RARCH_LOG("[CoreAudio] Starting microphone.\n");
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)microphone_context;
|
||||
if (!microphone)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to start microphone.\n");
|
||||
return false;
|
||||
}
|
||||
RARCH_LOG("[CoreAudio] Starting audio unit...\n");
|
||||
|
||||
OSStatus status = AudioOutputUnitStart(microphone->audio_unit);
|
||||
if (status == noErr)
|
||||
{
|
||||
RARCH_LOG("[CoreAudio] Audio unit started successfully.\n");
|
||||
microphone->is_running = true;
|
||||
return true;
|
||||
}
|
||||
RARCH_ERR("[CoreAudio] Failed to start microphone: %d.\n", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Stop microphone */
|
||||
static bool coreaudio_microphone_stop_mic(void *driver_context, void *microphone_context)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)microphone_context;
|
||||
if (!microphone)
|
||||
{
|
||||
RARCH_ERR("[CoreAudio] Failed to stop microphone.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (microphone->is_running)
|
||||
{
|
||||
OSStatus status = AudioOutputUnitStop(microphone->audio_unit);
|
||||
if (status == noErr)
|
||||
{
|
||||
microphone->is_running = false;
|
||||
return true;
|
||||
}
|
||||
RARCH_ERR("[CoreAudio] Failed to stop microphone: %d.\n", status);
|
||||
}
|
||||
return true; /* Already stopped */
|
||||
}
|
||||
|
||||
/* Check if microphone is alive */
|
||||
static bool coreaudio_microphone_mic_alive(const void *driver_context, const void *microphone_context)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)microphone_context;
|
||||
return microphone && microphone->is_running;
|
||||
}
|
||||
|
||||
/* Check if microphone uses float samples */
|
||||
static bool coreaudio_microphone_mic_use_float(const void *driver_context, const void *microphone_context)
|
||||
{
|
||||
coreaudio_microphone_t *microphone = (coreaudio_microphone_t*)microphone_context;
|
||||
return microphone && microphone->use_float;
|
||||
}
|
||||
|
||||
/* Get device list (not implemented for CoreAudio) */
|
||||
static struct string_list *coreaudio_microphone_device_list_new(const void *driver_context)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Free device list (not implemented for CoreAudio) */
|
||||
static void coreaudio_microphone_device_list_free(const void *driver_context, struct string_list *devices)
|
||||
{
|
||||
}
|
||||
|
||||
/* CoreAudio microphone driver structure */
|
||||
microphone_driver_t microphone_coreaudio = {
|
||||
coreaudio_microphone_init,
|
||||
coreaudio_microphone_free,
|
||||
coreaudio_microphone_read,
|
||||
coreaudio_microphone_set_nonblock_state,
|
||||
"coreaudio",
|
||||
coreaudio_microphone_device_list_new,
|
||||
coreaudio_microphone_device_list_free,
|
||||
coreaudio_microphone_open_mic,
|
||||
coreaudio_microphone_close_mic,
|
||||
coreaudio_microphone_mic_alive,
|
||||
coreaudio_microphone_start_mic,
|
||||
coreaudio_microphone_stop_mic,
|
||||
coreaudio_microphone_mic_use_float
|
||||
};
|
||||
File diff suppressed because it is too large.
Load diff
@@ -162,34 +162,35 @@ static void ctr_csnd_audio_free(void *data)
|
||||
free(ctr);
|
||||
}
|
||||
|
||||
static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
uint32_t samples_played = 0;
|
||||
uint64_t current_tick = 0;
|
||||
const uint16_t *src = buf;
|
||||
ctr_csnd_audio_t *ctr = (ctr_csnd_audio_t*)data;
|
||||
unsigned int i;
|
||||
uint32_t samples_played = 0;
|
||||
uint64_t current_tick = 0;
|
||||
const uint16_t *src = buf;
|
||||
ctr_csnd_audio_t *ctr = (ctr_csnd_audio_t*)data;
|
||||
|
||||
ctr_csnd_audio_update_playpos(ctr);
|
||||
|
||||
if ((((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 2)) ||
|
||||
(((ctr->pos - ctr->playpos ) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)) ||
|
||||
(((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||
if ( (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 2))
|
||||
|| (((ctr->pos - ctr->playpos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4))
|
||||
|| (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (len >> 2)))
|
||||
{
|
||||
if (ctr->nonblock)
|
||||
ctr->pos = (ctr->playpos + (CTR_CSND_AUDIO_COUNT >> 1)) & CTR_CSND_AUDIO_COUNT_MASK;
|
||||
else
|
||||
{
|
||||
do{
|
||||
do
|
||||
{
|
||||
/* todo: compute the correct sleep period */
|
||||
retro_sleep(1);
|
||||
ctr_csnd_audio_update_playpos(ctr);
|
||||
}while (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 1)
|
||||
} while (((ctr->playpos - ctr->pos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 1)
|
||||
|| (((ctr->pos - ctr->playpos) & CTR_CSND_AUDIO_COUNT_MASK) < (CTR_CSND_AUDIO_COUNT >> 4)));
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < (size >> 1); i += 2)
|
||||
for (i = 0; i < (len >> 1); i += 2)
|
||||
{
|
||||
ctr->l[ctr->pos] = src[i];
|
||||
ctr->r[ctr->pos] = src[i + 1];
|
||||
@@ -200,7 +201,7 @@ static ssize_t ctr_csnd_audio_write(void *data, const void *buf, size_t size)
|
||||
GSPGPU_FlushDataCache(ctr->l, CTR_CSND_AUDIO_SIZE);
|
||||
GSPGPU_FlushDataCache(ctr->r, CTR_CSND_AUDIO_SIZE);
|
||||
|
||||
return size;
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool ctr_csnd_audio_stop(void *data)
|
||||
@@ -239,20 +240,19 @@ static bool ctr_csnd_audio_start(void *data, bool is_shutdown)
|
||||
|
||||
/* Prevents restarting audio when the menu
|
||||
* is toggled off on shutdown */
|
||||
if (is_shutdown)
|
||||
return true;
|
||||
|
||||
if (!is_shutdown)
|
||||
{
|
||||
#if 0
|
||||
CSND_SetPlayState(0x8, 1);
|
||||
CSND_SetPlayState(0x9, 1);
|
||||
CSND_SetPlayState(0x8, 1);
|
||||
CSND_SetPlayState(0x9, 1);
|
||||
#endif
|
||||
|
||||
CSND_SetVol(0x8, 0x00008000, 0);
|
||||
CSND_SetVol(0x9, 0x80000000, 0);
|
||||
CSND_SetVol(0x8, 0x00008000, 0);
|
||||
CSND_SetVol(0x9, 0x80000000, 0);
|
||||
|
||||
csndExecCmds(false);
|
||||
|
||||
ctr->playing = true;
|
||||
csndExecCmds(false);
|
||||
ctr->playing = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -264,11 +264,7 @@ static void ctr_csnd_audio_set_nonblock_state(void *data, bool state)
|
||||
ctr->nonblock = state;
|
||||
}
|
||||
|
||||
static bool ctr_csnd_audio_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
static bool ctr_csnd_audio_use_float(void *data) { return false; }
|
||||
|
||||
static size_t ctr_csnd_audio_write_avail(void *data)
|
||||
{
|
||||
@@ -280,7 +276,6 @@ static size_t ctr_csnd_audio_write_avail(void *data)
|
||||
|
||||
static size_t ctr_csnd_audio_buffer_size(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return CTR_CSND_AUDIO_COUNT;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../../ctr/ctr_debug.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -91,15 +93,15 @@ static void ctr_dsp_audio_free(void *data)
|
||||
ndspExit();
|
||||
}
|
||||
|
||||
static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
u32 pos;
|
||||
ctr_dsp_audio_t * ctr = (ctr_dsp_audio_t*)data;
|
||||
uint32_t sample_pos = ndspChnGetSamplePos(ctr->channel);
|
||||
ctr_dsp_audio_t *ctr = (ctr_dsp_audio_t*)data;
|
||||
uint32_t sample_pos = ndspChnGetSamplePos(ctr->channel);
|
||||
|
||||
if ((((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 2)) ||
|
||||
(((ctr->pos - sample_pos ) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4)) ||
|
||||
(((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (size >> 2)))
|
||||
if ( (((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 2))
|
||||
|| (((ctr->pos - sample_pos) & CTR_DSP_AUDIO_COUNT_MASK) < (CTR_DSP_AUDIO_COUNT >> 4))
|
||||
|| (((sample_pos - ctr->pos) & CTR_DSP_AUDIO_COUNT_MASK) < (len >> 2)))
|
||||
{
|
||||
if (ctr->nonblock)
|
||||
ctr->pos = (sample_pos + (CTR_DSP_AUDIO_COUNT >> 1)) & CTR_DSP_AUDIO_COUNT_MASK;
|
||||
@@ -113,38 +115,38 @@ static ssize_t ctr_dsp_audio_write(void *data, const void *buf, size_t size)
|
||||
* changed, this prevents a hang on sleep. */
|
||||
if (!aptMainLoop())
|
||||
{
|
||||
command_event(CMD_EVENT_QUIT, NULL);
|
||||
retroarch_main_quit();
|
||||
return true;
|
||||
}
|
||||
|
||||
sample_pos = ndspChnGetSamplePos(ctr->channel);
|
||||
}while ( ((sample_pos - (ctr->pos + (size >>2))) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1)
|
||||
}while ( ((sample_pos - (ctr->pos + (len >>2))) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1)
|
||||
|| (((ctr->pos - (CTR_DSP_AUDIO_COUNT >> 4) - sample_pos) & CTR_DSP_AUDIO_COUNT_MASK) > (CTR_DSP_AUDIO_COUNT >> 1)));
|
||||
}
|
||||
}
|
||||
|
||||
pos = ctr->pos << 2;
|
||||
|
||||
if ((pos + size) > CTR_DSP_AUDIO_SIZE)
|
||||
if ((pos + len) > CTR_DSP_AUDIO_SIZE)
|
||||
{
|
||||
memcpy(ctr->dsp_buf.data_pcm8 + pos, buf,
|
||||
(CTR_DSP_AUDIO_SIZE - pos));
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, (CTR_DSP_AUDIO_SIZE - pos));
|
||||
|
||||
memcpy(ctr->dsp_buf.data_pcm8, (uint8_t*) buf + (CTR_DSP_AUDIO_SIZE - pos),
|
||||
(pos + size - CTR_DSP_AUDIO_SIZE));
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8, (pos + size - CTR_DSP_AUDIO_SIZE));
|
||||
(pos + len - CTR_DSP_AUDIO_SIZE));
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8, (pos + len - CTR_DSP_AUDIO_SIZE));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(ctr->dsp_buf.data_pcm8 + pos, buf, size);
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, size);
|
||||
memcpy(ctr->dsp_buf.data_pcm8 + pos, buf, len);
|
||||
DSP_FlushDataCache(ctr->dsp_buf.data_pcm8 + pos, len);
|
||||
}
|
||||
|
||||
ctr->pos += size >> 2;
|
||||
ctr->pos += len >> 2;
|
||||
ctr->pos &= CTR_DSP_AUDIO_COUNT_MASK;
|
||||
|
||||
return size;
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_audio_stop(void *data)
|
||||
@@ -169,11 +171,11 @@ static bool ctr_dsp_audio_start(void *data, bool is_shutdown)
|
||||
|
||||
/* Prevents restarting audio when the menu
|
||||
* is toggled off on shutdown */
|
||||
if (is_shutdown)
|
||||
return true;
|
||||
|
||||
ndspSetMasterVol(1.0);
|
||||
ctr->playing = true;
|
||||
if (!is_shutdown)
|
||||
{
|
||||
ndspSetMasterVol(1.0);
|
||||
ctr->playing = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -185,11 +187,7 @@ static void ctr_dsp_audio_set_nonblock_state(void *data, bool state)
|
||||
ctr->nonblock = state;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_audio_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
static bool ctr_dsp_audio_use_float(void *data) { return false; }
|
||||
|
||||
static size_t ctr_dsp_audio_write_avail(void *data)
|
||||
{
|
||||
@@ -200,7 +198,6 @@ static size_t ctr_dsp_audio_write_avail(void *data)
|
||||
|
||||
static size_t ctr_dsp_audio_buffer_size(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return CTR_DSP_AUDIO_COUNT;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
#include <3ds.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <math.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../../ctr/ctr_debug.h"
|
||||
#include "../../verbosity.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -43,7 +45,7 @@ typedef struct
|
||||
uint32_t pos;
|
||||
} ctr_dsp_thread_audio_t;
|
||||
|
||||
// PCM16 stereo
|
||||
/* PCM16 stereo */
|
||||
#define DSP_BYTES_TO_SAMPLES(bytes) (bytes / (2 * sizeof(uint16_t)))
|
||||
#define DSP_SAMPLES_TO_BYTES(samples) (samples * 2 * sizeof(uint16_t))
|
||||
|
||||
@@ -148,7 +150,7 @@ static void *ctr_dsp_thread_audio_init(const char *device, unsigned rate, unsign
|
||||
|| !(ctr->fifo_done = scond_new())
|
||||
|| !(ctr->thread = sthread_create(ctr_dsp_audio_loop, ctr)))
|
||||
{
|
||||
RARCH_LOG("[Audio]: thread creation failed.\n");
|
||||
RARCH_LOG("[Audio] Thread creation failed.\n");
|
||||
ctr->running = false;
|
||||
ctr_dsp_thread_audio_free(ctr);
|
||||
return NULL;
|
||||
@@ -198,9 +200,9 @@ static void ctr_dsp_thread_audio_free(void *data)
|
||||
ctr = NULL;
|
||||
}
|
||||
|
||||
static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
size_t avail, written;
|
||||
size_t avail, _len;
|
||||
ctr_dsp_thread_audio_t * ctr = (ctr_dsp_thread_audio_t*)data;
|
||||
|
||||
if (!ctr || !ctr->running)
|
||||
@@ -210,18 +212,18 @@ static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t si
|
||||
{
|
||||
slock_lock(ctr->fifo_lock);
|
||||
avail = FIFO_WRITE_AVAIL(ctr->fifo);
|
||||
written = MIN(avail, size);
|
||||
if (written > 0)
|
||||
_len = MIN(avail, len);
|
||||
if (_len > 0)
|
||||
{
|
||||
fifo_write(ctr->fifo, buf, written);
|
||||
fifo_write(ctr->fifo, buf, _len);
|
||||
scond_signal(ctr->fifo_avail);
|
||||
}
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
written = 0;
|
||||
while (written < size && ctr->running)
|
||||
_len = 0;
|
||||
while (_len < len && ctr->running)
|
||||
{
|
||||
slock_lock(ctr->fifo_lock);
|
||||
avail = FIFO_WRITE_AVAIL(ctr->fifo);
|
||||
@@ -240,16 +242,16 @@ static ssize_t ctr_dsp_thread_audio_write(void *data, const void *buf, size_t si
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t write_amt = MIN(size - written, avail);
|
||||
fifo_write(ctr->fifo, (const char*)buf + written, write_amt);
|
||||
size_t write_amt = MIN(len - _len, avail);
|
||||
fifo_write(ctr->fifo, (const char*)buf + _len, write_amt);
|
||||
scond_signal(ctr->fifo_avail);
|
||||
slock_unlock(ctr->fifo_lock);
|
||||
written += write_amt;
|
||||
_len += write_amt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool ctr_dsp_thread_audio_stop(void *data)
|
||||
|
||||
+166
-147
@@ -53,6 +53,8 @@
|
||||
#pragma comment(lib, "dxguid")
|
||||
#endif
|
||||
|
||||
#define CHUNK_SIZE 256
|
||||
|
||||
typedef struct dsound
|
||||
{
|
||||
LPDIRECTSOUND ds;
|
||||
@@ -67,7 +69,7 @@ typedef struct dsound
|
||||
#else
|
||||
HANDLE thread;
|
||||
#endif
|
||||
|
||||
size_t fifo_bufsize;
|
||||
unsigned buffer_size;
|
||||
|
||||
bool nonblock;
|
||||
@@ -75,17 +77,6 @@ typedef struct dsound
|
||||
volatile bool thread_alive;
|
||||
} dsound_t;
|
||||
|
||||
/* Forward declarations */
|
||||
static void *dsound_list_new(void *u);
|
||||
|
||||
static INLINE unsigned write_avail(unsigned read_ptr,
|
||||
unsigned write_ptr, unsigned buffer_size)
|
||||
{
|
||||
return (read_ptr + buffer_size - write_ptr) % buffer_size;
|
||||
}
|
||||
|
||||
#define CHUNK_SIZE 256
|
||||
|
||||
struct audio_lock
|
||||
{
|
||||
void *chunk1;
|
||||
@@ -94,39 +85,94 @@ struct audio_lock
|
||||
DWORD size2;
|
||||
};
|
||||
|
||||
static bool grab_region(dsound_t *ds, uint32_t write_ptr,
|
||||
static BOOL CALLBACK dsound_enumerate_cb(LPGUID guid,
|
||||
LPCSTR desc, LPCSTR module, LPVOID context)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *list = (struct string_list*)context;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
string_list_append(list, desc, attr);
|
||||
|
||||
if (guid)
|
||||
{
|
||||
LPGUID guid_copy = (LPGUID)malloc(sizeof(GUID) * 1);
|
||||
|
||||
if (guid_copy)
|
||||
{
|
||||
int i;
|
||||
|
||||
guid_copy->Data1 = guid->Data1;
|
||||
guid_copy->Data2 = guid->Data2;
|
||||
guid_copy->Data3 = guid->Data3;
|
||||
for (i = 0; i < 8; i++)
|
||||
guid_copy->Data4[i] = guid->Data4[i];
|
||||
|
||||
list->elems[list->size - 1].userdata = guid_copy;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void *dsound_list_new(void *u)
|
||||
{
|
||||
struct string_list *sl = string_list_new();
|
||||
|
||||
if (!sl)
|
||||
return NULL;
|
||||
|
||||
#ifndef _XBOX
|
||||
#ifdef UNICODE
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACKW)dsound_enumerate_cb, sl);
|
||||
#else
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACKA)dsound_enumerate_cb, sl);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
static INLINE unsigned _dsound_write_avail(unsigned read_ptr,
|
||||
unsigned write_ptr, unsigned buffer_size)
|
||||
{
|
||||
return (read_ptr + buffer_size - write_ptr) % buffer_size;
|
||||
}
|
||||
|
||||
static bool dsound_grab_region(dsound_t *ds, uint32_t write_ptr,
|
||||
struct audio_lock *region, HRESULT res)
|
||||
{
|
||||
if (res == DSERR_BUFFERLOST)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
RARCH_WARN("[DirectSound error]: %s\n", "DSERR_BUFFERLOST");
|
||||
RARCH_WARN("[DirectSound] %s.\n", "DSERR_BUFFERLOST");
|
||||
#endif
|
||||
if ((res = IDirectSoundBuffer_Restore(ds->dsb)) != DS_OK)
|
||||
return false;
|
||||
if ((res = IDirectSoundBuffer_Lock(ds->dsb, write_ptr, CHUNK_SIZE,
|
||||
®ion->chunk1, ®ion->size1, ®ion->chunk2, ®ion->size2, 0)) != DS_OK)
|
||||
return false;
|
||||
return true;
|
||||
if ((IDirectSoundBuffer_Restore(ds->dsb)) == DS_OK)
|
||||
if ((IDirectSoundBuffer_Lock(ds->dsb, write_ptr, CHUNK_SIZE,
|
||||
®ion->chunk1, ®ion->size1, ®ion->chunk2, ®ion->size2, 0)) == DS_OK)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
switch (res)
|
||||
else
|
||||
{
|
||||
case DSERR_INVALIDCALL:
|
||||
RARCH_WARN("[DirectSound error]: %s\n", "DSERR_INVALIDCALL");
|
||||
break;
|
||||
case DSERR_INVALIDPARAM:
|
||||
RARCH_WARN("[DirectSound error]: %s\n", "DSERR_INVALIDPARAM");
|
||||
break;
|
||||
case DSERR_PRIOLEVELNEEDED:
|
||||
RARCH_WARN("[DirectSound error]: %s\n", "DSERR_PRIOLEVELNEEDED");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch (res)
|
||||
{
|
||||
case DSERR_INVALIDCALL:
|
||||
RARCH_WARN("[DirectSound] %s.\n", "DSERR_INVALIDCALL");
|
||||
break;
|
||||
case DSERR_INVALIDPARAM:
|
||||
RARCH_WARN("[DirectSound] %s.\n", "DSERR_INVALIDPARAM");
|
||||
break;
|
||||
case DSERR_PRIOLEVELNEEDED:
|
||||
RARCH_WARN("[DirectSound] %s.\n", "DSERR_PRIOLEVELNEEDED");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,7 +198,7 @@ static DWORD CALLBACK dsound_thread(PVOID data)
|
||||
DWORD read_ptr, avail, fifo_avail;
|
||||
|
||||
IDirectSoundBuffer_GetCurrentPosition(ds->dsb, &read_ptr, NULL);
|
||||
avail = write_avail(read_ptr, write_ptr, ds->buffer_size);
|
||||
avail = _dsound_write_avail(read_ptr, write_ptr, ds->buffer_size);
|
||||
|
||||
EnterCriticalSection(&ds->crit);
|
||||
fifo_avail = FIFO_READ_AVAIL(ds->buffer);
|
||||
@@ -174,7 +220,7 @@ static DWORD CALLBACK dsound_thread(PVOID data)
|
||||
if ((res = IDirectSoundBuffer_Lock(ds->dsb, write_ptr, CHUNK_SIZE,
|
||||
®ion.chunk1, ®ion.size1, ®ion.chunk2, ®ion.size2, 0)) != DS_OK)
|
||||
{
|
||||
if (!grab_region(ds, write_ptr, ®ion, res))
|
||||
if (!dsound_grab_region(ds, write_ptr, ®ion, res))
|
||||
{
|
||||
ds->thread_alive = false;
|
||||
SetEvent(ds->event);
|
||||
@@ -192,7 +238,6 @@ static DWORD CALLBACK dsound_thread(PVOID data)
|
||||
else
|
||||
{
|
||||
/* All is good. Pull from it and notify FIFO. */
|
||||
|
||||
EnterCriticalSection(&ds->crit);
|
||||
if (region.chunk1)
|
||||
fifo_read(ds->buffer, region.chunk1, region.size1);
|
||||
@@ -205,7 +250,7 @@ static DWORD CALLBACK dsound_thread(PVOID data)
|
||||
|
||||
IDirectSoundBuffer_Unlock(ds->dsb, region.chunk1,
|
||||
region.size1, region.chunk2, region.size2);
|
||||
write_ptr = (write_ptr + region.size1 + region.size2)
|
||||
write_ptr = (write_ptr + region.size1 + region.size2)
|
||||
% ds->buffer_size;
|
||||
|
||||
if (is_pull)
|
||||
@@ -237,11 +282,10 @@ static bool dsound_start_thread(dsound_t *ds)
|
||||
if (!ds->thread)
|
||||
{
|
||||
ds->thread_alive = true;
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
ds->thread = sthread_create(dsound_thread, ds);
|
||||
ds->thread = sthread_create(dsound_thread, ds);
|
||||
#else
|
||||
ds->thread = CreateThread(NULL, 0, dsound_thread, ds, 0, NULL);
|
||||
ds->thread = CreateThread(NULL, 0, dsound_thread, ds, 0, NULL);
|
||||
#endif
|
||||
if (!ds->thread)
|
||||
return false;
|
||||
@@ -303,78 +347,71 @@ static void dsound_free(void *data)
|
||||
free(ds);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK enumerate_cb(LPGUID guid,
|
||||
LPCSTR desc, LPCSTR module, LPVOID context)
|
||||
static void dsound_set_format(WAVEFORMATEX *wf,
|
||||
bool float_fmt, unsigned channels, unsigned rate)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
struct string_list *list = (struct string_list*)context;
|
||||
WORD wBitsPerSample = float_fmt ? 32 : 16;
|
||||
WORD nBlockAlign = (channels * wBitsPerSample) / 8;
|
||||
DWORD nAvgBytesPerSec = rate * nBlockAlign;
|
||||
|
||||
attr.i = 0;
|
||||
if (float_fmt)
|
||||
wf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
|
||||
else
|
||||
wf->wFormatTag = WAVE_FORMAT_PCM;
|
||||
|
||||
string_list_append(list, desc, attr);
|
||||
wf->nChannels = channels;
|
||||
wf->nSamplesPerSec = rate;
|
||||
wf->nAvgBytesPerSec = nAvgBytesPerSec;
|
||||
wf->nBlockAlign = nBlockAlign;
|
||||
wf->wBitsPerSample = wBitsPerSample;
|
||||
|
||||
if (guid)
|
||||
{
|
||||
LPGUID guid_copy = (LPGUID)malloc(sizeof(GUID) * 1);
|
||||
|
||||
if (guid_copy)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
guid_copy->Data1 = guid->Data1;
|
||||
guid_copy->Data2 = guid->Data2;
|
||||
guid_copy->Data3 = guid->Data3;
|
||||
for (i = 0; i < 8; i++)
|
||||
guid_copy->Data4[i] = guid->Data4[i];
|
||||
|
||||
list->elems[list->size - 1].userdata = guid_copy;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
wf->cbSize = 0;
|
||||
}
|
||||
|
||||
static void dsound_set_wavefmt(WAVEFORMATEX *wfx,
|
||||
unsigned channels, unsigned samplerate)
|
||||
static const char *dsound_wave_format_name(const WAVEFORMATEX *format)
|
||||
{
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->nBlockAlign = channels * sizeof(int16_t);
|
||||
wfx->wBitsPerSample = 16;
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
case WAVE_FORMAT_PCM:
|
||||
return "WAVE_FORMAT_PCM";
|
||||
case WAVE_FORMAT_IEEE_FLOAT:
|
||||
return "WAVE_FORMAT_IEEE_FLOAT";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
wfx->nChannels = channels;
|
||||
wfx->nSamplesPerSec = samplerate;
|
||||
wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
|
||||
wfx->cbSize = 0;
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
static void *dsound_init(const char *dev, unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
unsigned block_frames, unsigned *new_rate)
|
||||
{
|
||||
LPGUID selected_device = NULL;
|
||||
WAVEFORMATEX wfx = {0};
|
||||
DSBUFFERDESC bufdesc = {0};
|
||||
int32_t idx_found = -1;
|
||||
struct string_list *list = (struct string_list*)dsound_list_new(NULL);
|
||||
dsound_t *ds = (dsound_t*)calloc(1, sizeof(*ds));
|
||||
LPGUID selected_device = NULL;
|
||||
WAVEFORMATEX wf = {0};
|
||||
DSBUFFERDESC bufdesc = {0};
|
||||
dsound_t *ds = (dsound_t*)calloc(1, sizeof(*ds));
|
||||
|
||||
if (!ds)
|
||||
goto error;
|
||||
return NULL;
|
||||
|
||||
InitializeCriticalSection(&ds->crit);
|
||||
|
||||
if (dev)
|
||||
{
|
||||
struct string_list *list = (struct string_list*)dsound_list_new(NULL);
|
||||
|
||||
/* Search for device name first */
|
||||
if (list && list->elems)
|
||||
{
|
||||
int32_t idx_found = -1;
|
||||
if (list->elems)
|
||||
{
|
||||
unsigned i;
|
||||
size_t i;
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
if (string_is_equal(dev, list->elems[i].data))
|
||||
{
|
||||
RARCH_DBG("[DirectSound] Found device #%d: \"%s\".\n", i, list->elems[i].data);
|
||||
idx_found = i;
|
||||
selected_device = (LPGUID)list->elems[idx_found].userdata;
|
||||
break;
|
||||
@@ -386,19 +423,21 @@ static void *dsound_init(const char *dev, unsigned rate, unsigned latency,
|
||||
if (idx_found == -1 && isdigit(dev[0]))
|
||||
{
|
||||
idx_found = strtoul(dev, NULL, 0);
|
||||
RARCH_LOG("[DirectSound]: Fallback, device index is a single number index instead: %d.\n", idx_found);
|
||||
RARCH_LOG("[DirectSound] Fallback, device index is a single number index instead: %d.\n", idx_found);
|
||||
|
||||
if (idx_found != -1)
|
||||
{
|
||||
if (idx_found < (int32_t)list->size)
|
||||
{
|
||||
RARCH_LOG("[DirectSound]: Corresponding name: %s\n", list->elems[idx_found].data);
|
||||
RARCH_LOG("[DirectSound] Corresponding name: %s.\n", list->elems[idx_found].data);
|
||||
selected_device = (LPGUID)list->elems[idx_found].userdata;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_list_free(list);
|
||||
}
|
||||
|
||||
if (DirectSoundCreate(selected_device, &ds->ds, NULL) != DS_OK)
|
||||
@@ -409,16 +448,22 @@ static void *dsound_init(const char *dev, unsigned rate, unsigned latency,
|
||||
goto error;
|
||||
#endif
|
||||
|
||||
dsound_set_wavefmt(&wfx, 2, rate);
|
||||
dsound_set_format(&wf, false, 2, rate);
|
||||
RARCH_DBG("[DirectSound] Requesting %u-bit %u-channel client with %s samples at %uHz %ums.\n",
|
||||
wf.wBitsPerSample,
|
||||
wf.nChannels,
|
||||
dsound_wave_format_name(&wf),
|
||||
wf.nSamplesPerSec,
|
||||
latency);
|
||||
|
||||
ds->buffer_size = (latency * wfx.nAvgBytesPerSec) / 1000;
|
||||
ds->buffer_size = (latency * wf.nAvgBytesPerSec) / 1000;
|
||||
ds->buffer_size /= CHUNK_SIZE;
|
||||
ds->buffer_size *= CHUNK_SIZE;
|
||||
if (ds->buffer_size < 4 * CHUNK_SIZE)
|
||||
ds->buffer_size = 4 * CHUNK_SIZE;
|
||||
|
||||
RARCH_LOG("[DirectSound]: Setting buffer size of %u bytes\n", ds->buffer_size);
|
||||
RARCH_LOG("[DirectSound]: Latency = %u ms\n", (unsigned)((1000 * ds->buffer_size) / wfx.nAvgBytesPerSec));
|
||||
RARCH_LOG("[DirectSound] Setting buffer size of %u bytes.\n", ds->buffer_size);
|
||||
RARCH_LOG("[DirectSound] Latency = %u ms.\n", (unsigned)((1000 * ds->buffer_size) / wf.nAvgBytesPerSec));
|
||||
|
||||
bufdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
bufdesc.dwFlags = 0;
|
||||
@@ -426,13 +471,14 @@ static void *dsound_init(const char *dev, unsigned rate, unsigned latency,
|
||||
bufdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
|
||||
#endif
|
||||
bufdesc.dwBufferBytes = ds->buffer_size;
|
||||
bufdesc.lpwfxFormat = &wfx;
|
||||
bufdesc.lpwfxFormat = &wf;
|
||||
|
||||
ds->event = CreateEvent(NULL, false, false, NULL);
|
||||
if (!ds->event)
|
||||
goto error;
|
||||
|
||||
ds->buffer = fifo_new(4 * 1024);
|
||||
ds->fifo_bufsize = 4 * 1024;
|
||||
ds->buffer = fifo_new(ds->fifo_bufsize);
|
||||
if (!ds->buffer)
|
||||
goto error;
|
||||
|
||||
@@ -444,19 +490,12 @@ static void *dsound_init(const char *dev, unsigned rate, unsigned latency,
|
||||
|
||||
dsound_clear_buffer(ds);
|
||||
|
||||
if (IDirectSoundBuffer_Play(ds->dsb, 0, 0, DSBPLAY_LOOPING) != DS_OK)
|
||||
goto error;
|
||||
|
||||
if (!dsound_start_thread(ds))
|
||||
goto error;
|
||||
|
||||
string_list_free(list);
|
||||
return ds;
|
||||
if (IDirectSoundBuffer_Play(ds->dsb, 0, 0, DSBPLAY_LOOPING) == DS_OK)
|
||||
if (dsound_start_thread(ds))
|
||||
return ds;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[DirectSound] Error occurred in init.\n");
|
||||
if (list)
|
||||
string_list_free(list);
|
||||
dsound_free(ds);
|
||||
return NULL;
|
||||
}
|
||||
@@ -464,11 +503,9 @@ error:
|
||||
static bool dsound_stop(void *data)
|
||||
{
|
||||
dsound_t *ds = (dsound_t*)data;
|
||||
|
||||
dsound_stop_thread(ds);
|
||||
ds->is_paused = (IDirectSoundBuffer_Stop(ds->dsb) == DS_OK) ? true : false;
|
||||
|
||||
return (ds->is_paused) ? true : false;
|
||||
return ds->is_paused;
|
||||
}
|
||||
|
||||
static bool dsound_start(void *data, bool is_shutdown)
|
||||
@@ -482,16 +519,13 @@ static bool dsound_start(void *data, bool is_shutdown)
|
||||
|
||||
ds->is_paused = (IDirectSoundBuffer_Play(
|
||||
ds->dsb, 0, 0, DSBPLAY_LOOPING) == DS_OK) ? false : true;
|
||||
return (ds->is_paused) ? false : true;
|
||||
return !ds->is_paused;
|
||||
}
|
||||
|
||||
static bool dsound_alive(void *data)
|
||||
{
|
||||
dsound_t *ds = (dsound_t*)data;
|
||||
|
||||
if (!ds)
|
||||
return false;
|
||||
return !ds->is_paused;
|
||||
return ds && !ds->is_paused;
|
||||
}
|
||||
|
||||
static void dsound_set_nonblock_state(void *data, bool state)
|
||||
@@ -501,9 +535,9 @@ static void dsound_set_nonblock_state(void *data, bool state)
|
||||
ds->nonblock = state;
|
||||
}
|
||||
|
||||
static ssize_t dsound_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t dsound_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
size_t written = 0;
|
||||
size_t _len = 0;
|
||||
dsound_t *ds = (dsound_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
|
||||
@@ -512,51 +546,48 @@ static ssize_t dsound_write(void *data, const void *buf_, size_t size)
|
||||
|
||||
if (ds->nonblock)
|
||||
{
|
||||
if (size > 0)
|
||||
if (len > 0)
|
||||
{
|
||||
size_t avail;
|
||||
|
||||
EnterCriticalSection(&ds->crit);
|
||||
avail = FIFO_WRITE_AVAIL(ds->buffer);
|
||||
if (avail > size)
|
||||
avail = size;
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
fifo_write(ds->buffer, buf, avail);
|
||||
LeaveCriticalSection(&ds->crit);
|
||||
|
||||
buf += avail;
|
||||
size -= avail;
|
||||
written += avail;
|
||||
_len += avail;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (size > 0)
|
||||
while (len > 0)
|
||||
{
|
||||
size_t avail;
|
||||
|
||||
EnterCriticalSection(&ds->crit);
|
||||
avail = FIFO_WRITE_AVAIL(ds->buffer);
|
||||
if (avail > size)
|
||||
avail = size;
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
fifo_write(ds->buffer, buf, avail);
|
||||
LeaveCriticalSection(&ds->crit);
|
||||
|
||||
buf += avail;
|
||||
size -= avail;
|
||||
written += avail;
|
||||
buf += avail;
|
||||
_len += avail;
|
||||
len -= avail;
|
||||
|
||||
if (!ds->thread_alive)
|
||||
break;
|
||||
|
||||
if (avail == 0)
|
||||
if (!(WaitForSingleObject(ds->event, 50) == WAIT_OBJECT_0))
|
||||
return -1;
|
||||
if (avail == 0 && !(WaitForSingleObject(ds->event, 50) == WAIT_OBJECT_0))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static size_t dsound_write_avail(void *data)
|
||||
@@ -570,27 +601,15 @@ static size_t dsound_write_avail(void *data)
|
||||
return avail;
|
||||
}
|
||||
|
||||
static size_t dsound_buffer_size(void *data) { return 4 * 1024; }
|
||||
static bool dsound_use_float(void *data) { return false; }
|
||||
|
||||
static void *dsound_list_new(void *u)
|
||||
static size_t dsound_buffer_size(void *data)
|
||||
{
|
||||
struct string_list *sl = string_list_new();
|
||||
|
||||
if (!sl)
|
||||
return NULL;
|
||||
|
||||
#ifndef _XBOX
|
||||
#ifdef UNICODE
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACKW)enumerate_cb, sl);
|
||||
#else
|
||||
DirectSoundEnumerate((LPDSENUMCALLBACKA)enumerate_cb, sl);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return sl;
|
||||
dsound_t *ds = (dsound_t*)data;
|
||||
return ds->fifo_bufsize;
|
||||
}
|
||||
|
||||
/* TODO/FIXME - implement? */
|
||||
static bool dsound_use_float(void *data) { return false; }
|
||||
|
||||
static void dsound_device_list_free(void *u, void *slp)
|
||||
{
|
||||
struct string_list *sl = (struct string_list*)slp;
|
||||
|
||||
+25
-28
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#ifdef GEKKO
|
||||
#include <gccore.h>
|
||||
@@ -31,6 +32,10 @@
|
||||
|
||||
#include "../audio_driver.h"
|
||||
|
||||
#define CHUNK_FRAMES 64
|
||||
#define CHUNK_SIZE (CHUNK_FRAMES * sizeof(uint32_t))
|
||||
#define BLOCKS 16
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t write_ptr;
|
||||
@@ -45,7 +50,7 @@ typedef struct
|
||||
static volatile gx_audio_t *gx_audio_data = NULL;
|
||||
static volatile bool stop_audio = false;
|
||||
|
||||
static void dma_callback(void)
|
||||
static void gx_audio_dma_callback(void)
|
||||
{
|
||||
gx_audio_t *wa = (gx_audio_t*)gx_audio_data;
|
||||
|
||||
@@ -68,7 +73,7 @@ static void *gx_audio_init(const char *device,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
gx_audio_t *wa = (gx_audio_t*)memalign(32, sizeof(*wa));
|
||||
gx_audio_t *wa = (gx_audio_t*)memalign(32, sizeof(*wa));
|
||||
if (!wa)
|
||||
return NULL;
|
||||
|
||||
@@ -77,9 +82,9 @@ static void *gx_audio_init(const char *device,
|
||||
memset(wa, 0, sizeof(*wa));
|
||||
|
||||
AIInit(NULL);
|
||||
AIRegisterDMACallback(dma_callback);
|
||||
AIRegisterDMACallback(gx_audio_dma_callback);
|
||||
|
||||
/* Ranges 0-32000 (default low) and 40000-47999
|
||||
/* Ranges 0-32000 (default low) and 40000-47999
|
||||
(in settings going down from 48000) -> set to 32000 hz */
|
||||
if (rate <= 32000 || (rate >= 40000 && rate < 48000))
|
||||
{
|
||||
@@ -102,19 +107,20 @@ static void *gx_audio_init(const char *device,
|
||||
}
|
||||
|
||||
/* Wii uses silly R, L, R, L interleaving. */
|
||||
static INLINE void copy_swapped(uint32_t * restrict dst,
|
||||
const uint32_t * restrict src, size_t size)
|
||||
static INLINE void gx_audio_copy_swapped(
|
||||
uint32_t *restrict dst,
|
||||
const uint32_t * restrict src, size_t len)
|
||||
{
|
||||
do
|
||||
{
|
||||
uint32_t s = *src++;
|
||||
*dst++ = (s >> 16) | (s << 16);
|
||||
} while (--size);
|
||||
} while (--len);
|
||||
}
|
||||
|
||||
static ssize_t gx_audio_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t gx_audio_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
size_t frames = size >> 2;
|
||||
size_t frames = len >> 2;
|
||||
const uint32_t *buf = buf_;
|
||||
gx_audio_t *wa = data;
|
||||
|
||||
@@ -127,14 +133,15 @@ static ssize_t gx_audio_write(void *data, const void *buf_, size_t size)
|
||||
|
||||
/* FIXME: Nonblocking audio should break out of loop
|
||||
* when it has nothing to write. */
|
||||
while ((wa->dma_write == wa->dma_next ||
|
||||
wa->dma_write == wa->dma_busy) && !wa->nonblock);
|
||||
while (( wa->dma_write == wa->dma_next
|
||||
|| wa->dma_write == wa->dma_busy) && !wa->nonblock);
|
||||
|
||||
copy_swapped(wa->data[wa->dma_write] + wa->write_ptr, buf, to_write);
|
||||
gx_audio_copy_swapped(wa->data[wa->dma_write] + wa->write_ptr,
|
||||
buf, to_write);
|
||||
|
||||
wa->write_ptr += to_write;
|
||||
frames -= to_write;
|
||||
buf += to_write;
|
||||
frames -= to_write;
|
||||
buf += to_write;
|
||||
|
||||
if (wa->write_ptr >= CHUNK_FRAMES)
|
||||
{
|
||||
@@ -142,8 +149,7 @@ static ssize_t gx_audio_write(void *data, const void *buf_, size_t size)
|
||||
wa->dma_write = (wa->dma_write + 1) & (BLOCKS - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return size;
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool gx_audio_stop(void *data)
|
||||
@@ -209,18 +215,9 @@ static size_t gx_audio_write_avail(void *data)
|
||||
& (BLOCKS - 1)) * CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static size_t gx_audio_buffer_size(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return BLOCKS * CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static bool gx_audio_use_float(void *data)
|
||||
{
|
||||
/* TODO/FIXME - verify */
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
static size_t gx_audio_buffer_size(void *data) { return BLOCKS * CHUNK_SIZE; }
|
||||
/* TODO/FIXME - implement/verify? */
|
||||
static bool gx_audio_use_float(void *data) { return false; }
|
||||
|
||||
audio_driver_t audio_gx = {
|
||||
gx_audio_init,
|
||||
|
||||
+42
-52
@@ -46,7 +46,7 @@ typedef struct jack
|
||||
bool is_paused;
|
||||
} jack_t;
|
||||
|
||||
static size_t read_deinterleaved(float *dst[2], jack_nframes_t dst_offset,
|
||||
static size_t ja_read_deinterleaved(float *dst[2], jack_nframes_t dst_offset,
|
||||
jack_ringbuffer_data_t buf, jack_nframes_t nframes)
|
||||
{
|
||||
int i;
|
||||
@@ -66,43 +66,37 @@ static size_t read_deinterleaved(float *dst[2], jack_nframes_t dst_offset,
|
||||
return nframes;
|
||||
}
|
||||
|
||||
static int process_cb(jack_nframes_t nframes, void *data)
|
||||
static int ja_process_cb(jack_nframes_t nframes, void *data)
|
||||
{
|
||||
int i;
|
||||
jack_nframes_t read = 0;
|
||||
jack_t *jd = (jack_t*)data;
|
||||
jack_ringbuffer_data_t buf[2];
|
||||
float *dst[2];
|
||||
|
||||
if (nframes <= 0)
|
||||
if (nframes > 0)
|
||||
{
|
||||
#ifdef HAVE_THREADS
|
||||
scond_signal(jd->cond);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
dst[i] = (float *)jack_port_get_buffer(jd->ports[i], nframes);
|
||||
|
||||
jack_ringbuffer_get_read_vector(jd->buffer, buf);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
read += read_deinterleaved(dst, read, buf[i], nframes - read);
|
||||
|
||||
jack_ringbuffer_read_advance(jd->buffer, read * sizeof(float) * 2);
|
||||
|
||||
for (; read < nframes; read++)
|
||||
int i;
|
||||
float *dst[2];
|
||||
jack_ringbuffer_data_t buf[2];
|
||||
jack_nframes_t read = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
dst[i][read] = 0.0f;
|
||||
dst[i] = (float *)jack_port_get_buffer(jd->ports[i], nframes);
|
||||
|
||||
jack_ringbuffer_get_read_vector(jd->buffer, buf);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
read += ja_read_deinterleaved(dst, read, buf[i], nframes - read);
|
||||
|
||||
jack_ringbuffer_read_advance(jd->buffer, read * sizeof(float) * 2);
|
||||
|
||||
for (; read < nframes; read++)
|
||||
for (i = 0; i < 2; i++)
|
||||
dst[i][read] = 0.0f;
|
||||
}
|
||||
#ifdef HAVE_THREADS
|
||||
scond_signal(jd->cond);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void shutdown_cb(void *data)
|
||||
static void ja_shutdown_cb(void *data)
|
||||
{
|
||||
jack_t *jd = (jack_t*)data;
|
||||
|
||||
@@ -115,7 +109,7 @@ static void shutdown_cb(void *data)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int parse_ports(char **dest_ports, const char **jports)
|
||||
static int ja_parse_ports(char **dest_ports, const char **jports)
|
||||
{
|
||||
int i;
|
||||
char *save = NULL;
|
||||
@@ -137,7 +131,7 @@ static int parse_ports(char **dest_ports, const char **jports)
|
||||
return 2;
|
||||
}
|
||||
|
||||
static size_t find_buffersize(jack_t *jd, int latency, unsigned out_rate)
|
||||
static size_t ja_find_buffersize(jack_t *jd, int latency, unsigned out_rate)
|
||||
{
|
||||
jack_latency_range_t range;
|
||||
int i, buffer_frames, min_buffer_frames;
|
||||
@@ -151,12 +145,12 @@ static size_t find_buffersize(jack_t *jd, int latency, unsigned out_rate)
|
||||
jack_latency = range.max;
|
||||
}
|
||||
|
||||
RARCH_LOG("[JACK]: Jack latency is %d frames.\n", jack_latency);
|
||||
RARCH_LOG("[JACK] Jack latency is %d frames.\n", jack_latency);
|
||||
|
||||
buffer_frames = frames - jack_latency;
|
||||
min_buffer_frames = jack_get_buffer_size(jd->client) * 2;
|
||||
|
||||
RARCH_LOG("[JACK]: Minimum buffer size is %d frames.\n", min_buffer_frames);
|
||||
RARCH_LOG("[JACK] Minimum buffer size is %d frames.\n", min_buffer_frames);
|
||||
|
||||
if (buffer_frames < min_buffer_frames)
|
||||
buffer_frames = min_buffer_frames;
|
||||
@@ -190,41 +184,41 @@ static void *ja_init(const char *device,
|
||||
|
||||
*new_rate = jack_get_sample_rate(jd->client);
|
||||
|
||||
jack_set_process_callback(jd->client, process_cb, jd);
|
||||
jack_on_shutdown(jd->client, shutdown_cb, jd);
|
||||
jack_set_process_callback(jd->client, ja_process_cb, jd);
|
||||
jack_on_shutdown(jd->client, ja_shutdown_cb, jd);
|
||||
|
||||
jd->ports[0] = jack_port_register(jd->client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
jd->ports[1] = jack_port_register(jd->client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
if (!jd->ports[0] || !jd->ports[1])
|
||||
{
|
||||
RARCH_ERR("[JACK]: Failed to register ports.\n");
|
||||
RARCH_ERR("[JACK] Failed to register ports.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
jports = jack_get_ports(jd->client, NULL, NULL, JackPortIsPhysical | JackPortIsInput);
|
||||
if (!jports)
|
||||
{
|
||||
RARCH_ERR("[JACK]: Failed to get ports.\n");
|
||||
RARCH_ERR("[JACK] Failed to get ports.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
bufsize = find_buffersize(jd, latency, *new_rate);
|
||||
bufsize = ja_find_buffersize(jd, latency, *new_rate);
|
||||
jd->buffer_size = bufsize;
|
||||
|
||||
RARCH_LOG("[JACK]: Internal buffer size: %d frames.\n", (int)(bufsize / sizeof(jack_default_audio_sample_t)));
|
||||
RARCH_LOG("[JACK] Internal buffer size: %d frames.\n", (int)(bufsize / sizeof(jack_default_audio_sample_t)));
|
||||
|
||||
jd->buffer = jack_ringbuffer_create(bufsize);
|
||||
if (!jd->buffer)
|
||||
{
|
||||
RARCH_ERR("[JACK]: Failed to create buffers.\n");
|
||||
RARCH_ERR("[JACK] Failed to create buffers.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
parsed = parse_ports(dest_ports, jports);
|
||||
parsed = ja_parse_ports(dest_ports, jports);
|
||||
|
||||
if (jack_activate(jd->client) < 0)
|
||||
{
|
||||
RARCH_ERR("[JACK]: Failed to activate Jack...\n");
|
||||
RARCH_ERR("[JACK] Failed to activate Jack.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -232,7 +226,7 @@ static void *ja_init(const char *device,
|
||||
{
|
||||
if (jack_connect(jd->client, jack_port_name(jd->ports[i]), dest_ports[i]))
|
||||
{
|
||||
RARCH_ERR("[JACK]: Failed to connect to Jack port.\n");
|
||||
RARCH_ERR("[JACK] Failed to connect to Jack port.\n");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
@@ -252,13 +246,13 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t ja_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t ja_write(void *data, const void *buf_, size_t len)
|
||||
{
|
||||
size_t _len = 0;
|
||||
jack_t *jd = (jack_t*)data;
|
||||
const char *buf = (const char *)buf_;
|
||||
size_t written = 0;
|
||||
|
||||
while (size > 0)
|
||||
while (len > 0)
|
||||
{
|
||||
size_t avail, to_write;
|
||||
|
||||
@@ -267,7 +261,7 @@ static ssize_t ja_write(void *data, const void *buf_, size_t size)
|
||||
|
||||
avail = jack_ringbuffer_write_space(jd->buffer);
|
||||
|
||||
to_write = size < avail ? size : avail;
|
||||
to_write = (len < avail) ? len : avail;
|
||||
/* make sure to only write multiples of the sample size */
|
||||
to_write = (to_write / sizeof(float)) * sizeof(float);
|
||||
|
||||
@@ -275,8 +269,8 @@ static ssize_t ja_write(void *data, const void *buf_, size_t size)
|
||||
{
|
||||
jack_ringbuffer_write(jd->buffer, buf, to_write);
|
||||
buf += to_write;
|
||||
size -= to_write;
|
||||
written += to_write;
|
||||
len -= to_write;
|
||||
_len += to_write;
|
||||
}
|
||||
else if (!jd->nonblock)
|
||||
{
|
||||
@@ -291,7 +285,7 @@ static ssize_t ja_write(void *data, const void *buf_, size_t size)
|
||||
break;
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool ja_stop(void *data)
|
||||
@@ -350,11 +344,7 @@ static void ja_free(void *data)
|
||||
free(jd);
|
||||
}
|
||||
|
||||
static bool ja_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
}
|
||||
static bool ja_use_float(void *data) { return true; }
|
||||
|
||||
static size_t ja_write_avail(void *data)
|
||||
{
|
||||
|
||||
+135
-60
@@ -32,6 +32,8 @@
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
#include <retro_timers.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
|
||||
#include "../audio_driver.h"
|
||||
#include "../../verbosity.h"
|
||||
@@ -47,10 +49,8 @@ typedef struct al
|
||||
ALCcontext *ctx;
|
||||
size_t res_ptr;
|
||||
ALsizei num_buffers;
|
||||
size_t tmpbuf_ptr;
|
||||
int rate;
|
||||
ALenum format;
|
||||
uint8_t tmpbuf[OPENAL_BUFSIZE];
|
||||
bool nonblock;
|
||||
bool is_paused;
|
||||
} al_t;
|
||||
@@ -79,19 +79,93 @@ static void al_free(void *data)
|
||||
free(al);
|
||||
}
|
||||
|
||||
static void *al_list_new(void *u)
|
||||
{
|
||||
union string_list_elem_attr attr;
|
||||
const char *audio_out_device_list;
|
||||
struct string_list *sl = string_list_new();
|
||||
|
||||
if (!sl)
|
||||
return NULL;
|
||||
|
||||
attr.i = 0;
|
||||
|
||||
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
|
||||
audio_out_device_list = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
else
|
||||
audio_out_device_list = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
|
||||
if (audio_out_device_list)
|
||||
{
|
||||
while (*audio_out_device_list)
|
||||
{
|
||||
string_list_append(sl, audio_out_device_list, attr);
|
||||
audio_out_device_list += strlen(audio_out_device_list) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return sl;
|
||||
}
|
||||
|
||||
|
||||
static void *al_init(const char *device, unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
al_t *al;
|
||||
|
||||
(void)device;
|
||||
|
||||
al = (al_t*)calloc(1, sizeof(al_t));
|
||||
size_t _latency;
|
||||
char *dev_id = NULL;
|
||||
al_t *al = (al_t*)calloc(1, sizeof(al_t));
|
||||
if (!al)
|
||||
return NULL;
|
||||
|
||||
al->handle = alcOpenDevice(NULL);
|
||||
if (device)
|
||||
{
|
||||
struct string_list *list = (struct string_list*)al_list_new(NULL);
|
||||
|
||||
/* Search for device name first */
|
||||
if (list && list->elems)
|
||||
{
|
||||
int32_t idx_found = -1;
|
||||
if (list->elems)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < list->size; i++)
|
||||
{
|
||||
if (string_is_equal(device, list->elems[i].data))
|
||||
{
|
||||
RARCH_DBG("[OpenAL] Found device #%d: \"%s\".\n", i, list->elems[i].data);
|
||||
idx_found = i;
|
||||
dev_id = strdup(list->elems[i].data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Index was not found yet based on name string,
|
||||
* just assume id is a one-character number index. */
|
||||
|
||||
if (idx_found == -1 && isdigit(device[0]))
|
||||
{
|
||||
idx_found = strtoul(device, NULL, 0);
|
||||
RARCH_LOG("[OpenAL] Fallback, device index is a single number index instead: %d.\n", idx_found);
|
||||
|
||||
if (idx_found != -1)
|
||||
{
|
||||
if (idx_found < (int32_t)list->size)
|
||||
{
|
||||
RARCH_LOG("[OpenAL] Corresponding name: %s.\n", list->elems[idx_found].data);
|
||||
dev_id = strdup(list->elems[idx_found].data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string_list_free(list);
|
||||
}
|
||||
|
||||
al->handle = alcOpenDevice(dev_id);
|
||||
if (dev_id)
|
||||
free(dev_id);
|
||||
dev_id = NULL;
|
||||
if (!al->handle)
|
||||
goto error;
|
||||
|
||||
@@ -101,14 +175,26 @@ static void *al_init(const char *device, unsigned rate, unsigned latency,
|
||||
|
||||
alcMakeContextCurrent(al->ctx);
|
||||
|
||||
al->rate = rate;
|
||||
al->rate = rate;
|
||||
*new_rate = rate;
|
||||
|
||||
/* We already use one buffer for tmpbuf. */
|
||||
al->num_buffers = (latency * rate * 2 * sizeof(int16_t)) / (1000 * OPENAL_BUFSIZE) - 1;
|
||||
if (alIsExtensionPresent("AL_EXT_FLOAT32"))
|
||||
{
|
||||
al->format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32");
|
||||
_latency = latency * rate * 2 * sizeof(float);
|
||||
RARCH_LOG("[OpenAL] Device supports float sample format\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
al->format = AL_FORMAT_STEREO16;
|
||||
_latency = latency * rate * 2 * sizeof(int16_t);
|
||||
}
|
||||
|
||||
al->num_buffers = _latency / (1000 * OPENAL_BUFSIZE);
|
||||
if (al->num_buffers < 2)
|
||||
al->num_buffers = 2;
|
||||
|
||||
RARCH_LOG("[OpenAL]: Using %u buffers of %u bytes.\n", (unsigned)al->num_buffers, OPENAL_BUFSIZE);
|
||||
RARCH_LOG("[OpenAL] Using %u buffers of %u bytes (%s format).\n", (unsigned)al->num_buffers, OPENAL_BUFSIZE, (al->format == AL_FORMAT_STEREO16) ? "integer" : "float");
|
||||
|
||||
al->buffers = (ALuint*)calloc(al->num_buffers, sizeof(ALuint));
|
||||
al->res_buf = (ALuint*)calloc(al->num_buffers, sizeof(ALuint));
|
||||
@@ -116,9 +202,11 @@ static void *al_init(const char *device, unsigned rate, unsigned latency,
|
||||
goto error;
|
||||
|
||||
alGenSources(1, &al->source);
|
||||
alSourcei(al->source, AL_LOOPING, AL_FALSE);
|
||||
alGenBuffers(al->num_buffers, al->buffers);
|
||||
|
||||
memcpy(al->res_buf, al->buffers, al->num_buffers * sizeof(ALuint));
|
||||
|
||||
al->res_ptr = al->num_buffers;
|
||||
|
||||
return al;
|
||||
@@ -144,70 +232,49 @@ static bool al_unqueue_buffers(al_t *al)
|
||||
|
||||
static bool al_get_buffer(al_t *al, ALuint *buffer)
|
||||
{
|
||||
if (!al->res_ptr)
|
||||
while (al->res_ptr == 0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (al_unqueue_buffers(al))
|
||||
break;
|
||||
if (al_unqueue_buffers(al))
|
||||
break;
|
||||
|
||||
if (al->nonblock)
|
||||
return false;
|
||||
if (al->nonblock)
|
||||
return false;
|
||||
|
||||
/* Must sleep as there is no proper blocking method. */
|
||||
retro_sleep(1);
|
||||
}
|
||||
/* Must sleep as there is no proper blocking method. */
|
||||
retro_sleep(1);
|
||||
}
|
||||
|
||||
*buffer = al->res_buf[--al->res_ptr];
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t al_fill_internal_buf(al_t *al, const void *buf, size_t size)
|
||||
{
|
||||
size_t read_size = MIN(OPENAL_BUFSIZE - al->tmpbuf_ptr, size);
|
||||
memcpy(al->tmpbuf + al->tmpbuf_ptr, buf, read_size);
|
||||
al->tmpbuf_ptr += read_size;
|
||||
return read_size;
|
||||
}
|
||||
|
||||
static ssize_t al_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t al_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
al_t *al = (al_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
size_t written = 0;
|
||||
const uint8_t *buf = (const uint8_t*)s;
|
||||
size_t _len = 0;
|
||||
|
||||
while (size)
|
||||
while (len)
|
||||
{
|
||||
ALint val;
|
||||
ALuint buffer;
|
||||
size_t rc = al_fill_internal_buf(al, buf, size);
|
||||
|
||||
written += rc;
|
||||
buf += rc;
|
||||
size -= rc;
|
||||
|
||||
if (al->tmpbuf_ptr != OPENAL_BUFSIZE)
|
||||
break;
|
||||
size_t rc = MIN(OPENAL_BUFSIZE, len);
|
||||
|
||||
if (!al_get_buffer(al, &buffer))
|
||||
break;
|
||||
|
||||
alBufferData(buffer, AL_FORMAT_STEREO16, al->tmpbuf, OPENAL_BUFSIZE, al->rate);
|
||||
al->tmpbuf_ptr = 0;
|
||||
alBufferData(buffer, al->format, buf, rc, al->rate);
|
||||
alSourceQueueBuffers(al->source, 1, &buffer);
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
return -1;
|
||||
|
||||
_len += rc;
|
||||
buf += rc;
|
||||
len -= rc;
|
||||
|
||||
alGetSourcei(al->source, AL_SOURCE_STATE, &val);
|
||||
if (val != AL_PLAYING)
|
||||
alSourcePlay(al->source);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool al_stop(void *data)
|
||||
@@ -221,9 +288,7 @@ static bool al_stop(void *data)
|
||||
static bool al_alive(void *data)
|
||||
{
|
||||
al_t *al = (al_t*)data;
|
||||
if (!al)
|
||||
return false;
|
||||
return !al->is_paused;
|
||||
return al && !al->is_paused;
|
||||
}
|
||||
|
||||
static void al_set_nonblock_state(void *data, bool state)
|
||||
@@ -245,19 +310,29 @@ static size_t al_write_avail(void *data)
|
||||
{
|
||||
al_t *al = (al_t*)data;
|
||||
al_unqueue_buffers(al);
|
||||
return al->res_ptr * OPENAL_BUFSIZE + (OPENAL_BUFSIZE - al->tmpbuf_ptr);
|
||||
return al->res_ptr * OPENAL_BUFSIZE;
|
||||
}
|
||||
|
||||
static size_t al_buffer_size(void *data)
|
||||
{
|
||||
al_t *al = (al_t*)data;
|
||||
return (al->num_buffers + 1) * OPENAL_BUFSIZE; /* Also got tmpbuf. */
|
||||
return (al->num_buffers) * OPENAL_BUFSIZE;
|
||||
}
|
||||
|
||||
static bool al_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
al_t *al = (al_t*)data;
|
||||
if (al->format == AL_FORMAT_STEREO16)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void al_device_list_free(void *u, void *slp)
|
||||
{
|
||||
struct string_list *sl = (struct string_list*)slp;
|
||||
|
||||
if (sl)
|
||||
string_list_free(sl);
|
||||
}
|
||||
|
||||
audio_driver_t audio_openal = {
|
||||
@@ -270,8 +345,8 @@ audio_driver_t audio_openal = {
|
||||
al_free,
|
||||
al_use_float,
|
||||
"openal",
|
||||
NULL,
|
||||
NULL,
|
||||
al_list_new,
|
||||
al_device_list_free,
|
||||
al_write_avail,
|
||||
al_buffer_size,
|
||||
};
|
||||
+15
-19
@@ -116,7 +116,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency,
|
||||
if (!sl)
|
||||
goto error;
|
||||
|
||||
RARCH_LOG("[OpenSL]: Requested audio latency: %u ms.\n", latency);
|
||||
RARCH_LOG("[OpenSL] Requested audio latency: %u ms.\n", latency);
|
||||
|
||||
GOTO_IF_FAIL(slCreateEngine(&sl->engine_object, 0, NULL, 0, NULL, NULL));
|
||||
GOTO_IF_FAIL(SLObjectItf_Realize(sl->engine_object, SL_BOOLEAN_FALSE));
|
||||
@@ -147,7 +147,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency,
|
||||
for (i = 0; i < sl->buf_count; i++)
|
||||
sl->buffer[i] = sl->buffer_chunk + i * sl->buf_size;
|
||||
|
||||
RARCH_LOG("[OpenSL]: Setting audio latency: Block size = %u, Blocks = %u, Total = %u ...\n",
|
||||
RARCH_LOG("[OpenSL] Setting audio latency: Block size = %u, Blocks = %u, Total = %u...\n",
|
||||
sl->buf_size, sl->buf_count, sl->buf_size * sl->buf_count);
|
||||
|
||||
fmt_pcm.formatType = SL_DATAFORMAT_PCM;
|
||||
@@ -195,7 +195,7 @@ static void *sl_init(const char *device, unsigned rate, unsigned latency,
|
||||
return sl;
|
||||
|
||||
error:
|
||||
RARCH_ERR("[OpenSL]: Couldn't initialize OpenSL ES driver, error code: [%d].\n", (int)res);
|
||||
RARCH_ERR("[OpenSL] Couldn't initialize OpenSL ES driver. Error code: %d.\n", (int)res);
|
||||
sl_free(sl);
|
||||
return NULL;
|
||||
}
|
||||
@@ -232,13 +232,13 @@ static bool sl_start(void *data, bool is_shutdown)
|
||||
return sl->is_paused ? false : true;
|
||||
}
|
||||
|
||||
static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||
static ssize_t sl_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
size_t _len = 0;
|
||||
sl_t *sl = (sl_t*)data;
|
||||
size_t written = 0;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
const uint8_t *buf = (const uint8_t*)s;
|
||||
|
||||
while (size)
|
||||
while (len)
|
||||
{
|
||||
size_t avail_write;
|
||||
|
||||
@@ -255,15 +255,15 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||
slock_unlock(sl->lock);
|
||||
}
|
||||
|
||||
avail_write = MIN(sl->buf_size - sl->buffer_ptr, size);
|
||||
avail_write = MIN(sl->buf_size - sl->buffer_ptr, len);
|
||||
|
||||
if (avail_write)
|
||||
{
|
||||
memcpy(sl->buffer[sl->buffer_index] + sl->buffer_ptr, buf, avail_write);
|
||||
sl->buffer_ptr += avail_write;
|
||||
buf += avail_write;
|
||||
size -= avail_write;
|
||||
written += avail_write;
|
||||
len -= avail_write;
|
||||
_len += avail_write;
|
||||
}
|
||||
|
||||
if (sl->buffer_ptr >= sl->buf_size)
|
||||
@@ -275,20 +275,19 @@ static ssize_t sl_write(void *data, const void *buf_, size_t size)
|
||||
|
||||
if (res != SL_RESULT_SUCCESS)
|
||||
{
|
||||
RARCH_ERR("[OpenSL]: Failed to write! (Error: 0x%x)\n", (unsigned)res);
|
||||
RARCH_ERR("[OpenSL] Failed to write. Error: 0x%x.\n", (unsigned)res);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static size_t sl_write_avail(void *data)
|
||||
{
|
||||
sl_t *sl = (sl_t*)data;
|
||||
size_t avail = (sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr);
|
||||
return avail;
|
||||
return ((sl->buf_count - (int)sl->buffered_blocks - 1) * sl->buf_size + (sl->buf_size - (int)sl->buffer_ptr));
|
||||
}
|
||||
|
||||
static size_t sl_buffer_size(void *data)
|
||||
@@ -297,11 +296,8 @@ static size_t sl_buffer_size(void *data)
|
||||
return sl->buf_size * sl->buf_count;
|
||||
}
|
||||
|
||||
static bool sl_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
/* TODO/FIXME - implement */
|
||||
static bool sl_use_float(void *data) { return false; }
|
||||
|
||||
audio_driver_t audio_opensl = {
|
||||
sl_init,
|
||||
|
||||
+11
-16
@@ -71,7 +71,7 @@ static void *oss_init(const char *device,
|
||||
frag = (frags << 16) | 10;
|
||||
|
||||
if (ioctl(ossaudio->fd, SNDCTL_DSP_SETFRAGMENT, &frag) < 0)
|
||||
RARCH_WARN("Cannot set fragment sizes. Latency might not be as expected ...\n");
|
||||
RARCH_WARN("[OSS] Could not set fragment sizes. Latency might not be as expected.\n");
|
||||
|
||||
channels = 2;
|
||||
format = is_little_endian() ? AFMT_S16_LE : AFMT_S16_BE;
|
||||
@@ -89,7 +89,7 @@ static void *oss_init(const char *device,
|
||||
|
||||
if (new_rate != (int)rate)
|
||||
{
|
||||
RARCH_WARN("Requested sample rate not supported. Adjusting output rate to %d Hz.\n", new_rate);
|
||||
RARCH_WARN("[OSS] Requested sample rate not supported. Adjusting output rate to %d Hz.\n", new_rate);
|
||||
*new_out_rate = new_rate;
|
||||
}
|
||||
|
||||
@@ -103,23 +103,19 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t oss_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t oss_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ssize_t ret;
|
||||
ssize_t _len;
|
||||
oss_audio_t *ossaudio = (oss_audio_t*)data;
|
||||
|
||||
if (size == 0)
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if ((ret = write(ossaudio->fd, buf, size)) < 0)
|
||||
if ((_len = write(ossaudio->fd, s, len)) < 0)
|
||||
{
|
||||
if (errno == EAGAIN && (fcntl(ossaudio->fd, F_GETFL) & O_NONBLOCK))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool oss_stop(void *data)
|
||||
@@ -162,14 +158,14 @@ static void oss_set_nonblock_state(void *data, bool state)
|
||||
rc = fcntl(ossaudio->fd, F_SETFL,
|
||||
fcntl(ossaudio->fd, F_GETFL) & (~O_NONBLOCK));
|
||||
if (rc != 0)
|
||||
RARCH_WARN("Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n");
|
||||
RARCH_WARN("[OSS] Could not set nonblocking on OSS file descriptor. Will not be able to fast-forward.\n");
|
||||
}
|
||||
|
||||
static void oss_free(void *data)
|
||||
{
|
||||
oss_audio_t *ossaudio = (oss_audio_t*)data;
|
||||
|
||||
/*RETROFW IOCTL always returns EINVAL*/
|
||||
/*RETROFW IOCTL always returns EINVAL*/
|
||||
#if !defined(RETROFW)
|
||||
if (ioctl(ossaudio->fd, SNDCTL_DSP_RESET, 0) < 0)
|
||||
return;
|
||||
@@ -186,7 +182,7 @@ static size_t oss_write_avail(void *data)
|
||||
|
||||
if (ioctl(ossaudio->fd, SNDCTL_DSP_GETOSPACE, &info) < 0)
|
||||
{
|
||||
RARCH_ERR("[OSS]: SNDCTL_DSP_GETOSPACE failed ...\n");
|
||||
RARCH_ERR("[OSS] SNDCTL_DSP_GETOSPACE failed.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -200,7 +196,7 @@ static size_t oss_buffer_size(void *data)
|
||||
|
||||
if (ioctl(ossaudio->fd, SNDCTL_DSP_GETOSPACE, &info) < 0)
|
||||
{
|
||||
RARCH_ERR("[OSS]: SNDCTL_DSP_GETOSPACE failed ...\n");
|
||||
RARCH_ERR("[OSS] SNDCTL_DSP_GETOSPACE failed.\n");
|
||||
return 1; /* Return something non-zero to avoid SIGFPE. */
|
||||
}
|
||||
|
||||
@@ -209,7 +205,6 @@ static size_t oss_buffer_size(void *data)
|
||||
|
||||
static bool oss_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+637
-252
File diff suppressed because it is too large.
Load diff
+16
-40
@@ -33,9 +33,16 @@ typedef struct ps2_audio
|
||||
bool running;
|
||||
} ps2_audio_t;
|
||||
|
||||
static void audioConfigure(ps2_audio_t *ps2, unsigned rate)
|
||||
static void *ps2_audio_init(const char *device,
|
||||
unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
struct audsrv_fmt_t format;
|
||||
ps2_audio_t *ps2 = (ps2_audio_t*)calloc(1, sizeof(ps2_audio_t));
|
||||
|
||||
if (!ps2)
|
||||
return NULL;
|
||||
|
||||
format.bits = AUDIO_BITS;
|
||||
format.freq = rate;
|
||||
@@ -43,19 +50,6 @@ static void audioConfigure(ps2_audio_t *ps2, unsigned rate)
|
||||
|
||||
audsrv_set_format(&format);
|
||||
audsrv_set_volume(MAX_VOLUME);
|
||||
}
|
||||
|
||||
static void *ps2_audio_init(const char *device,
|
||||
unsigned rate, unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
ps2_audio_t *ps2 = (ps2_audio_t*)calloc(1, sizeof(ps2_audio_t));
|
||||
|
||||
if (!ps2)
|
||||
return NULL;
|
||||
|
||||
audioConfigure(ps2, rate);
|
||||
|
||||
return ps2;
|
||||
}
|
||||
@@ -71,50 +65,39 @@ static void ps2_audio_free(void *data)
|
||||
free(ps2);
|
||||
}
|
||||
|
||||
static ssize_t ps2_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ps2_audio_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||
|
||||
if (!ps2->running)
|
||||
return -1;
|
||||
|
||||
return audsrv_play_audio(buf, size);
|
||||
return audsrv_play_audio(s, len);
|
||||
}
|
||||
|
||||
static bool ps2_audio_alive(void *data)
|
||||
{
|
||||
bool alive = false;
|
||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||
|
||||
if (ps2)
|
||||
alive = ps2->running;
|
||||
|
||||
return alive;
|
||||
return ps2->running;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ps2_audio_stop(void *data)
|
||||
{
|
||||
bool stop = true;
|
||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||
|
||||
if (ps2)
|
||||
{
|
||||
audsrv_stop_audio();
|
||||
ps2->running = false;
|
||||
}
|
||||
|
||||
return stop;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ps2_audio_start(void *data, bool is_shutdown)
|
||||
{
|
||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||
bool start = true;
|
||||
|
||||
if (ps2)
|
||||
ps2->running = true;
|
||||
|
||||
return start;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void ps2_audio_set_nonblock_state(void *data, bool toggle)
|
||||
@@ -125,11 +108,6 @@ static void ps2_audio_set_nonblock_state(void *data, bool toggle)
|
||||
ps2->nonblock = toggle;
|
||||
}
|
||||
|
||||
static bool ps2_audio_use_float(void *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t ps2_audio_write_avail(void *data)
|
||||
{
|
||||
ps2_audio_t* ps2 = (ps2_audio_t*)data;
|
||||
@@ -140,10 +118,8 @@ static size_t ps2_audio_write_avail(void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t ps2_audio_buffer_size(void *data)
|
||||
{
|
||||
return AUDIO_BUFFER;
|
||||
}
|
||||
static bool ps2_audio_use_float(void *data) { return false; }
|
||||
static size_t ps2_audio_buffer_size(void *data) { return AUDIO_BUFFER; }
|
||||
|
||||
audio_driver_t audio_ps2 = {
|
||||
ps2_audio_init,
|
||||
|
||||
@@ -41,9 +41,9 @@ typedef struct
|
||||
|
||||
|
||||
#ifdef __PSL1GHT__
|
||||
static void event_loop(void *data)
|
||||
static void ps3_event_loop(void *data)
|
||||
#else
|
||||
static void event_loop(uint64_t data)
|
||||
static void ps3_event_loop(uint64_t data)
|
||||
#endif
|
||||
{
|
||||
float out_tmp[AUDIO_BLOCK_SAMPLES * AUDIO_CHANNELS]
|
||||
@@ -131,7 +131,7 @@ static void *ps3_audio_init(const char *device,
|
||||
|
||||
audioPortStart(data->audio_port);
|
||||
data->started = true;
|
||||
sysThreadCreate(&data->thread, event_loop,
|
||||
sysThreadCreate(&data->thread, ps3_event_loop,
|
||||
#ifdef __PSL1GHT__
|
||||
data,
|
||||
#else
|
||||
@@ -142,24 +142,23 @@ static void *ps3_audio_init(const char *device,
|
||||
return data;
|
||||
}
|
||||
|
||||
static ssize_t ps3_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ps3_audio_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
ps3_audio_t *aud = data;
|
||||
|
||||
if (aud->nonblock)
|
||||
{
|
||||
if (FIFO_WRITE_AVAIL(aud->buffer) < size)
|
||||
if (FIFO_WRITE_AVAIL(aud->buffer) < len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (FIFO_WRITE_AVAIL(aud->buffer) < size)
|
||||
while (FIFO_WRITE_AVAIL(aud->buffer) < len)
|
||||
sysLwCondWait(&aud->cond, 0);
|
||||
|
||||
sysLwMutexLock(&aud->lock, PS3_SYS_NO_TIMEOUT);
|
||||
fifo_write(aud->buffer, buf, size);
|
||||
fifo_write(aud->buffer, s, len);
|
||||
sysLwMutexUnlock(&aud->lock);
|
||||
|
||||
return size;
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool ps3_audio_stop(void *data)
|
||||
@@ -220,10 +219,7 @@ static void ps3_audio_free(void *data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static bool ps3_audio_use_float(void *data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
static bool ps3_audio_use_float(void *data) { return true; }
|
||||
|
||||
static size_t ps3_audio_write_avail(void *data)
|
||||
{
|
||||
|
||||
+33
-35
@@ -68,7 +68,7 @@ typedef struct psp_audio
|
||||
#define AUDIO_BUFFER_SIZE_MASK (AUDIO_BUFFER_SIZE-1)
|
||||
|
||||
/* Return port used */
|
||||
static int configureAudio(unsigned rate)
|
||||
static int psp_configure_audio(unsigned rate)
|
||||
{
|
||||
#if defined(VITA)
|
||||
return sceAudioOutOpenPort(
|
||||
@@ -83,7 +83,7 @@ static int configureAudio(unsigned rate)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void audioMainLoop(void *data)
|
||||
static void psp_audio_mainloop(void *data)
|
||||
{
|
||||
psp_audio_t* psp = (psp_audio_t*)data;
|
||||
|
||||
@@ -115,7 +115,9 @@ static void audioMainLoop(void *data)
|
||||
cond ? (psp->zeroBuffer)
|
||||
: (psp->buffer + read_pos_2));
|
||||
#else
|
||||
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, cond ? (psp->zeroBuffer)
|
||||
sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX,
|
||||
cond
|
||||
? (psp->zeroBuffer)
|
||||
: (psp->buffer + read_pos));
|
||||
#endif
|
||||
}
|
||||
@@ -134,7 +136,7 @@ static void *psp_audio_init(const char *device,
|
||||
if (!psp)
|
||||
return NULL;
|
||||
|
||||
if ((port = configureAudio(rate)) < 0)
|
||||
if ((port = psp_configure_audio(rate)) < 0)
|
||||
{
|
||||
free(psp);
|
||||
return NULL;
|
||||
@@ -160,7 +162,7 @@ static void *psp_audio_init(const char *device,
|
||||
|
||||
psp->nonblock = false;
|
||||
psp->running = true;
|
||||
psp->worker_thread = sthread_create(audioMainLoop, psp);
|
||||
psp->worker_thread = sthread_create(psp_audio_mainloop, psp);
|
||||
|
||||
return psp;
|
||||
}
|
||||
@@ -202,11 +204,11 @@ static void psp_audio_free(void *data)
|
||||
|
||||
}
|
||||
|
||||
static ssize_t psp_audio_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t psp_audio_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
psp_audio_t* psp = (psp_audio_t*)data;
|
||||
uint16_t write_pos = psp->write_pos;
|
||||
uint16_t sampleCount = size / sizeof(uint32_t);
|
||||
psp_audio_t* psp = (psp_audio_t*)data;
|
||||
uint16_t write_pos = psp->write_pos;
|
||||
uint16_t sample_count = len / sizeof(uint32_t);
|
||||
|
||||
if (!psp->running)
|
||||
return -1;
|
||||
@@ -214,35 +216,34 @@ static ssize_t psp_audio_write(void *data, const void *buf, size_t size)
|
||||
if (psp->nonblock)
|
||||
{
|
||||
if (AUDIO_BUFFER_SIZE - ((uint16_t)
|
||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size)
|
||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
slock_lock(psp->cond_lock);
|
||||
while (AUDIO_BUFFER_SIZE - ((uint16_t)
|
||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < size)
|
||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK) < len)
|
||||
scond_wait(psp->cond, psp->cond_lock);
|
||||
slock_unlock(psp->cond_lock);
|
||||
|
||||
slock_lock(psp->fifo_lock);
|
||||
if ((write_pos + sampleCount) > AUDIO_BUFFER_SIZE)
|
||||
if ((write_pos + sample_count) > AUDIO_BUFFER_SIZE)
|
||||
{
|
||||
memcpy(psp->buffer + write_pos, buf,
|
||||
memcpy(psp->buffer + write_pos, s,
|
||||
(AUDIO_BUFFER_SIZE - write_pos) * sizeof(uint32_t));
|
||||
memcpy(psp->buffer, (uint32_t*) buf +
|
||||
memcpy(psp->buffer, (uint32_t*)s +
|
||||
(AUDIO_BUFFER_SIZE - write_pos),
|
||||
(write_pos + sampleCount - AUDIO_BUFFER_SIZE) * sizeof(uint32_t));
|
||||
(write_pos + sample_count - AUDIO_BUFFER_SIZE) * sizeof(uint32_t));
|
||||
}
|
||||
else
|
||||
memcpy(psp->buffer + write_pos, buf, size);
|
||||
memcpy(psp->buffer + write_pos, s, len);
|
||||
|
||||
write_pos += sampleCount;
|
||||
write_pos += sample_count;
|
||||
write_pos &= AUDIO_BUFFER_SIZE_MASK;
|
||||
psp->write_pos = write_pos;
|
||||
|
||||
slock_unlock(psp->fifo_lock);
|
||||
return size;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool psp_audio_alive(void *data)
|
||||
@@ -260,14 +261,15 @@ static bool psp_audio_stop(void *data)
|
||||
#if defined(ORBIS)
|
||||
return false;
|
||||
#else
|
||||
if (psp){
|
||||
if (psp)
|
||||
{
|
||||
psp->running = false;
|
||||
|
||||
if (!psp->worker_thread)
|
||||
return true;
|
||||
|
||||
sthread_join(psp->worker_thread);
|
||||
psp->worker_thread = NULL;
|
||||
if (psp->worker_thread)
|
||||
{
|
||||
sthread_join(psp->worker_thread);
|
||||
psp->worker_thread = NULL;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
@@ -282,7 +284,7 @@ static bool psp_audio_start(void *data, bool is_shutdown)
|
||||
if (!psp->worker_thread)
|
||||
{
|
||||
psp->running = true;
|
||||
psp->worker_thread = sthread_create(audioMainLoop, psp);
|
||||
psp->worker_thread = sthread_create(psp_audio_mainloop, psp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,28 +298,24 @@ static void psp_audio_set_nonblock_state(void *data, bool toggle)
|
||||
psp->nonblock = toggle;
|
||||
}
|
||||
|
||||
static bool psp_audio_use_float(void *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t psp_write_avail(void *data)
|
||||
{
|
||||
size_t val;
|
||||
size_t _len;
|
||||
psp_audio_t* psp = (psp_audio_t*)data;
|
||||
|
||||
if (!psp||!psp->running)
|
||||
return 0;
|
||||
slock_lock(psp->fifo_lock);
|
||||
val = AUDIO_BUFFER_SIZE - ((uint16_t)
|
||||
_len = AUDIO_BUFFER_SIZE - ((uint16_t)
|
||||
(psp->write_pos - psp->read_pos) & AUDIO_BUFFER_SIZE_MASK);
|
||||
slock_unlock(psp->fifo_lock);
|
||||
return val;
|
||||
return _len;
|
||||
}
|
||||
|
||||
/* TODO/FIXME - implement? */
|
||||
static bool psp_audio_use_float(void *data) { return false; }
|
||||
static size_t psp_buffer_size(void *data)
|
||||
{
|
||||
/* TODO/FIXME - implement? */
|
||||
return AUDIO_BUFFER_SIZE /** sizeof(uint32_t)*/;
|
||||
}
|
||||
|
||||
|
||||
+57
-63
@@ -72,7 +72,7 @@ static void pulse_free(void *data)
|
||||
free(pa);
|
||||
}
|
||||
|
||||
static void stream_success_cb(pa_stream *s, int success, void *data)
|
||||
static void pulse_stream_success_cb(pa_stream *s, int success, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
(void)s;
|
||||
@@ -80,7 +80,7 @@ static void stream_success_cb(pa_stream *s, int success, void *data)
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
}
|
||||
|
||||
static void context_state_cb(pa_context *c, void *data)
|
||||
static void pulse_context_state_cb(pa_context *c, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
@@ -90,7 +90,7 @@ static void context_state_cb(pa_context *c, void *data)
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
RARCH_ERR("[PulseAudio]: Connection failed\n");
|
||||
RARCH_ERR("[PulseAudio] Connection failed.\n");
|
||||
pa->is_ready = false;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
@@ -117,11 +117,11 @@ static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *
|
||||
if (eol > 0)
|
||||
return;
|
||||
|
||||
RARCH_DBG("[PulseAudio]: Sink detected: %s\n",l->name);
|
||||
RARCH_DBG("[PulseAudio] Sink detected: %s.\n", l->name);
|
||||
string_list_append(pa->devicelist, l->name, attr);
|
||||
}
|
||||
|
||||
static void stream_state_cb(pa_stream *s, void *data)
|
||||
static void pulse_stream_state_cb(pa_stream *s, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
@@ -142,32 +142,32 @@ static void stream_state_cb(pa_stream *s, void *data)
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_request_cb(pa_stream *s, size_t length, void *data)
|
||||
static void pulse_stream_request_cb(pa_stream *s, size_t len, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
}
|
||||
|
||||
static void stream_latency_update_cb(pa_stream *s, void *data)
|
||||
static void pulse_stream_latency_update_cb(pa_stream *s, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
}
|
||||
|
||||
static void underrun_update_cb(pa_stream *s, void *data)
|
||||
static void pulse_underrun_update_cb(pa_stream *s, void *data)
|
||||
{
|
||||
#if 0
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
(void)s;
|
||||
|
||||
RARCH_LOG("[PulseAudio]: Underrun (Buffer: %u, Writable size: %u).\n",
|
||||
RARCH_LOG("[PulseAudio] Underrun (Buffer: %u, Writable size: %u).\n",
|
||||
(unsigned)pa->buffer_size,
|
||||
(unsigned)pa_stream_writable_size(pa->stream));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void buffer_attr_cb(pa_stream *s, void *data)
|
||||
static void pulse_buffer_attr_cb(pa_stream *s, void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
const pa_buffer_attr *server_attr = pa_stream_get_buffer_attr(s);
|
||||
@@ -175,24 +175,23 @@ static void buffer_attr_cb(pa_stream *s, void *data)
|
||||
pa->buffer_size = server_attr->tlength;
|
||||
|
||||
#if 0
|
||||
RARCH_LOG("[PulseAudio]: Got new buffer size %u.\n", (unsigned)pa->buffer_size);
|
||||
RARCH_LOG("[PulseAudio] Got new buffer size %u.\n", (unsigned)pa->buffer_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void *pulse_init(const char *device, unsigned rate,
|
||||
unsigned latency,
|
||||
unsigned block_frames,
|
||||
unsigned latency, unsigned block_frames,
|
||||
unsigned *new_rate)
|
||||
{
|
||||
pa_sample_spec spec;
|
||||
pa_sample_spec spec;
|
||||
pa_buffer_attr buffer_attr = {0};
|
||||
const pa_buffer_attr *server_attr = NULL;
|
||||
pa_t *pa = (pa_t*)calloc(1, sizeof(*pa));
|
||||
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
|
||||
if (!pa)
|
||||
goto error;
|
||||
return NULL;
|
||||
|
||||
memset(&spec, 0, sizeof(spec));
|
||||
|
||||
pa->devicelist = string_list_new();
|
||||
|
||||
@@ -204,7 +203,7 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
if (!pa->context)
|
||||
goto error;
|
||||
|
||||
pa_context_set_state_callback(pa->context, context_state_cb, pa);
|
||||
pa_context_set_state_callback(pa->context, pulse_context_state_cb, pa);
|
||||
|
||||
/* Code is not prepared to use multiple PulseAudio servers, device is used as sink. */
|
||||
if (pa_context_connect(pa->context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0)
|
||||
@@ -232,11 +231,12 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
if (!pa->stream)
|
||||
goto unlock_error;
|
||||
|
||||
pa_stream_set_state_callback(pa->stream, stream_state_cb, pa);
|
||||
pa_stream_set_write_callback(pa->stream, stream_request_cb, pa);
|
||||
pa_stream_set_latency_update_callback(pa->stream, stream_latency_update_cb, pa);
|
||||
pa_stream_set_underflow_callback(pa->stream, underrun_update_cb, pa);
|
||||
pa_stream_set_buffer_attr_callback(pa->stream, buffer_attr_cb, pa);
|
||||
pa_stream_set_state_callback(pa->stream, pulse_stream_state_cb, pa);
|
||||
pa_stream_set_write_callback(pa->stream, pulse_stream_request_cb, pa);
|
||||
pa_stream_set_latency_update_callback(pa->stream,
|
||||
pulse_stream_latency_update_cb, pa);
|
||||
pa_stream_set_underflow_callback(pa->stream, pulse_underrun_update_cb, pa);
|
||||
pa_stream_set_buffer_attr_callback(pa->stream, pulse_buffer_attr_cb, pa);
|
||||
|
||||
buffer_attr.maxlength = -1;
|
||||
buffer_attr.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &spec);
|
||||
@@ -257,7 +257,7 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
if (server_attr)
|
||||
{
|
||||
pa->buffer_size = server_attr->tlength;
|
||||
RARCH_LOG("[PulseAudio]: Requested %u bytes buffer, got %u.\n",
|
||||
RARCH_LOG("[PulseAudio] Requested %u bytes buffer, got %u.\n",
|
||||
(unsigned)buffer_attr.tlength,
|
||||
(unsigned)pa->buffer_size);
|
||||
}
|
||||
@@ -276,33 +276,51 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool pulse_start(void *data, bool is_shutdown);
|
||||
static ssize_t pulse_write(void *data, const void *buf_, size_t size)
|
||||
static bool pulse_start(void *data, bool is_shutdown)
|
||||
{
|
||||
bool ret;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return false;
|
||||
if (!pa->is_paused)
|
||||
return true;
|
||||
|
||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_cork(pa->stream, false, pulse_stream_success_cb, pa);
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
ret = pa->success;
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
pa->is_paused = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t pulse_write(void *data, const void *s, size_t len)
|
||||
{
|
||||
size_t _len = 0;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
const uint8_t *buf = (const uint8_t*)buf_;
|
||||
size_t written = 0;
|
||||
const uint8_t *buf = (const uint8_t*)s;
|
||||
|
||||
/* Workaround buggy menu code.
|
||||
* If a write happens while we're paused, we might never progress. */
|
||||
if (pa->is_paused)
|
||||
if (!pulse_start(pa, false))
|
||||
return -1;
|
||||
if (pa->is_paused && !pulse_start(pa, false))
|
||||
return -1;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return 0;
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
while (size)
|
||||
while (len)
|
||||
{
|
||||
size_t writable = MIN(size, pa_stream_writable_size(pa->stream));
|
||||
size_t writable = MIN(len, pa_stream_writable_size(pa->stream));
|
||||
|
||||
if (writable)
|
||||
{
|
||||
pa_stream_write(pa->stream, buf, writable, NULL, 0, PA_SEEK_RELATIVE);
|
||||
buf += writable;
|
||||
size -= writable;
|
||||
written += writable;
|
||||
buf += writable;
|
||||
len -= writable;
|
||||
_len += writable;
|
||||
}
|
||||
else if (!pa->nonblock)
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
@@ -312,7 +330,7 @@ static ssize_t pulse_write(void *data, const void *buf_, size_t size)
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool pulse_stop(void *data)
|
||||
@@ -327,7 +345,7 @@ static bool pulse_stop(void *data)
|
||||
|
||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_cork(pa->stream, true, stream_success_cb, pa);
|
||||
pa_stream_cork(pa->stream, true, pulse_stream_success_cb, pa);
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
ret = pa->success;
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
@@ -344,26 +362,6 @@ static bool pulse_alive(void *data)
|
||||
return !pa->is_paused;
|
||||
}
|
||||
|
||||
static bool pulse_start(void *data, bool is_shutdown)
|
||||
{
|
||||
bool ret;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return false;
|
||||
if (!pa->is_paused)
|
||||
return true;
|
||||
|
||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_cork(pa->stream, false, stream_success_cb, pa);
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
ret = pa->success;
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
pa->is_paused = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void pulse_set_nonblock_state(void *data, bool state)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
@@ -371,11 +369,7 @@ static void pulse_set_nonblock_state(void *data, bool state)
|
||||
pa->nonblock = state;
|
||||
}
|
||||
|
||||
static bool pulse_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return true;
|
||||
}
|
||||
static bool pulse_use_float(void *data) { return true; }
|
||||
|
||||
static size_t pulse_write_avail(void *data)
|
||||
{
|
||||
|
||||
+14
-21
@@ -45,7 +45,7 @@ static void *ra_init(const char *device, unsigned rate, unsigned latency,
|
||||
|
||||
if (!(vss = roar_vs_new_simple(device, "RetroArch", rate, 2, ROAR_CODEC_PCM_S, 16, ROAR_DIR_PLAY, &err)))
|
||||
{
|
||||
RARCH_ERR("RoarAudio: \"%s\"\n", roar_vs_strerr(err));
|
||||
RARCH_ERR("[RoarAudio] \"%s\".\n", roar_vs_strerr(err));
|
||||
free(roar);
|
||||
return NULL;
|
||||
}
|
||||
@@ -56,32 +56,32 @@ static void *ra_init(const char *device, unsigned rate, unsigned latency,
|
||||
return roar;
|
||||
}
|
||||
|
||||
static ssize_t ra_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t ra_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
int err;
|
||||
size_t written = 0;
|
||||
roar_t *roar = (roar_t*)data;
|
||||
size_t _len = 0;
|
||||
roar_t *roar = (roar_t*)data;
|
||||
|
||||
if (size == 0)
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
while (written < size)
|
||||
while (_len < len)
|
||||
{
|
||||
ssize_t rc;
|
||||
size_t write_amt = size - written;
|
||||
size_t write_amt = len - _len;
|
||||
|
||||
if ((rc = roar_vs_write(roar->vss,
|
||||
(const char*)buf + written, write_amt, &err)) < (ssize_t)write_amt)
|
||||
(const char*)buf + _len, write_amt, &err)) < (ssize_t)write_amt)
|
||||
{
|
||||
if (roar->nonblocking)
|
||||
return rc;
|
||||
else if (rc < 0)
|
||||
return -1;
|
||||
}
|
||||
written += rc;
|
||||
_len += rc;
|
||||
}
|
||||
|
||||
return size;
|
||||
return _len;
|
||||
}
|
||||
|
||||
static bool ra_stop(void *data)
|
||||
@@ -106,7 +106,7 @@ static void ra_set_nonblock_state(void *data, bool state)
|
||||
|
||||
if (roar_vs_blocking(roar->vss, (state) ? ROAR_VS_FALSE : ROAR_VS_TRUE, NULL) < 0)
|
||||
{
|
||||
RARCH_ERR("Can't set nonblocking. Will not be able to fast-forward.\n");
|
||||
RARCH_ERR("[RoarAudio] Can't set nonblocking. Will not be able to fast-forward.\n");
|
||||
}
|
||||
roar->nonblocking = state;
|
||||
}
|
||||
@@ -126,16 +126,9 @@ static void ra_free(void *data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static bool ra_use_float(void *data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static size_t ra_write_avail(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return 0;
|
||||
}
|
||||
/* TODO/FIXME - implement? */
|
||||
static bool ra_use_float(void *data) { return false; }
|
||||
static size_t ra_write_avail(void *data) { return 0; }
|
||||
|
||||
audio_driver_t audio_roar = {
|
||||
ra_init,
|
||||
|
||||
+17
-25
@@ -48,7 +48,7 @@ static ssize_t rsound_audio_cb(void *data, size_t bytes, void *userdata)
|
||||
return write_size;
|
||||
}
|
||||
|
||||
static void err_cb(void *userdata)
|
||||
static void rsound_err_cb(void *userdata)
|
||||
{
|
||||
rsd_t *rsd = (rsd_t*)userdata;
|
||||
rsd->has_error = true;
|
||||
@@ -85,7 +85,7 @@ static void *rs_init(const char *device, unsigned rate, unsigned latency,
|
||||
|
||||
rsd_set_param(rd, RSD_FORMAT, &format);
|
||||
|
||||
rsd_set_callback(rd, rsound_audio_cb, err_cb, 256, rsd);
|
||||
rsd_set_callback(rd, rsound_audio_cb, rsound_err_cb, 256, rsd);
|
||||
|
||||
if (rsd_start(rd) < 0)
|
||||
{
|
||||
@@ -101,8 +101,9 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ssize_t rs_write(void *data, const void *buf, size_t size)
|
||||
static ssize_t rs_write(void *data, const void *buf, size_t len)
|
||||
{
|
||||
size_t _len;
|
||||
rsd_t *rsd = (rsd_t*)data;
|
||||
|
||||
if (rsd->has_error)
|
||||
@@ -110,21 +111,20 @@ static ssize_t rs_write(void *data, const void *buf, size_t size)
|
||||
|
||||
if (rsd->nonblock)
|
||||
{
|
||||
size_t avail, write_amt;
|
||||
size_t avail;
|
||||
|
||||
rsd_callback_lock(rsd->rd);
|
||||
|
||||
avail = FIFO_WRITE_AVAIL(rsd->buffer);
|
||||
write_amt = avail > size ? size : avail;
|
||||
avail = FIFO_WRITE_AVAIL(rsd->buffer);
|
||||
_len = avail > len ? len : avail;
|
||||
|
||||
fifo_write(rsd->buffer, buf, write_amt);
|
||||
fifo_write(rsd->buffer, buf, _len);
|
||||
rsd_callback_unlock(rsd->rd);
|
||||
return write_amt;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t written = 0;
|
||||
while (written < size && !rsd->has_error)
|
||||
_len = 0;
|
||||
while (_len < len && !rsd->has_error)
|
||||
{
|
||||
size_t avail;
|
||||
rsd_callback_lock(rsd->rd);
|
||||
@@ -143,13 +143,13 @@ static ssize_t rs_write(void *data, const void *buf, size_t size)
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t write_amt = size - written > avail ? avail : size - written;
|
||||
fifo_write(rsd->buffer, (const char*)buf + written, write_amt);
|
||||
size_t write_amt = len - _len > avail ? avail : len - _len;
|
||||
fifo_write(rsd->buffer, (const char*)buf + _len, write_amt);
|
||||
rsd_callback_unlock(rsd->rd);
|
||||
written += write_amt;
|
||||
_len += write_amt;
|
||||
}
|
||||
}
|
||||
return written;
|
||||
return _len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -213,17 +213,9 @@ static size_t rs_write_avail(void *data)
|
||||
return val;
|
||||
}
|
||||
|
||||
static size_t rs_buffer_size(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return 1024 * 4;
|
||||
}
|
||||
|
||||
static bool rs_use_float(void *data)
|
||||
{
|
||||
(void)data;
|
||||
return false;
|
||||
}
|
||||
/* TODO/FIXME - implement? */
|
||||
static size_t rs_buffer_size(void *data) { return 1024 * 4; }
|
||||
static bool rs_use_float(void *data) { return false; }
|
||||
|
||||
audio_driver_t audio_rsound = {
|
||||
rs_init,
|
||||
|
||||
@@ -286,7 +286,7 @@ int rsd_stop (rsound_t *rd);
|
||||
or there was an unexpected error. This function will block until all data has
|
||||
been written to the buffer. This function will return the number of bytes written to the buffer,
|
||||
or 0 should it fail (disconnection from server). You will have to restart the stream again should this occur. */
|
||||
size_t rsd_write (rsound_t *rd, const void* buf, size_t size);
|
||||
size_t rsd_write (rsound_t *rd, const void *s, size_t len);
|
||||
|
||||
/* Gets the position of the buffer pointer.
|
||||
Not really interesting for normal applications.
|
||||
|
||||
Loaded 100 of 1187 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user