Compare commits
2074 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
975a4ae871 | ||
![]() |
56aaf3c73e | ||
![]() |
12fd1cad0c | ||
![]() |
e573cbf032 | ||
![]() |
dead461542 | ||
![]() |
3d5da1ac73 | ||
![]() |
ec408ca6a6 | ||
![]() |
ea66cdd6a5 | ||
![]() |
f762e8034f | ||
![]() |
bb1e369f30 | ||
![]() |
8376578921 | ||
![]() |
ed2354cd9d | ||
![]() |
386688b87a | ||
![]() |
38d56dddf1 | ||
![]() |
e8975942ec | ||
![]() |
3ca80a7336 | ||
![]() |
d029dae7ad | ||
![]() |
9e058732ee | ||
![]() |
cad5d11261 | ||
![]() |
fcaedec2ab | ||
![]() |
ead9d59e88 | ||
![]() |
34b8a17ccd | ||
![]() |
a53d081c39 | ||
![]() |
823134e4ba | ||
![]() |
272167b4fc | ||
![]() |
92f09bba94 | ||
![]() |
1f50bdb230 | ||
![]() |
2eef4e6716 | ||
![]() |
d989dbfec4 | ||
![]() |
ca9fcec364 | ||
![]() |
354104f9a9 | ||
![]() |
8649ea3d6f | ||
![]() |
752ff12c37 | ||
![]() |
4bb89b1755 | ||
![]() |
0ef553d30e | ||
![]() |
43a62aef07 | ||
![]() |
ed4d0aa909 | ||
![]() |
023ce4e720 | ||
![]() |
368d9359dd | ||
![]() |
d98c19d561 | ||
![]() |
cab77e35e0 | ||
![]() |
e3e90b4b93 | ||
![]() |
f8c69893e1 | ||
![]() |
49678a0893 | ||
![]() |
d667b5b48c | ||
![]() |
9cba55b39c | ||
![]() |
c2cbb7b8ce | ||
![]() |
8217d75ca1 | ||
![]() |
1ca70d9759 | ||
![]() |
4303aaa9b8 | ||
![]() |
7b56bae289 | ||
![]() |
4183416b3e | ||
![]() |
a60dee57ce | ||
![]() |
5724656acb | ||
![]() |
329f9cd9fe | ||
![]() |
fbdb8b406e | ||
![]() |
85d0bbd957 | ||
![]() |
414f00d6ae | ||
![]() |
17b0add058 | ||
![]() |
c68ed40661 | ||
![]() |
ff624075a8 | ||
![]() |
08db28469d | ||
![]() |
a20b326807 | ||
![]() |
4db1b1b250 | ||
![]() |
ff6b263b48 | ||
![]() |
c0bf052fa9 | ||
![]() |
5419cff925 | ||
![]() |
eee10ad2ed | ||
![]() |
98472a8104 | ||
![]() |
d094c168aa | ||
![]() |
4b18460bc6 | ||
![]() |
412c0a965c | ||
![]() |
2becf79223 | ||
![]() |
43ec96d4a0 | ||
![]() |
3d1d779da7 | ||
![]() |
c88056ba83 | ||
![]() |
e769751221 | ||
![]() |
49b9a90c3f | ||
![]() |
64d141f71e | ||
![]() |
c488d3123f | ||
![]() |
967af60327 | ||
![]() |
f1ef9f9d31 | ||
![]() |
dfaf08743c | ||
![]() |
d9552d8a6d | ||
![]() |
7586a8ab2c | ||
![]() |
e1a942250b | ||
![]() |
72be0185de | ||
![]() |
7e4cbce06b | ||
![]() |
177d62f431 | ||
![]() |
5a11e03725 | ||
![]() |
75d068b7cd | ||
![]() |
1208503888 | ||
![]() |
de90d401d2 | ||
![]() |
396defaea9 | ||
![]() |
18f350cd04 | ||
![]() |
478180ebe4 | ||
![]() |
4a3059f509 | ||
![]() |
78728138a0 | ||
![]() |
63fc98591d | ||
![]() |
53def9a682 | ||
![]() |
323231d1dd | ||
![]() |
714011c81e | ||
![]() |
952ff4207b | ||
![]() |
150b16ec2c | ||
![]() |
c98bc4a243 | ||
![]() |
014f8cd693 | ||
![]() |
aea37e46e3 | ||
![]() |
31ab78ae8e | ||
![]() |
f82e1453e4 | ||
![]() |
a2b77c8813 | ||
![]() |
18add29472 | ||
![]() |
b111a8fe8d | ||
![]() |
3b23cf0258 | ||
![]() |
28e864e096 | ||
![]() |
1de19b921a | ||
![]() |
ff162b5a03 | ||
![]() |
d8e4705dd4 | ||
![]() |
338e1f5926 | ||
![]() |
a7fdfa08e1 | ||
![]() |
9703a401c5 | ||
![]() |
753a2aa462 | ||
![]() |
10990a0684 | ||
![]() |
91254e9211 | ||
![]() |
0f79287b04 | ||
![]() |
f2fac77d8c | ||
![]() |
81b7373637 | ||
![]() |
fa67c2548a | ||
![]() |
ea80587ddb | ||
![]() |
828f5f8384 | ||
![]() |
1295a1272a | ||
![]() |
66646d9276 | ||
![]() |
d0497dba92 | ||
![]() |
42914e8227 | ||
![]() |
59b49b7881 | ||
![]() |
5620f16330 | ||
![]() |
be024d4ad7 | ||
![]() |
75c740fe2b | ||
![]() |
6c8d86bb90 | ||
![]() |
b253a6b71e | ||
![]() |
ca7b4df812 | ||
![]() |
bc8dd57236 | ||
![]() |
f4f461b8bb | ||
![]() |
cbb9b6957f | ||
![]() |
f6b56c9317 | ||
![]() |
3717fb6c8d | ||
![]() |
f6abbc01bd | ||
![]() |
57a71c157d | ||
![]() |
cc76aeb7bb | ||
![]() |
811cabf8a9 | ||
![]() |
bf8d2f93d2 | ||
![]() |
07d8259ad6 | ||
![]() |
a00d412008 | ||
![]() |
5fb39658f1 | ||
![]() |
b0703b92c3 | ||
![]() |
dd9fd3d8a7 | ||
![]() |
cf0c59864f | ||
![]() |
4c0404c70d | ||
![]() |
573a413ee1 | ||
![]() |
f633e6ca49 | ||
![]() |
07b06d76be | ||
![]() |
856fe2da15 | ||
![]() |
f82aae65cd | ||
![]() |
3fbd11a104 | ||
![]() |
58a99f1907 | ||
![]() |
cf86dfd317 | ||
![]() |
a057b4f6d8 | ||
![]() |
62b03cfddf | ||
![]() |
18b827b979 | ||
![]() |
0a379fc514 | ||
![]() |
445c11b8d9 | ||
![]() |
8d290ad509 | ||
![]() |
b90c48b50f | ||
![]() |
d19e7db09e | ||
![]() |
9939904b02 | ||
![]() |
ca23b15f5c | ||
![]() |
ffa676f577 | ||
![]() |
6d023c4df3 | ||
![]() |
b31bd37a30 | ||
![]() |
78faee8c7c | ||
![]() |
40e2a703d0 | ||
![]() |
b01edcb9bc | ||
![]() |
f7fffc9be8 | ||
![]() |
50e8634097 | ||
![]() |
e3994e517e | ||
![]() |
2bb7785189 | ||
![]() |
90c8408111 | ||
![]() |
64786ec12a | ||
![]() |
b3c82f8886 | ||
![]() |
063259dc52 | ||
![]() |
b4c9d9c2a7 | ||
![]() |
fa2b59df4b | ||
![]() |
f41a169460 | ||
![]() |
f567083006 | ||
![]() |
a2a677e539 | ||
![]() |
9123c0b733 | ||
![]() |
788e3b31e1 | ||
![]() |
71f0ed8b74 | ||
![]() |
ac2e4e593d | ||
![]() |
edaa7d7748 | ||
![]() |
3cdf965fba | ||
![]() |
6b60d1e71f | ||
![]() |
7b7fb5acd5 | ||
![]() |
0a7d612f41 | ||
![]() |
38da76bbe0 | ||
![]() |
a13e045742 | ||
![]() |
811620c0a0 | ||
![]() |
504f5f7bdd | ||
![]() |
32bcad51b8 | ||
![]() |
a40510c241 | ||
![]() |
ac8dce6599 | ||
![]() |
190d525099 | ||
![]() |
1b6666fa39 | ||
![]() |
1dd01c99e8 | ||
![]() |
d50b30a498 | ||
![]() |
42a3a87f13 | ||
![]() |
9dfedbe619 | ||
![]() |
88957b4c9d | ||
![]() |
b2f2c9322b | ||
![]() |
3be2051808 | ||
![]() |
ff32b0dc9b | ||
![]() |
c1869a11af | ||
![]() |
e22a4fdba4 | ||
![]() |
29a7b2c5b5 | ||
![]() |
3b6c285c2a | ||
![]() |
575d1786af | ||
![]() |
bc1c927952 | ||
![]() |
f95bc85f91 | ||
![]() |
4015195314 | ||
![]() |
c3d883c6cb | ||
![]() |
097e30321b | ||
![]() |
b6ddeaacf2 | ||
![]() |
b0c60ec124 | ||
![]() |
f3b788703e | ||
![]() |
4bb83781e8 | ||
![]() |
a73195b7cc | ||
![]() |
1bd00b8a9a | ||
![]() |
d84eaeafc5 | ||
![]() |
20ae84bff9 | ||
![]() |
7372c931b3 | ||
![]() |
29e1b6e465 | ||
![]() |
eda06993f8 | ||
![]() |
4b30ef1cf2 | ||
![]() |
e92e5e8eb8 | ||
![]() |
4e5271fcdf | ||
![]() |
3c55487a16 | ||
![]() |
76a1cae5d8 | ||
![]() |
81a97315e3 | ||
![]() |
53c14d97a6 | ||
![]() |
69a82eec17 | ||
![]() |
45cadef22f | ||
![]() |
0a033fb10a | ||
![]() |
591afa0647 | ||
![]() |
05eac20ffe | ||
![]() |
38d263ac19 | ||
![]() |
f71c204eef | ||
![]() |
51147203be | ||
![]() |
a931686317 | ||
![]() |
5bd322bdcf | ||
![]() |
bb097109f0 | ||
![]() |
2ab6c40ff1 | ||
![]() |
68bb738af2 | ||
![]() |
6b968beede | ||
![]() |
f68dd1bffb | ||
![]() |
f92b71ca99 | ||
![]() |
2b79fe2d6a | ||
![]() |
44dd9af276 | ||
![]() |
d3013d4f8c | ||
![]() |
678524ad21 | ||
![]() |
32a64481f2 | ||
![]() |
1776015c6c | ||
![]() |
f1c71a26e3 | ||
![]() |
e78ab767d3 | ||
![]() |
f01eb2f95d | ||
![]() |
1450e45d97 | ||
![]() |
ec8cba369c | ||
![]() |
f4c248f406 | ||
![]() |
f3b2a58646 | ||
![]() |
c6f89c42b2 | ||
![]() |
5e93cfdd9e | ||
![]() |
d91d5a3ab5 | ||
![]() |
907c045f33 | ||
![]() |
90f189eb54 | ||
![]() |
4abd5b2112 | ||
![]() |
df9a665994 | ||
![]() |
7a098ca0ed | ||
![]() |
33716732a1 | ||
![]() |
97ae594375 | ||
![]() |
3f321ae9a0 | ||
![]() |
161d32a7e7 | ||
![]() |
d7137586a9 | ||
![]() |
cd0c06ba6e | ||
![]() |
899ab63d91 | ||
![]() |
1097820a5a | ||
![]() |
39114f91a7 | ||
![]() |
4f01387edf | ||
![]() |
de3e0585f1 | ||
![]() |
f85f25ba82 | ||
![]() |
10a2c179f9 | ||
![]() |
6eea56861b | ||
![]() |
21fd2064ae | ||
![]() |
dcbab8e37a | ||
![]() |
5677278251 | ||
![]() |
a83bee993d | ||
![]() |
96a31f554a | ||
![]() |
d14ec6aea5 | ||
![]() |
917cedf893 | ||
![]() |
193dd71600 | ||
![]() |
6c293a3d7f | ||
![]() |
e847ddf011 | ||
![]() |
7e8b448985 | ||
![]() |
d1f3a87c08 | ||
![]() |
9f8145e590 | ||
![]() |
791efc171a | ||
![]() |
144312a525 | ||
![]() |
92684112ed | ||
![]() |
ef114ee6cb | ||
![]() |
667f209742 | ||
![]() |
4ad0747c78 | ||
![]() |
c5cf66402c | ||
![]() |
05417049eb | ||
![]() |
c7b0c46d9f | ||
![]() |
df578c91ad | ||
![]() |
70008c47c9 | ||
![]() |
938affef32 | ||
![]() |
a3c33000ee | ||
![]() |
1e54b7b294 | ||
![]() |
cc0dbcf3f4 | ||
![]() |
c5a2cadccc | ||
![]() |
9aa43416b6 | ||
![]() |
8364029db8 | ||
![]() |
d842d21be0 | ||
![]() |
3514fd2433 | ||
![]() |
6778ff27ea | ||
![]() |
f32315d699 | ||
![]() |
8b754b24b6 | ||
![]() |
b1bee9ff38 | ||
![]() |
569be2d402 | ||
![]() |
78a73eac53 | ||
![]() |
533cb99c33 | ||
![]() |
79726940dc | ||
![]() |
27c7891169 | ||
![]() |
7a3a793a12 | ||
![]() |
8088469eca | ||
![]() |
3dcb082015 | ||
![]() |
bece023028 | ||
![]() |
9c4df66925 | ||
![]() |
2b43ceb6c6 | ||
![]() |
c143adba91 | ||
![]() |
142fdc8d86 | ||
![]() |
67778dcd3d | ||
![]() |
ed80863eac | ||
![]() |
c3fc84de12 | ||
![]() |
904f83cd85 | ||
![]() |
28bf100a50 | ||
![]() |
accbd4e82a | ||
![]() |
d7f478c154 | ||
![]() |
8f7f13fea4 | ||
![]() |
c82b03a74c | ||
![]() |
58fb36bdb9 | ||
![]() |
4297a7b0a4 | ||
![]() |
1bab6d0dd7 | ||
![]() |
13b85edbe2 | ||
![]() |
dc53098e43 | ||
![]() |
3c66feff5a | ||
![]() |
218c3bc0d5 | ||
![]() |
9f5eddcd13 | ||
![]() |
3cba76552b | ||
![]() |
e98a8b624b | ||
![]() |
6c6947b01f | ||
![]() |
78c91e9e5b | ||
![]() |
44493ca0c4 | ||
![]() |
42acf78b09 | ||
![]() |
3aa9f8af18 | ||
![]() |
8a32ee30a5 | ||
![]() |
981dc0626b | ||
![]() |
8986d14e98 | ||
![]() |
5163b1a624 | ||
![]() |
860aa9d6d0 | ||
![]() |
64dc5212f9 | ||
![]() |
6cff3214f3 | ||
![]() |
fd910bd5e9 | ||
![]() |
c6086bed41 | ||
![]() |
1a9dfdfab8 | ||
![]() |
5284cd11a9 | ||
![]() |
d1a47cffad | ||
![]() |
f469595eee | ||
![]() |
9cfc52f114 | ||
![]() |
30bfb756c2 | ||
![]() |
711f85445e | ||
![]() |
8aae9766e5 | ||
![]() |
288b98ccbf | ||
![]() |
bde50b1be8 | ||
![]() |
a34dfd55be | ||
![]() |
609c1d4d4c | ||
![]() |
c12fe09969 | ||
![]() |
bd14afe347 | ||
![]() |
f445a13051 | ||
![]() |
8ddf607d9f | ||
![]() |
5900253b85 | ||
![]() |
ccec94925f | ||
![]() |
4504a9d0b5 | ||
![]() |
057f98ad45 | ||
![]() |
3b1c9aa026 | ||
![]() |
658397dc38 | ||
![]() |
0cd1c8e23e | ||
![]() |
0345c1e6f8 | ||
![]() |
f6c4cda0d4 | ||
![]() |
39fd713b91 | ||
![]() |
31d77ec580 | ||
![]() |
06116382ee | ||
![]() |
d2046de193 | ||
![]() |
4397fe3a13 | ||
![]() |
534e1fa6eb | ||
![]() |
3e8cc2c670 | ||
![]() |
3c565baf9d | ||
![]() |
2e182e84c3 | ||
![]() |
a42021655c | ||
![]() |
2498a2b0bd | ||
![]() |
4484411a77 | ||
![]() |
61a151c803 | ||
![]() |
5149c950aa | ||
![]() |
18f4d846c9 | ||
![]() |
db95aa250d | ||
![]() |
982d1bf662 | ||
![]() |
a0393e9ddf | ||
![]() |
a8d6328bd4 | ||
![]() |
13dab13319 | ||
![]() |
c623aa0f06 | ||
![]() |
79403afbe6 | ||
![]() |
4c650e87fa | ||
![]() |
3dde62befe | ||
![]() |
8bfabbe265 | ||
![]() |
e334b16aaa | ||
![]() |
5626ace245 | ||
![]() |
52652cb609 | ||
![]() |
256f40d4f5 | ||
![]() |
ef9acc54ec | ||
![]() |
a9f2d25957 | ||
![]() |
6fc47fbb69 | ||
![]() |
9c11184238 | ||
![]() |
a421c1dbfb | ||
![]() |
7ec707927d | ||
![]() |
837134daef | ||
![]() |
4011899846 | ||
![]() |
28e743ba70 | ||
![]() |
a161d404ad | ||
![]() |
cd607cb280 | ||
![]() |
4e60ab7f53 | ||
![]() |
71e7d32b08 | ||
![]() |
d5e422970c | ||
![]() |
871ba5a488 | ||
![]() |
249e8d59cb | ||
![]() |
8f4769d2ac | ||
![]() |
a3ca9963a5 | ||
![]() |
2d3c23876c | ||
![]() |
bd8d8eef3e | ||
![]() |
e786207cc2 | ||
![]() |
b042095ac2 | ||
![]() |
3413d1bf23 | ||
![]() |
018c5ef731 | ||
![]() |
fdb136f1fa | ||
![]() |
9e33074735 | ||
![]() |
d6d465cdf4 | ||
![]() |
e76573cc1a | ||
![]() |
3fa6dc71e2 | ||
![]() |
6fec269844 | ||
![]() |
b6004b6837 | ||
![]() |
86d3b25aec | ||
![]() |
8a407bfbb0 | ||
![]() |
d30a590d9e | ||
![]() |
f95e404be1 | ||
![]() |
ffb8b4fc68 | ||
![]() |
f86d6b0162 | ||
![]() |
71c72ed072 | ||
![]() |
a8d343e07b | ||
![]() |
d020172181 | ||
![]() |
e5c9f6c1fe | ||
![]() |
176dc11748 | ||
![]() |
c2abd02b9b | ||
![]() |
12ecfdd423 | ||
![]() |
67cfbfc2f3 | ||
![]() |
fc83d38e67 | ||
![]() |
7063c423eb | ||
![]() |
36b93993cf | ||
![]() |
ceffc5aa72 | ||
![]() |
ccb45b6f6e | ||
![]() |
d2e47e014a | ||
![]() |
a5b8d7917f | ||
![]() |
d0e735ee4b | ||
![]() |
ece5971027 | ||
![]() |
7c6b0d5c31 | ||
![]() |
03151310cf | ||
![]() |
baa2bc0c38 | ||
![]() |
7e1b53480e | ||
![]() |
6425b4f9f5 | ||
![]() |
fb907f5f76 | ||
![]() |
b107a1583f | ||
![]() |
ced3f320eb | ||
![]() |
a9d7293818 | ||
![]() |
add42e9edf | ||
![]() |
265ad4b96a | ||
![]() |
92eeb4969f | ||
![]() |
6fcddaf8fa | ||
![]() |
41fd583fbc | ||
![]() |
ceba6816de | ||
![]() |
093cb475bb | ||
![]() |
d44790b35f | ||
![]() |
f8164a3dd1 | ||
![]() |
c20126598f | ||
![]() |
6c818bb37a | ||
![]() |
8cb160b1f8 | ||
![]() |
df91f3738a | ||
![]() |
b5b268f606 | ||
![]() |
ce6b8c94a2 | ||
![]() |
6e643fe58b | ||
![]() |
2bf91a0487 | ||
![]() |
2775d747ac | ||
![]() |
99659e4cf9 | ||
![]() |
3bbcda917c | ||
![]() |
7e43fb79af | ||
![]() |
eb2b567da6 | ||
![]() |
ab332d7b2e | ||
![]() |
53e22b81ef | ||
![]() |
3fc9d50adb | ||
![]() |
c2da6dd45b | ||
![]() |
7146f825b2 | ||
![]() |
f61a5f5200 | ||
![]() |
dc05dd7ca1 | ||
![]() |
57dd344f3b | ||
![]() |
f7f59df8aa | ||
![]() |
0525a6f90f | ||
![]() |
7b4305d81b | ||
![]() |
94e9e93fa4 | ||
![]() |
d2a1294e9a | ||
![]() |
3d897f18cd | ||
![]() |
68c14d1e53 | ||
![]() |
48089394a5 | ||
![]() |
30bd190b41 | ||
![]() |
cf93cd9307 | ||
![]() |
f40816e063 | ||
![]() |
3759f29852 | ||
![]() |
bc5555933f | ||
![]() |
ead7ae8504 | ||
![]() |
ad5abba8c6 | ||
![]() |
61296cedd2 | ||
![]() |
d9c29a2c4f | ||
![]() |
f5172e6b84 | ||
![]() |
544bcbe903 | ||
![]() |
f35dab1b56 | ||
![]() |
caee420087 | ||
![]() |
e8c374113e | ||
![]() |
98a241a730 | ||
![]() |
be8297d6f6 | ||
![]() |
09da80e9f4 | ||
![]() |
df4ecf63a8 | ||
![]() |
b4d1937857 | ||
![]() |
0be5fbdc35 | ||
![]() |
ae7e25ea65 | ||
![]() |
5013de6770 | ||
![]() |
9614c48e4c | ||
![]() |
c6e1ca1c22 | ||
![]() |
30dc473697 | ||
![]() |
65974ceabc | ||
![]() |
6caf53d1c2 | ||
![]() |
dee6e498d9 | ||
![]() |
b3723274f7 | ||
![]() |
9fb7cc796b | ||
![]() |
3472208c05 | ||
![]() |
fc30e1d559 | ||
![]() |
cd4bb444ff | ||
![]() |
e443513996 | ||
![]() |
3d16f22135 | ||
![]() |
6cc1ff5eeb | ||
![]() |
3000b9dcde | ||
![]() |
3b867462a3 | ||
![]() |
b8aa9348b9 | ||
![]() |
513e3a3d21 | ||
![]() |
bfb0897b54 | ||
![]() |
86e8b8c10d | ||
![]() |
ee57c3490a | ||
![]() |
77c1f54876 | ||
![]() |
dc5984d0e0 | ||
![]() |
7afbd4800f | ||
![]() |
0720702c91 | ||
![]() |
5f396e824f | ||
![]() |
4f229c254c | ||
![]() |
25e58df5e0 | ||
![]() |
1261327fa6 | ||
![]() |
09c3cc58e4 | ||
![]() |
7ef31f84a7 | ||
![]() |
85c2b396ce | ||
![]() |
0759d72108 | ||
![]() |
9b9144f25d | ||
![]() |
b677e891b4 | ||
![]() |
509f62f68d | ||
![]() |
868bf752f3 | ||
![]() |
051cdc9670 | ||
![]() |
4de5c216ff | ||
![]() |
ad2c7304ea | ||
![]() |
4dd1309c3f | ||
![]() |
541da2740d | ||
![]() |
95e2bec215 | ||
![]() |
72c96052b4 | ||
![]() |
2ab168735f | ||
![]() |
85cdf05890 | ||
![]() |
bf78b7f815 | ||
![]() |
ffb9874d84 | ||
![]() |
228cdbe6af | ||
![]() |
a303639c9e | ||
![]() |
c5133f6088 | ||
![]() |
27d368d48d | ||
![]() |
085b599f84 | ||
![]() |
3b84eb3b70 | ||
![]() |
aa877a29d7 | ||
![]() |
0abee77e62 | ||
![]() |
114fcee2ae | ||
![]() |
b488204093 | ||
![]() |
322bfbaf57 | ||
![]() |
2718f4c333 | ||
![]() |
8c342a764b | ||
![]() |
697c3f8cb9 | ||
![]() |
bb292f501d | ||
![]() |
723e54f74e | ||
![]() |
1a8c96a3f0 | ||
![]() |
a88040e4d5 | ||
![]() |
47a0f46ce8 | ||
![]() |
66fb352cca | ||
![]() |
fd77acc217 | ||
![]() |
595d1942cb | ||
![]() |
b905933999 | ||
![]() |
219a756abc | ||
![]() |
2f76f9da89 | ||
![]() |
b0b8f573bc | ||
![]() |
746aa6cc0f | ||
![]() |
fac610d47b | ||
![]() |
93209da176 | ||
![]() |
35a2a48c47 | ||
![]() |
22dcca9832 | ||
![]() |
db6c0d54cf | ||
![]() |
a17abc5557 | ||
![]() |
741c6f1179 | ||
![]() |
43b285ef7a | ||
![]() |
f4bb18b05e | ||
![]() |
14885f25b4 | ||
![]() |
4e16ea0f0a | ||
![]() |
42a696873b | ||
![]() |
cfd51db229 | ||
![]() |
12f11c97ae | ||
![]() |
6a78d11127 | ||
![]() |
256ee7a8c7 | ||
![]() |
07a51957ee | ||
![]() |
37c4470f10 | ||
![]() |
4dc7d1c0cd | ||
![]() |
f6a85f0b0b | ||
![]() |
5b8b660bd0 | ||
![]() |
d9cb85df83 | ||
![]() |
445e82be75 | ||
![]() |
98a12c49dd | ||
![]() |
b78cc7e48a | ||
![]() |
ac9ce0b3ad | ||
![]() |
cf2b814629 | ||
![]() |
bbe7a37359 | ||
![]() |
d0aa154ea6 | ||
![]() |
df4616ae4a | ||
![]() |
10f62db9fd | ||
![]() |
5c075210d6 | ||
![]() |
0cf85b0771 | ||
![]() |
fa90047e52 | ||
![]() |
b9f64fe19b | ||
![]() |
dd072912e8 | ||
![]() |
9dbdc75689 | ||
![]() |
dce211dbba | ||
![]() |
b4e5fa5c1b | ||
![]() |
f12fa7e20a | ||
![]() |
96f8f1da0c | ||
![]() |
db7eec042e | ||
![]() |
52aed3f8a1 | ||
![]() |
cadd186f1b | ||
![]() |
dd9ab16d67 | ||
![]() |
d8b6aff23a | ||
![]() |
b8aac3f8fc | ||
![]() |
4aab97ccb1 | ||
![]() |
4cd21f1e07 | ||
![]() |
403f0f8c64 | ||
![]() |
8c4246f2ad | ||
![]() |
54d5184255 | ||
![]() |
0c5b986fc4 | ||
![]() |
7b2cdd618e | ||
![]() |
30bb3f1fcb | ||
![]() |
b45ea66175 | ||
![]() |
543c5034af | ||
![]() |
c8aa7afdc6 | ||
![]() |
b35bb1b50c | ||
![]() |
6341be9cdf | ||
![]() |
93a14a93f9 | ||
![]() |
d6559e2ac9 | ||
![]() |
65e6755b8b | ||
![]() |
6ead9750f4 | ||
![]() |
6532c7e089 | ||
![]() |
8b3d934230 | ||
![]() |
e2b7c30811 | ||
![]() |
c8bb3c0b71 | ||
![]() |
9990e8473c | ||
![]() |
d765182bbb | ||
![]() |
5a63d1d5a4 | ||
![]() |
6d409d27ca | ||
![]() |
e9c2885f34 | ||
![]() |
ecb8f7362b | ||
![]() |
17ccfec358 | ||
![]() |
a55bb28069 | ||
![]() |
a2e3dc0592 | ||
![]() |
df142d4f61 | ||
![]() |
fac8edd47a | ||
![]() |
9a9da7b077 | ||
![]() |
131441846b | ||
![]() |
3ff728ab02 | ||
![]() |
78bf4ef5fa | ||
![]() |
318d0b3976 | ||
![]() |
90a14e14f4 | ||
![]() |
dea46e8d5a | ||
![]() |
7e5ce623fe | ||
![]() |
e17805f208 | ||
![]() |
d8bcdca55a | ||
![]() |
f6f2a3b366 | ||
![]() |
d52c7e7a1b | ||
![]() |
c4acccac14 | ||
![]() |
13001c018c | ||
![]() |
1b39efb694 | ||
![]() |
0c343cb1c3 | ||
![]() |
aead221184 | ||
![]() |
16d1c9f5d6 | ||
![]() |
0c464b24ad | ||
![]() |
a249a630c0 | ||
![]() |
f39823eac0 | ||
![]() |
69de99636f | ||
![]() |
afcff1fa77 | ||
![]() |
9b5bae049c | ||
![]() |
7a3415166e | ||
![]() |
5b2b4bf13c | ||
![]() |
4bd67bc298 | ||
![]() |
1560749579 | ||
![]() |
ed68fd4ab3 | ||
![]() |
e9a9dabb49 | ||
![]() |
31faafea9d | ||
![]() |
6961bd61ca | ||
![]() |
726fc53e62 | ||
![]() |
c598686bd9 | ||
![]() |
cab87e9398 | ||
![]() |
680037927d | ||
![]() |
60f72f0ff9 | ||
![]() |
debc855806 | ||
![]() |
10e32454ef | ||
![]() |
8d41e9658f | ||
![]() |
086652dd50 | ||
![]() |
6135f0763b | ||
![]() |
307964d874 | ||
![]() |
f3dd50de87 | ||
![]() |
c776bcc5f6 | ||
![]() |
4bbc43d91a | ||
![]() |
db8b5dc698 | ||
![]() |
2f56c61b47 | ||
![]() |
1d340e7664 | ||
![]() |
ea62bc0bb2 | ||
![]() |
8380c3be02 | ||
![]() |
6470bcda19 | ||
![]() |
2d51349d1d | ||
![]() |
2f2b394d72 | ||
![]() |
ba181ae9df | ||
![]() |
f62546ec79 | ||
![]() |
1c155a0d03 | ||
![]() |
8f196db778 | ||
![]() |
d0302d1bbe | ||
![]() |
d73267df5e | ||
![]() |
8bbfb5cda1 | ||
![]() |
1e17d5b1cc | ||
![]() |
f881917d2f | ||
![]() |
99244f51b0 | ||
![]() |
606d029ed9 | ||
![]() |
e4b9d679fb | ||
![]() |
2bf2bd8932 | ||
![]() |
4a8a33ea85 | ||
![]() |
ac4b83046a | ||
![]() |
2a2ac35b98 | ||
![]() |
8c744efd56 | ||
![]() |
597e59f10d | ||
![]() |
3cd07d0b54 | ||
![]() |
13259225c2 | ||
![]() |
7acd91331c | ||
![]() |
0fdaca17a2 | ||
![]() |
539c0ed171 | ||
![]() |
553365b942 | ||
![]() |
100308db02 | ||
![]() |
ab967462e6 | ||
![]() |
1bc553ea62 | ||
![]() |
687ea53616 | ||
![]() |
220d9528a3 | ||
![]() |
fc7d3f64c0 | ||
![]() |
63ab7767a3 | ||
![]() |
20894d1c5e | ||
![]() |
2f03d2234a | ||
![]() |
dadf3d846b | ||
![]() |
941a9284b9 | ||
![]() |
4ee3820bd6 | ||
![]() |
c155df5d79 | ||
![]() |
33b70567c8 | ||
![]() |
720bf51ba6 | ||
![]() |
26bdb72428 | ||
![]() |
90c8a1b1cf | ||
![]() |
3143dbf3dc | ||
![]() |
38d587aaeb | ||
![]() |
fe9bafa741 | ||
![]() |
8092e18158 | ||
![]() |
6ed77f2a27 | ||
![]() |
a73688a2be | ||
![]() |
e7d327226a | ||
![]() |
ae1eb9ccde | ||
![]() |
860064c812 | ||
![]() |
845901ab01 | ||
![]() |
25f7360264 | ||
![]() |
78ec7d0fe1 | ||
![]() |
a1e9678b69 | ||
![]() |
be5d629c13 | ||
![]() |
957b399e90 | ||
![]() |
5e6c164b9f | ||
![]() |
5d9a889190 | ||
![]() |
a9acc9c971 | ||
![]() |
308010794a | ||
![]() |
0ce72cbf9d | ||
![]() |
6e52ab285a | ||
![]() |
3da4648112 | ||
![]() |
1897409476 | ||
![]() |
c60d65dd8f | ||
![]() |
f29949e14d | ||
![]() |
75aa98ddaa | ||
![]() |
06909f4f00 | ||
![]() |
aca081557a | ||
![]() |
a71efacd1e | ||
![]() |
871063dab7 | ||
![]() |
135662d6b0 | ||
![]() |
a69c3c1848 | ||
![]() |
50e5244e25 | ||
![]() |
1c07f197de | ||
![]() |
13c32111a0 | ||
![]() |
28c6975732 | ||
![]() |
12091fcfb1 | ||
![]() |
5598826eaf | ||
![]() |
3fea624cca | ||
![]() |
9007dd9ab7 | ||
![]() |
08166cf330 | ||
![]() |
e51b6a6233 | ||
![]() |
3887465d80 | ||
![]() |
d84f96a571 | ||
![]() |
f600e226da | ||
![]() |
d775f13a03 | ||
![]() |
b630afdeda | ||
![]() |
c39c259078 | ||
![]() |
a571c4ba33 | ||
![]() |
889be6e29d | ||
![]() |
d15f64ae5d | ||
![]() |
a07117ea55 | ||
![]() |
d0dae177cf | ||
![]() |
e2f6cc9c9f | ||
![]() |
8748b2dc3f | ||
![]() |
5f66af3712 | ||
![]() |
31ae50b137 | ||
![]() |
87e0459fcc | ||
![]() |
07e58ae64f | ||
![]() |
a88d18148c | ||
![]() |
1cf43a9dc9 | ||
![]() |
196ce8426b | ||
![]() |
6a95c34a81 | ||
![]() |
ea0e6d9824 | ||
![]() |
14d3da0e18 | ||
![]() |
b6b8fb7d73 | ||
![]() |
2bca3cd247 | ||
![]() |
22a353b8e3 | ||
![]() |
743fa73a01 | ||
![]() |
4d6192adcd | ||
![]() |
9f1ada898e | ||
![]() |
5617521380 | ||
![]() |
9835a2545d | ||
![]() |
c28cefeeb0 | ||
![]() |
afd5b750dc | ||
![]() |
21d747cd36 | ||
![]() |
ef3494f160 | ||
![]() |
2dc6c4a496 | ||
![]() |
2777a23672 | ||
![]() |
32afd92d30 | ||
![]() |
0c809fbb40 | ||
![]() |
ad80acb22a | ||
![]() |
bd8414f8ea | ||
![]() |
2eb467c788 | ||
![]() |
c436e29b89 | ||
![]() |
44219d5e91 | ||
![]() |
b9de3270f6 | ||
![]() |
590d6faeb0 | ||
![]() |
62e96e9a58 | ||
![]() |
1c818ef0a0 | ||
![]() |
d6ce2e3671 | ||
![]() |
85b6a52662 | ||
![]() |
0246082b9b | ||
![]() |
3b031c6ba5 | ||
![]() |
74740ca50b | ||
![]() |
631baa7120 | ||
![]() |
657d6edff7 | ||
![]() |
737c5a9549 | ||
![]() |
c5fb56f90f | ||
![]() |
4cd9abe632 | ||
![]() |
b67e7df38e | ||
![]() |
e068d62ac6 | ||
![]() |
1a4a6f3807 | ||
![]() |
a012b25335 | ||
![]() |
46e8b137e9 | ||
![]() |
4b25c5e8d6 | ||
![]() |
2fdbae3e1f | ||
![]() |
87e06793c2 | ||
![]() |
8cc451a2e2 | ||
![]() |
723c2c7fa9 | ||
![]() |
4dd2c5cdd5 | ||
![]() |
bdc257b40e | ||
![]() |
4728f7c697 | ||
![]() |
1c4c0fe8a1 | ||
![]() |
360274a6e9 | ||
![]() |
07228ff56a | ||
![]() |
a61f153df7 | ||
![]() |
34e91850d9 | ||
![]() |
3a21241248 | ||
![]() |
5c75096bcd | ||
![]() |
a43b0f5253 | ||
![]() |
d93271e86d | ||
![]() |
4a6df9f961 | ||
![]() |
a43ae2369b | ||
![]() |
9a049de859 | ||
![]() |
58b8398aa0 | ||
![]() |
645751f680 | ||
![]() |
2d3b6879f5 | ||
![]() |
26c0924461 | ||
![]() |
d4f801a8e9 | ||
![]() |
cb1082c58c | ||
![]() |
8406864963 | ||
![]() |
85ef034fd0 | ||
![]() |
59141f62bb | ||
![]() |
d68cadba7b | ||
![]() |
1207fd1f16 | ||
![]() |
8aa61e230c | ||
![]() |
2c7bda8a3b | ||
![]() |
d58c5dd398 | ||
![]() |
171da7a347 | ||
![]() |
3fd70a769a | ||
![]() |
4280f84535 | ||
![]() |
c3d9c32615 | ||
![]() |
a938b609b9 | ||
![]() |
d3c7fac606 | ||
![]() |
fea3f6cc72 | ||
![]() |
aee5966e1c | ||
![]() |
95e53ac0a0 | ||
![]() |
5d11759f7d | ||
![]() |
829616534e | ||
![]() |
863f4d8366 | ||
![]() |
bdd0c3686d | ||
![]() |
91769d536d | ||
![]() |
9500343d85 | ||
![]() |
ef053035d0 | ||
![]() |
35faafb32c | ||
![]() |
f9fd868b99 | ||
![]() |
8b903626c2 | ||
![]() |
021519f295 | ||
![]() |
e83685d667 | ||
![]() |
81a198a76a | ||
![]() |
b2b7974ba0 | ||
![]() |
f59ca94416 | ||
![]() |
22ff0d80ce | ||
![]() |
5a22a0c27d | ||
![]() |
287ef181ba | ||
![]() |
bc63810ebd | ||
![]() |
92cdea123e | ||
![]() |
e4c7e343c8 | ||
![]() |
6b75be183d | ||
![]() |
718f6d9cef | ||
![]() |
2ee43c403c | ||
![]() |
24fa3f5e7b | ||
![]() |
bbbda7f812 | ||
![]() |
e958900380 | ||
![]() |
74926c1dd3 | ||
![]() |
2654888782 | ||
![]() |
49597b0e9c | ||
![]() |
b5ecfb4c9a | ||
![]() |
07fa3764ef | ||
![]() |
5acc77a163 | ||
![]() |
0709878b4c | ||
![]() |
662e477028 | ||
![]() |
b7b7c381ee | ||
![]() |
995cd95474 | ||
![]() |
fe8a13f76f | ||
![]() |
9252432bc0 | ||
![]() |
f057f6768f | ||
![]() |
806bf0be8d | ||
![]() |
958506a108 | ||
![]() |
e8fd771b91 | ||
![]() |
fa4178fefa | ||
![]() |
1af59d31b9 | ||
![]() |
20758cef30 | ||
![]() |
272938529d | ||
![]() |
a67b7266ed | ||
![]() |
f26159a0e3 | ||
![]() |
675e8667c2 | ||
![]() |
a1a26b70bc | ||
![]() |
34a7f86a07 | ||
![]() |
e7311ac2f3 | ||
![]() |
8d9ecc0c62 | ||
![]() |
f01b991108 | ||
![]() |
f80736c3d7 | ||
![]() |
2c7f69cf85 | ||
![]() |
348ecc1118 | ||
![]() |
a9678f0ae0 | ||
![]() |
461f298d2c | ||
![]() |
068de7cf40 | ||
![]() |
d04eb87c4f | ||
![]() |
8af68db965 | ||
![]() |
1cf632e98b | ||
![]() |
58c11c3128 | ||
![]() |
efcda95dda | ||
![]() |
80d2028bac | ||
![]() |
215213fc2c | ||
![]() |
99d32dc0b4 | ||
![]() |
0998097253 | ||
![]() |
c17be5af6b | ||
![]() |
b376536a3b | ||
![]() |
e7edc02647 | ||
![]() |
69bf835059 | ||
![]() |
b97ffddfe8 | ||
![]() |
6407b7c591 | ||
![]() |
e14cd92d59 | ||
![]() |
73cadd1798 | ||
![]() |
fb9840f1f8 | ||
![]() |
492aaa3375 | ||
![]() |
33c5da700d | ||
![]() |
48d3af7d9a | ||
![]() |
9b3470eabd | ||
![]() |
86a505b4f3 | ||
![]() |
ed6c6296eb | ||
![]() |
b27a41812f | ||
![]() |
6c933d2b77 | ||
![]() |
fb5610f9bd | ||
![]() |
7adbd00811 | ||
![]() |
1c91d19163 | ||
![]() |
f491135318 | ||
![]() |
a7ced00520 | ||
![]() |
be3359fc67 | ||
![]() |
69ed35ed71 | ||
![]() |
280d35a053 | ||
![]() |
eca6b9f0af | ||
![]() |
cc9345e703 | ||
![]() |
3fb8f3ec95 | ||
![]() |
fc3e0dfcd1 | ||
![]() |
6513ff92a7 | ||
![]() |
a0eb6d0976 | ||
![]() |
7530770842 | ||
![]() |
11ea72e240 | ||
![]() |
c98330909a | ||
![]() |
bec6fa4ad7 | ||
![]() |
ac7ce73526 | ||
![]() |
4c6619e6c5 | ||
![]() |
e8121fdc11 | ||
![]() |
21f17270a1 | ||
![]() |
423cd5900e | ||
![]() |
b9f535cd49 | ||
![]() |
e228144159 | ||
![]() |
9431a7b022 | ||
![]() |
cd041f8574 | ||
![]() |
8ba3378096 | ||
![]() |
225984822d | ||
![]() |
01b68db30e | ||
![]() |
33fdaa5b6d | ||
![]() |
6a1f5667f9 | ||
![]() |
fab5f58ee0 | ||
![]() |
55be8e6f52 | ||
![]() |
c75b9b0d12 | ||
![]() |
9b85446808 | ||
![]() |
fd5d42836f | ||
![]() |
4eaa82fd22 | ||
![]() |
a497cc46f9 | ||
![]() |
178f737971 | ||
![]() |
74963bce9d | ||
![]() |
33a4dbe1e5 | ||
![]() |
60f32d0bce | ||
![]() |
dce36d3e55 | ||
![]() |
4f393553f4 | ||
![]() |
91afc7b23c | ||
![]() |
36d158e13e | ||
![]() |
02a97b5985 | ||
![]() |
b980545012 | ||
![]() |
8aad152b23 | ||
![]() |
2deb5b7fec | ||
![]() |
2fd5182608 | ||
![]() |
7ad7caa2ae | ||
![]() |
6d1710c74f | ||
![]() |
233b8d0129 | ||
![]() |
f55bdf07d3 | ||
![]() |
6c2b532ae3 | ||
![]() |
2539f294e4 | ||
![]() |
b6a3ce9305 | ||
![]() |
b07495aae9 | ||
![]() |
686a53215d | ||
![]() |
6190da1300 | ||
![]() |
6fd7d8191e | ||
![]() |
2ccd1cc9f0 | ||
![]() |
8167bdd978 | ||
![]() |
dfb3e34f7b | ||
![]() |
45ee75055e | ||
![]() |
5da4e321c0 | ||
![]() |
e8519fecb4 | ||
![]() |
06c172838c | ||
![]() |
1543dd85b5 | ||
![]() |
f37a1026f9 | ||
![]() |
91fb7fa3d8 | ||
![]() |
7b70153068 | ||
![]() |
7e096ee2c5 | ||
![]() |
86a90daf1b | ||
![]() |
42f7df9681 | ||
![]() |
2edad38c7c | ||
![]() |
296ee4961e | ||
![]() |
b1becddf11 | ||
![]() |
667edcd9d0 | ||
![]() |
b4e75bedf0 | ||
![]() |
5482ef5451 | ||
![]() |
f254831aa6 | ||
![]() |
bd40c8649c | ||
![]() |
7c53df2ed1 | ||
![]() |
5ca6026787 | ||
![]() |
483daa5882 | ||
![]() |
e2bc92d128 | ||
![]() |
5ffe3773d4 | ||
![]() |
a7c68018a2 | ||
![]() |
5ffb82993e | ||
![]() |
07add0bd91 | ||
![]() |
9a9b6fa326 | ||
![]() |
ba43ec5759 | ||
![]() |
008a9560fe | ||
![]() |
6ff01cc72c | ||
![]() |
031410c72b | ||
![]() |
710def8e38 | ||
![]() |
c0bda1b103 | ||
![]() |
0e87ce4680 | ||
![]() |
b4d594eeff | ||
![]() |
ce09379bae | ||
![]() |
b27fb64317 | ||
![]() |
099455db25 | ||
![]() |
3146bf51e6 | ||
![]() |
b24a5e0662 | ||
![]() |
e52ac0b187 | ||
![]() |
eaa1590866 | ||
![]() |
071af004bd | ||
![]() |
23ab4e5e5f | ||
![]() |
8e563cbccd | ||
![]() |
1aee89f5ea | ||
![]() |
fb547260d1 | ||
![]() |
2065e32904 | ||
![]() |
ac15581c56 | ||
![]() |
9e2e882157 | ||
![]() |
99ded56047 | ||
![]() |
65386f52f0 | ||
![]() |
5b8dce7456 | ||
![]() |
de938eb621 | ||
![]() |
83cc6c0835 | ||
![]() |
304d78a4c8 | ||
![]() |
347590751c | ||
![]() |
fe4b1f96f1 | ||
![]() |
9de984f7f8 | ||
![]() |
b6cb9b853a | ||
![]() |
50b930f283 | ||
![]() |
cbeb809798 | ||
![]() |
ea626368a0 | ||
![]() |
c81747dd15 | ||
![]() |
f8810d7caf | ||
![]() |
92f54f0b59 | ||
![]() |
ddce544b53 | ||
![]() |
21fb7eea82 | ||
![]() |
fd7eb43366 | ||
![]() |
7d0ca894a4 | ||
![]() |
a1add27c4c | ||
![]() |
fc8194ee1e | ||
![]() |
8ffcdb73e8 | ||
![]() |
111528e51c | ||
![]() |
5628dcf47e | ||
![]() |
fb4f02cd38 | ||
![]() |
d1be643c0d | ||
![]() |
c9761bf6af | ||
![]() |
4a47265224 | ||
![]() |
f0f3017a76 | ||
![]() |
d3f0b62348 | ||
![]() |
6a53fb33da | ||
![]() |
dcaf299864 | ||
![]() |
ab2e00bc38 | ||
![]() |
48d02bef15 | ||
![]() |
1d67aa7bf2 | ||
![]() |
e56066f721 | ||
![]() |
5e3844ac13 | ||
![]() |
cb4f5d454b | ||
![]() |
e5c6fe1bb2 | ||
![]() |
bf65a9732c | ||
![]() |
1388b3219a | ||
![]() |
d9e8ce22cb | ||
![]() |
c85ba73371 | ||
![]() |
224944528f | ||
![]() |
cdcd3e77b3 | ||
![]() |
ed5058a363 | ||
![]() |
a670ff6d3e | ||
![]() |
32f6d34904 | ||
![]() |
d3ae05506d | ||
![]() |
96f4394dce | ||
![]() |
35567e6507 | ||
![]() |
ae37e25452 | ||
![]() |
c4537fe6f6 | ||
![]() |
677334f5a9 | ||
![]() |
3d9652ae35 | ||
![]() |
a9130cb99c | ||
![]() |
b1d60b5c85 | ||
![]() |
99a05c56ad | ||
![]() |
cfc65397b3 | ||
![]() |
cd8fd1ef42 | ||
![]() |
6350089e51 | ||
![]() |
8e5a67ed9f | ||
![]() |
cccbcf510a | ||
![]() |
a1e680fec7 | ||
![]() |
1b58bd64ff | ||
![]() |
196de8c758 | ||
![]() |
222b777552 | ||
![]() |
b5c206d3ae | ||
![]() |
17ace95268 | ||
![]() |
779d73f94b | ||
![]() |
73307bf2e7 | ||
![]() |
7623c1c5cb | ||
![]() |
de568c84c2 | ||
![]() |
1f5b9c6185 | ||
![]() |
a5f8fd774d | ||
![]() |
cc5443c38e | ||
![]() |
8a86460b8f | ||
![]() |
7ae9e49f51 | ||
![]() |
c682d087d9 | ||
![]() |
57da5c0841 | ||
![]() |
a224722ae2 | ||
![]() |
283ef5b163 | ||
![]() |
09a188bfd9 | ||
![]() |
10f086854b | ||
![]() |
d67c6c37e3 | ||
![]() |
136725dfb1 | ||
![]() |
438895842c | ||
![]() |
82b8f4f1ce | ||
![]() |
0705f42cf8 | ||
![]() |
cadc67ea40 | ||
![]() |
054e9ecaae | ||
![]() |
84fe3bfa87 | ||
![]() |
2ef8403bfa | ||
![]() |
1d3b2baee7 | ||
![]() |
86de876b24 | ||
![]() |
8a9f04f7fe | ||
![]() |
98bd4dfe04 | ||
![]() |
8e0e4d7c04 | ||
![]() |
a5e8269c72 | ||
![]() |
0acc88cde5 | ||
![]() |
3392cbbd91 | ||
![]() |
e7b211f2c0 | ||
![]() |
6c5bc9b4a3 | ||
![]() |
cd2f65aafc | ||
![]() |
3ee5093b03 | ||
![]() |
6e2ad6860f | ||
![]() |
8610eb84c6 | ||
![]() |
a2e008347c | ||
![]() |
a1ef0159e3 | ||
![]() |
1c5f76635a | ||
![]() |
e2a0fd7a28 | ||
![]() |
5869a4ba2d | ||
![]() |
ac9a93261b | ||
![]() |
4b79f0047d | ||
![]() |
6a789b660a | ||
![]() |
0d8e44a079 | ||
![]() |
f097952b42 | ||
![]() |
224d511616 | ||
![]() |
050c6cc4b0 | ||
![]() |
bc2d23ff0d | ||
![]() |
2939fadd6a | ||
![]() |
ef260377c3 | ||
![]() |
b9213df64b | ||
![]() |
aa7694047b | ||
![]() |
e2bc63217a | ||
![]() |
6c5b8bcf9d | ||
![]() |
e425fe3f97 | ||
![]() |
6507993972 | ||
![]() |
f081696f62 | ||
![]() |
09157c3130 | ||
![]() |
00626b1633 | ||
![]() |
7e0cdbe502 | ||
![]() |
ca08902d71 | ||
![]() |
fad0e834d5 | ||
![]() |
dc76eb6139 | ||
![]() |
55e113c7a7 | ||
![]() |
b62f5e079e | ||
![]() |
ac1eaff6ec | ||
![]() |
45f6129ae7 | ||
![]() |
f3503e0026 | ||
![]() |
826a654c95 | ||
![]() |
08754e6ce7 | ||
![]() |
3843972b05 | ||
![]() |
37862f0f20 | ||
![]() |
1f184f4aec | ||
![]() |
db5a691693 | ||
![]() |
48693250a4 | ||
![]() |
570dcb6309 | ||
![]() |
19e43087a8 | ||
![]() |
fe0b6a1117 | ||
![]() |
72851647ca | ||
![]() |
1c90400081 | ||
![]() |
672e18cac9 | ||
![]() |
e939d667d9 | ||
![]() |
8bb5a565cd | ||
![]() |
7562c5751c | ||
![]() |
e6e7d6dbd6 | ||
![]() |
fe60c52c70 | ||
![]() |
93f4590453 | ||
![]() |
1098d271b8 | ||
![]() |
51168169e7 | ||
![]() |
d256a0e98f | ||
![]() |
6717325c3f | ||
![]() |
c4a0571e7a | ||
![]() |
e4a06da14e | ||
![]() |
36d6ead65c | ||
![]() |
7eae3bc8c5 | ||
![]() |
24b2198668 | ||
![]() |
d29be0f460 | ||
![]() |
8f93c36466 | ||
![]() |
3092e5a8a5 | ||
![]() |
55f95b3ac9 | ||
![]() |
16218c8680 | ||
![]() |
c11345c4d9 | ||
![]() |
e31f0b8b0c | ||
![]() |
7dd3b72a8c | ||
![]() |
aeccccb33d | ||
![]() |
b46a27c554 | ||
![]() |
13bc15c05d | ||
![]() |
cb1e644230 | ||
![]() |
9bc0fada5c | ||
![]() |
019aea3d63 | ||
![]() |
21439108ed | ||
![]() |
754b30a7a6 | ||
![]() |
89d5d480d7 | ||
![]() |
fbcacb590b | ||
![]() |
f97ad2b2ee | ||
![]() |
e70f7141be | ||
![]() |
7a08ce7ece | ||
![]() |
86486336ec | ||
![]() |
ec2a2522aa | ||
![]() |
556f9ee39c | ||
![]() |
7dad662d69 | ||
![]() |
2daa3eb61f | ||
![]() |
3079aa1f9d | ||
![]() |
28f9a0a900 | ||
![]() |
a6bb3cf60a | ||
![]() |
004da5d385 | ||
![]() |
0368282486 | ||
![]() |
4404f20cf4 | ||
![]() |
faca8bc02a | ||
![]() |
5e93c05095 | ||
![]() |
0f4f04eaa4 | ||
![]() |
2e55d561d3 | ||
![]() |
76a9049739 | ||
![]() |
27bfcda20d | ||
![]() |
c6d1d360a3 | ||
![]() |
afc1236b06 | ||
![]() |
bedd5f00f8 | ||
![]() |
36239895bd | ||
![]() |
738583e3d4 | ||
![]() |
c513478c31 | ||
![]() |
a944927b56 | ||
![]() |
b9a8b0d146 | ||
![]() |
4d15db0134 | ||
![]() |
0d1a54262c | ||
![]() |
e7ef7f5159 | ||
![]() |
3dc989bccb | ||
![]() |
75d46efd23 | ||
![]() |
b83392cb04 | ||
![]() |
7640d333f4 | ||
![]() |
c880099deb | ||
![]() |
42f5ecd4a1 | ||
![]() |
733989a284 | ||
![]() |
493f74d94d | ||
![]() |
3b71e2abef | ||
![]() |
30cad0c5f1 | ||
![]() |
3a387643b3 | ||
![]() |
e6b37703da | ||
![]() |
990f473bb3 | ||
![]() |
cf1de78205 | ||
![]() |
ccea6dd74b | ||
![]() |
166b490eed | ||
![]() |
efd871ad2f | ||
![]() |
b78896d64e | ||
![]() |
e753c924ef | ||
![]() |
9dc7b5a6d9 | ||
![]() |
f5d21c9cdb | ||
![]() |
6ce13646da | ||
![]() |
151653dd98 | ||
![]() |
619cfe6a1c | ||
![]() |
8acf996d90 | ||
![]() |
15e432204e | ||
![]() |
4b1630e1ec | ||
![]() |
41e63031b0 | ||
![]() |
bb86f27fdf | ||
![]() |
5cf4f62610 | ||
![]() |
8e10a14866 | ||
![]() |
94f850a588 | ||
![]() |
3882c11450 | ||
![]() |
08f77c2b60 | ||
![]() |
6269abbcc8 | ||
![]() |
22ebe0e58f | ||
![]() |
f072cbbba7 | ||
![]() |
1a5b66b78d | ||
![]() |
bea5973e0c | ||
![]() |
0366dcf604 | ||
![]() |
8211d4a1c2 | ||
![]() |
fc2154ee92 | ||
![]() |
76f85e6f7b | ||
![]() |
81ce684b35 | ||
![]() |
42bd888946 | ||
![]() |
6bea346c41 | ||
![]() |
8d23706354 | ||
![]() |
62bfb1a273 | ||
![]() |
38e86af75c | ||
![]() |
607c2c5ba2 | ||
![]() |
85f58eb082 | ||
![]() |
54383b017e | ||
![]() |
438b7b7bd0 | ||
![]() |
27a40a9843 | ||
![]() |
c7b0e9b05b | ||
![]() |
356c829b76 | ||
![]() |
ffbb5c48ed | ||
![]() |
6b6c7b0920 | ||
![]() |
de332a16d1 | ||
![]() |
84ab3ee3af | ||
![]() |
ce0d896492 | ||
![]() |
eae9cb4afe | ||
![]() |
459a812a54 | ||
![]() |
7743647460 | ||
![]() |
352ec364f0 | ||
![]() |
54f684b7b3 | ||
![]() |
1943b158fe | ||
![]() |
a36eeb5261 | ||
![]() |
a8b00faba1 | ||
![]() |
bf73d0f905 | ||
![]() |
193ffa06d9 | ||
![]() |
9d176e35d4 | ||
![]() |
cd2e8c6ef1 | ||
![]() |
8461d71b52 | ||
![]() |
e31cdf0df9 | ||
![]() |
6f41791ea6 | ||
![]() |
0bacbcd04e | ||
![]() |
ffe689363f | ||
![]() |
48d7fedbc0 | ||
![]() |
75dff64450 | ||
![]() |
f0b58c6f24 | ||
![]() |
f3661b19c0 | ||
![]() |
2f5106c97f | ||
![]() |
0c19418e84 | ||
![]() |
60c077c790 | ||
![]() |
7aaa4dda22 | ||
![]() |
109b3700b5 | ||
![]() |
71fecf4d1f | ||
![]() |
0f75c79665 | ||
![]() |
9bcb01a75e | ||
![]() |
4f29034f11 | ||
![]() |
567bf445bf | ||
![]() |
28a0c46ca7 | ||
![]() |
7cc33d0f27 | ||
![]() |
5fba8d773c | ||
![]() |
36cd73df51 | ||
![]() |
6f20889f00 | ||
![]() |
8e408725e9 | ||
![]() |
d053797340 | ||
![]() |
c8d0f947d2 | ||
![]() |
86e036c393 | ||
![]() |
7652a2986b | ||
![]() |
b1480167be | ||
![]() |
e118e958f7 | ||
![]() |
ee61dfe087 | ||
![]() |
9231f420c1 | ||
![]() |
0f92d021a1 | ||
![]() |
cbdc3194cc | ||
![]() |
993df0fd28 | ||
![]() |
4294fdb0b2 | ||
![]() |
082523bcea | ||
![]() |
5d13c13821 | ||
![]() |
21ef656e24 | ||
![]() |
3c4fe8cc04 | ||
![]() |
95ebd57b25 | ||
![]() |
84e09aa8dd | ||
![]() |
6cce3d2996 | ||
![]() |
77b34fa961 | ||
![]() |
024d978ae5 | ||
![]() |
e0f55b9295 | ||
![]() |
ccd83748f7 | ||
![]() |
291ee9f86a | ||
![]() |
59e4d7f0f5 | ||
![]() |
4647448399 | ||
![]() |
7dfe841876 | ||
![]() |
34db35c36d | ||
![]() |
3e9738dc66 | ||
![]() |
2ecf57cdd9 | ||
![]() |
c8b602038e | ||
![]() |
e384fa226e | ||
![]() |
cbb595ba83 | ||
![]() |
fdeec0307e | ||
![]() |
f084bbbf35 | ||
![]() |
20d69b957f | ||
![]() |
7de0a621e3 | ||
![]() |
3441ea9844 | ||
![]() |
83752e9349 | ||
![]() |
8fdfe85b5f | ||
![]() |
d4d9a85ad8 | ||
![]() |
6f22452b54 | ||
![]() |
a4a37d7a19 | ||
![]() |
d1b1a8e490 | ||
![]() |
104fe124df | ||
![]() |
5bdbd74d59 | ||
![]() |
e621c24270 | ||
![]() |
554888318a | ||
![]() |
49aaf98a7f | ||
![]() |
ccdb94b06c | ||
![]() |
6f7bfa71a9 | ||
![]() |
fb3564fbe7 | ||
![]() |
e1e365e16e | ||
![]() |
5b5a18db2a | ||
![]() |
3fa4dad418 | ||
![]() |
0756607e32 | ||
![]() |
a03be5a8a6 | ||
![]() |
39c5bb95d2 | ||
![]() |
4d33b089da | ||
![]() |
58996b841a | ||
![]() |
df03a7b3f8 | ||
![]() |
ac03871174 | ||
![]() |
2a086d20c6 | ||
![]() |
d5cfa6d4dc | ||
![]() |
f415167e59 | ||
![]() |
9477db2363 | ||
![]() |
8d11577ff2 | ||
![]() |
037d1d9ad1 | ||
![]() |
619ef2b341 | ||
![]() |
f06fe76d35 | ||
![]() |
eb86fdfbea | ||
![]() |
c7712e2ef0 | ||
![]() |
61fa770644 | ||
![]() |
334bd73792 | ||
![]() |
090ce262c4 | ||
![]() |
d551d40886 | ||
![]() |
aecfcaa8a2 | ||
![]() |
61a3028788 | ||
![]() |
11d048b8e3 | ||
![]() |
d814a01f2a | ||
![]() |
4c0916df79 | ||
![]() |
e4844b9936 | ||
![]() |
60aa8c527b | ||
![]() |
9f7c3b8ea6 | ||
![]() |
9f4f1bab39 | ||
![]() |
73bd6af0f9 | ||
![]() |
2aa54c5365 | ||
![]() |
bc8542503d | ||
![]() |
a6aea4ba58 | ||
![]() |
0b41faec89 | ||
![]() |
e12bd00b47 | ||
![]() |
50eac9b49e | ||
![]() |
e0405f1781 | ||
![]() |
680d03e4d6 | ||
![]() |
b4fc2e38ab | ||
![]() |
16639f9d71 | ||
![]() |
22f2605e25 | ||
![]() |
69476b4f21 | ||
![]() |
fdf92c5f3b | ||
![]() |
5e22c83baa | ||
![]() |
eed1a3c239 | ||
![]() |
94c037821b | ||
![]() |
e38e8eb636 | ||
![]() |
bef8c83388 | ||
![]() |
2e98324486 | ||
![]() |
6e2d7445c5 | ||
![]() |
90e7ace980 | ||
![]() |
2b0a127fa5 | ||
![]() |
07c5d3277f | ||
![]() |
d1d44a4fde | ||
![]() |
6837a67234 | ||
![]() |
d6eb74262a | ||
![]() |
403aa8c5a1 | ||
![]() |
cd1148c6aa | ||
![]() |
cfd26f53f0 | ||
![]() |
69ad5671ed | ||
![]() |
f9e0f0d257 | ||
![]() |
98f3135ad3 | ||
![]() |
8c9c3a91e6 | ||
![]() |
7f3518333d | ||
![]() |
f1f871f103 | ||
![]() |
6387b52896 | ||
![]() |
077e95da85 | ||
![]() |
7f6e1fbc8d | ||
![]() |
06827cfcf1 | ||
![]() |
6dc3097998 | ||
![]() |
cd35271698 | ||
![]() |
7b575f61d0 | ||
![]() |
400e3ea649 | ||
![]() |
622d871587 | ||
![]() |
63d04645c7 | ||
![]() |
3f4908c363 | ||
![]() |
dd0f1d9d2d | ||
![]() |
b31d171ae8 | ||
![]() |
085f06594c | ||
![]() |
ce3d41052c | ||
![]() |
44f3df697f | ||
![]() |
28c75b2283 | ||
![]() |
b6e56119c4 | ||
![]() |
a0e29b5435 | ||
![]() |
65ff72cdf8 | ||
![]() |
1da0956331 | ||
![]() |
983078992d | ||
![]() |
81059f80d8 | ||
![]() |
a261442279 | ||
![]() |
2f41eba100 | ||
![]() |
91a6fb81c1 | ||
![]() |
c95f0820bc | ||
![]() |
830a1bd130 | ||
![]() |
5c5ea8a254 | ||
![]() |
5222c684d3 | ||
![]() |
5798faa13b | ||
![]() |
a062693875 | ||
![]() |
6887d5d347 | ||
![]() |
39c9669445 | ||
![]() |
44565e22a0 | ||
![]() |
ddec10d494 | ||
![]() |
758e969cb6 | ||
![]() |
a9a6a5041b | ||
![]() |
59dd8ffbc6 | ||
![]() |
8f9fe1b11a | ||
![]() |
9ed0152cf2 | ||
![]() |
250332a8d5 | ||
![]() |
39825c6622 | ||
![]() |
cee3070ca4 | ||
![]() |
cd08e5c7da | ||
![]() |
dd4beea44c | ||
![]() |
5b48d59769 | ||
![]() |
4dec12fcfc | ||
![]() |
57ad3aca8e | ||
![]() |
f677f42be7 | ||
![]() |
a5760670ef | ||
![]() |
f04a3ec201 | ||
![]() |
f402c5fe3c | ||
![]() |
9352e25392 | ||
![]() |
1c90b0c19d | ||
![]() |
cd776ff1a8 | ||
![]() |
40a587bbaf | ||
![]() |
818d729d8b | ||
![]() |
dd5daa0767 | ||
![]() |
ef5090c397 | ||
![]() |
cf073de36c | ||
![]() |
f16054639b | ||
![]() |
b0983e8708 | ||
![]() |
0febb218ed | ||
![]() |
dfcfeeb550 | ||
![]() |
820debf45a | ||
![]() |
c19292c036 | ||
![]() |
4ee81e6a3d | ||
![]() |
87a8a3e22f | ||
![]() |
e9125ef8e4 | ||
![]() |
6ff394bcc9 | ||
![]() |
7ce96585f5 | ||
![]() |
41cc31c124 | ||
![]() |
605af61a0f | ||
![]() |
77e163e5b8 | ||
![]() |
0e00b9009d | ||
![]() |
a6dd998d31 | ||
![]() |
cdd0ccc67a | ||
![]() |
a918821868 | ||
![]() |
c637b96f10 | ||
![]() |
44b9197354 | ||
![]() |
7a8f96b1dd | ||
![]() |
f4f21f462d | ||
![]() |
d09b8b5bd7 | ||
![]() |
ee327db517 | ||
![]() |
90a61b6bab | ||
![]() |
00583bc4a8 | ||
![]() |
2d06a8e880 | ||
![]() |
e1a434edbc | ||
![]() |
6b3b1cbd99 | ||
![]() |
4dd861ee23 | ||
![]() |
4f0f81a047 | ||
![]() |
e3908c8de6 | ||
![]() |
81c49fba03 | ||
![]() |
eb174d5ba3 | ||
![]() |
4c899e9c5a | ||
![]() |
00b0f6ad51 | ||
![]() |
fe1e467a49 | ||
![]() |
73cb538d72 | ||
![]() |
64b9e7fd48 | ||
![]() |
12de22d3bb | ||
![]() |
821bc6d777 | ||
![]() |
6e66a5b77b | ||
![]() |
cf5c10bbe6 | ||
![]() |
4e30e74739 | ||
![]() |
42890b9acf | ||
![]() |
33a27379f9 | ||
![]() |
0cf57cc7ca | ||
![]() |
68fcbaf4c8 | ||
![]() |
9c83d3c78c | ||
![]() |
676dfabc91 | ||
![]() |
60e6d1d61b | ||
![]() |
975e275030 | ||
![]() |
afcd5670e3 | ||
![]() |
b17b53955c | ||
![]() |
ff2b427cc1 | ||
![]() |
a62fe30546 | ||
![]() |
25ebb427da | ||
![]() |
c5bde10b4f | ||
![]() |
e582e893cc | ||
![]() |
833ec3d3cd | ||
![]() |
3d446d3266 | ||
![]() |
e660229c40 | ||
![]() |
ee6e0e16cb | ||
![]() |
eb1733609a | ||
![]() |
e2e66404d5 | ||
![]() |
3ecb19d0f1 | ||
![]() |
fd02c87fa2 | ||
![]() |
63ac81c8f5 | ||
![]() |
557bee61d5 | ||
![]() |
8bfb88840b | ||
![]() |
593bb5a8a7 | ||
![]() |
822ac7b100 | ||
![]() |
cc70c5c67d | ||
![]() |
ae7e1a22cb | ||
![]() |
16944b5397 | ||
![]() |
72e44d596f | ||
![]() |
8f2ca8f085 | ||
![]() |
6725c2afa1 | ||
![]() |
e9d4b73cc3 | ||
![]() |
929ec70512 | ||
![]() |
6cd5d73607 | ||
![]() |
80a7e1ea7d | ||
![]() |
0d3b26b3aa | ||
![]() |
52acea7b1f | ||
![]() |
e9b49a43e2 | ||
![]() |
4fa5538e2b | ||
![]() |
84e74173de | ||
![]() |
6cdb2a4896 | ||
![]() |
d8bef3270d | ||
![]() |
a33db8fe6f | ||
![]() |
1c3f5517fa | ||
![]() |
10972da060 | ||
![]() |
a38f02541d | ||
![]() |
fdba76ba47 | ||
![]() |
f900ab0121 | ||
![]() |
f80ab6a7a2 | ||
![]() |
6ed209bbf3 | ||
![]() |
fe85fa3bea | ||
![]() |
76b7882f33 | ||
![]() |
bf0ab2d44c | ||
![]() |
bcbfa560e9 | ||
![]() |
8b366f0795 | ||
![]() |
aa08f9692c | ||
![]() |
288ba84939 | ||
![]() |
4c74016b1a | ||
![]() |
1d8544ef3b | ||
![]() |
91a12f76cd | ||
![]() |
f4627acc48 | ||
![]() |
2b1194d574 | ||
![]() |
e8debd2e45 | ||
![]() |
1caa41a623 | ||
![]() |
bf59635280 | ||
![]() |
5d6f75aaef | ||
![]() |
eaf0662b75 | ||
![]() |
6e8ea2a2cb | ||
![]() |
b043b2a761 | ||
![]() |
ac7e0dfb77 | ||
![]() |
05d47bb09a | ||
![]() |
575a5bd0b8 | ||
![]() |
ae4c189e19 | ||
![]() |
362a6e6d46 | ||
![]() |
c76c7c68ff | ||
![]() |
59ac9d39d5 | ||
![]() |
ec41caade4 | ||
![]() |
06ec06cdd7 | ||
![]() |
b7acf86408 | ||
![]() |
58c4db925b | ||
![]() |
fe0c4ff3c2 | ||
![]() |
7a2af0fbf4 | ||
![]() |
d83127722f | ||
![]() |
dc03ad05be | ||
![]() |
a62df3cb8f | ||
![]() |
18e32abda9 | ||
![]() |
15d29da43b | ||
![]() |
8b217d5313 | ||
![]() |
ac62586bad | ||
![]() |
c150fd9a1c | ||
![]() |
674d14879f | ||
![]() |
81df45a893 | ||
![]() |
c1f0708a5d | ||
![]() |
153f5854e2 | ||
![]() |
f532964fde | ||
![]() |
efea609dc3 | ||
![]() |
f3a160038d | ||
![]() |
f016eef48a | ||
![]() |
f649514183 | ||
![]() |
afd31677dd | ||
![]() |
b28710b08c | ||
![]() |
712ed555e6 | ||
![]() |
11fb5bc3d0 | ||
![]() |
2a5feb225b | ||
![]() |
970e338847 | ||
![]() |
0b9f650fe2 | ||
![]() |
977834179a | ||
![]() |
b42732743d | ||
![]() |
99e6409a67 | ||
![]() |
6a0a5f9693 | ||
![]() |
fe9db8b369 | ||
![]() |
ca035d0e8d | ||
![]() |
84c9260dc4 | ||
![]() |
987c02e946 | ||
![]() |
5c0bc612fe | ||
![]() |
0e28b53242 | ||
![]() |
5fc0ce80fc | ||
![]() |
af9092df39 | ||
![]() |
58a5da33c2 | ||
![]() |
7077eac589 | ||
![]() |
b3435ae432 | ||
![]() |
a31129333c | ||
![]() |
2983c2a24f | ||
![]() |
412bedb697 | ||
![]() |
d37811f177 | ||
![]() |
d4ca853fd3 | ||
![]() |
5a8d2e8057 | ||
![]() |
687fc358fd | ||
![]() |
c4c2da06b7 | ||
![]() |
8928cd53bf | ||
![]() |
ca88fc4ed3 | ||
![]() |
b83a1d79b7 | ||
![]() |
cec2a837cf | ||
![]() |
cff47262da | ||
![]() |
da83eae754 | ||
![]() |
c5409d52f5 | ||
![]() |
54fc8f0e8c | ||
![]() |
2ea633a2f7 | ||
![]() |
9a52043fad | ||
![]() |
39a5be2df9 | ||
![]() |
96560e317a | ||
![]() |
adb27903eb | ||
![]() |
51150faa39 | ||
![]() |
ea96919b80 | ||
![]() |
5835afb849 | ||
![]() |
7f3fecbdf5 | ||
![]() |
a2c6d5e148 | ||
![]() |
373706c92b | ||
![]() |
7afe63aa06 | ||
![]() |
8fab855099 | ||
![]() |
062fef36f9 | ||
![]() |
fefe2df3ee | ||
![]() |
90b91ead72 | ||
![]() |
1e98e41381 | ||
![]() |
7030e8f050 | ||
![]() |
74bb514a8c | ||
![]() |
46914e486c | ||
![]() |
f9abc561fb | ||
![]() |
2e22ff2e36 | ||
![]() |
8c3be4a5f0 | ||
![]() |
3fe2f7337c | ||
![]() |
ec24eb1d8e | ||
![]() |
ffcaf85609 | ||
![]() |
d0c481e44e | ||
![]() |
67e2d9f9e1 | ||
![]() |
dd5aa2b483 | ||
![]() |
806494a254 | ||
![]() |
5c3afd020a | ||
![]() |
190cdfc326 | ||
![]() |
13b954c765 | ||
![]() |
49f6b50ed3 | ||
![]() |
0f2a304d34 | ||
![]() |
a142f93dca | ||
![]() |
2dfe2fb22c | ||
![]() |
e8564b4c90 | ||
![]() |
2fd81b4932 | ||
![]() |
0cf4c6ffea | ||
![]() |
25f89afbfb | ||
![]() |
43f3cdcd24 | ||
![]() |
3454fed324 | ||
![]() |
a64ffda688 | ||
![]() |
8400da9934 | ||
![]() |
ae8bdd473c | ||
![]() |
adfc5db3d2 | ||
![]() |
3f32a6b607 | ||
![]() |
21aa1631a4 | ||
![]() |
49968541fd | ||
![]() |
cc143105b8 | ||
![]() |
fed44e95b3 | ||
![]() |
71ece56470 | ||
![]() |
204a1de3fd | ||
![]() |
80ddf4aecf | ||
![]() |
12b4a666bc | ||
![]() |
cfdbaf331e | ||
![]() |
052d350b19 | ||
![]() |
2ca18a7ee5 | ||
![]() |
7dbe5f4640 | ||
![]() |
432ecd1b6a | ||
![]() |
7d9aa5b716 | ||
![]() |
43267dc892 | ||
![]() |
3ec6c26e6c | ||
![]() |
7de684668b | ||
![]() |
4741d7bfe2 | ||
![]() |
aea99a1222 | ||
![]() |
7c8038e2da | ||
![]() |
673336297d | ||
![]() |
ee4b7042ce | ||
![]() |
310ab7d41b | ||
![]() |
fc1796f3e8 | ||
![]() |
d8926ea5eb | ||
![]() |
0c1e428c7d | ||
![]() |
bcd97f5887 | ||
![]() |
0faf86c2b9 | ||
![]() |
b30957c89c | ||
![]() |
dbbcbc3616 | ||
![]() |
1889150013 | ||
![]() |
14f9cdde6b | ||
![]() |
3ab0691eec | ||
![]() |
1e073a196f | ||
![]() |
7b60e3916c | ||
![]() |
c486c5bf5b | ||
![]() |
fc0b6d143a | ||
![]() |
5f4252bcd2 | ||
![]() |
a588aef921 | ||
![]() |
b70df57f7b | ||
![]() |
e813c93e08 | ||
![]() |
900c4977cc | ||
![]() |
bb39fffab9 | ||
![]() |
f52aefb341 | ||
![]() |
aecb5630cb | ||
![]() |
0f0245625a | ||
![]() |
8583689fa4 | ||
![]() |
7a1e026bb5 | ||
![]() |
64f04ee6db | ||
![]() |
5c6f538b85 | ||
![]() |
00aa83a498 | ||
![]() |
e44848f8c4 | ||
![]() |
5ea8950a13 | ||
![]() |
184557bfed | ||
![]() |
b4253210d2 | ||
![]() |
8e1585aa8a | ||
![]() |
dee49d7488 | ||
![]() |
1ecde309e4 | ||
![]() |
d62a738460 | ||
![]() |
0f1b1bb44d | ||
![]() |
16f870aa41 | ||
![]() |
16f729eb22 | ||
![]() |
36f0bd432c | ||
![]() |
457ab8b2ce | ||
![]() |
1ebf5f3bcb | ||
![]() |
a928a9640f | ||
![]() |
cb302476b4 | ||
![]() |
31726737df | ||
![]() |
082be33cbd | ||
![]() |
9aada2ef19 | ||
![]() |
4066b2767b | ||
![]() |
de43bddc1a | ||
![]() |
6edfc56c9d | ||
![]() |
5837a63942 | ||
![]() |
3a28f456b1 | ||
![]() |
4f6fc2675c | ||
![]() |
c7da1821c3 | ||
![]() |
1a8c3271da | ||
![]() |
bd49e8e76f | ||
![]() |
533699abe7 | ||
![]() |
267ccc98d3 | ||
![]() |
cd3c2fdb49 | ||
![]() |
5cbc319e96 | ||
![]() |
d435dcdca4 | ||
![]() |
e5ab456df3 | ||
![]() |
08bf4f74a9 | ||
![]() |
a838a03412 | ||
![]() |
ad4e597f74 | ||
![]() |
ee3610a2d2 | ||
![]() |
88b75b57d0 | ||
![]() |
aa4c7055f8 | ||
![]() |
4b70f9d213 | ||
![]() |
79d2d1c201 | ||
![]() |
406bda9b95 | ||
![]() |
405f1dd027 | ||
![]() |
51f349d504 | ||
![]() |
4f201d1e85 | ||
![]() |
03cfef100f | ||
![]() |
ff89b491dd | ||
![]() |
7552dff0e5 | ||
![]() |
110589c0f3 | ||
![]() |
3400398230 | ||
![]() |
5c244e9a8c | ||
![]() |
4e2f4e2091 | ||
![]() |
e69bef3ce3 | ||
![]() |
c1c0fc79bc | ||
![]() |
02a77f6797 | ||
![]() |
77b316cdfb | ||
![]() |
2abfc7b87b | ||
![]() |
050f0c3d8f | ||
![]() |
90e6c727da | ||
![]() |
d3d9a04e62 | ||
![]() |
a66051216f | ||
![]() |
0debba0f6e | ||
![]() |
f2bd2c318c | ||
![]() |
21c42819c7 | ||
![]() |
5899a272ef | ||
![]() |
27b4c62bc1 | ||
![]() |
b227fddec7 | ||
![]() |
2c1f1de33c | ||
![]() |
c26622cf8f | ||
![]() |
9e91873428 | ||
![]() |
7363d50a1e | ||
![]() |
15213a041d | ||
![]() |
fb70a34c80 | ||
![]() |
fbf76c6d21 | ||
![]() |
bc00c38f9d | ||
![]() |
4658bd8208 | ||
![]() |
6eb1caa417 | ||
![]() |
41efc1376e | ||
![]() |
0f35016773 | ||
![]() |
c641ca90a9 | ||
![]() |
87c88fcb27 | ||
![]() |
4f80a129f1 | ||
![]() |
6987f2ba82 | ||
![]() |
563db580ae | ||
![]() |
125daea16a | ||
![]() |
fd2c6b8a4b | ||
![]() |
5b1db917bc | ||
![]() |
849b0563ce | ||
![]() |
16a99ad515 | ||
![]() |
d93172bee8 | ||
![]() |
25429af122 | ||
![]() |
4bfd104a23 | ||
![]() |
7745067d99 | ||
![]() |
b19d3629b9 | ||
![]() |
84c519df09 | ||
![]() |
737a56a030 | ||
![]() |
12b6959ea2 | ||
![]() |
7519768cb1 | ||
![]() |
9af470c92d | ||
![]() |
ac8c1d0a01 | ||
![]() |
921d01b59d | ||
![]() |
8aa4a66ba0 | ||
![]() |
2e7153d8d6 | ||
![]() |
70b5a81a29 | ||
![]() |
83fd822e8b | ||
![]() |
dd3752956a | ||
![]() |
bf15cac980 | ||
![]() |
1a61b01315 | ||
![]() |
c643b6ff16 | ||
![]() |
b3f5b4932c | ||
![]() |
b3f5f2f75f | ||
![]() |
62288907dd | ||
![]() |
cdbdcec715 | ||
![]() |
ccf78448aa | ||
![]() |
ed001e0cfb | ||
![]() |
26382713c2 | ||
![]() |
f37481f843 | ||
![]() |
c3f6502be2 | ||
![]() |
0120f396ac | ||
![]() |
231fffe594 | ||
![]() |
e67afc35b8 | ||
![]() |
5e73007b1d | ||
![]() |
2d9876a261 | ||
![]() |
303d67aed2 | ||
![]() |
575fbad254 | ||
![]() |
fa0aa91bf9 | ||
![]() |
3e641e2147 | ||
![]() |
de7e4f0db7 | ||
![]() |
a1cb1d78bd | ||
![]() |
1178f2c1ab | ||
![]() |
76f277eeb4 | ||
![]() |
4000390dcd |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -35,7 +35,8 @@ tags
|
||||
/mkinstalldirs
|
||||
/build
|
||||
/src/mpd
|
||||
/systemd/mpd.service
|
||||
/systemd/system/mpd.service
|
||||
/systemd/user/mpd.service
|
||||
/stamp-h1
|
||||
|
||||
/src/dsd2pcm/dsd2pcm
|
||||
@@ -83,3 +84,5 @@ tags
|
||||
/*.tar.bz2
|
||||
/*.tar.xz
|
||||
/mpd-*/
|
||||
|
||||
__pycache__/
|
||||
|
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
dist: trusty
|
||||
language: cpp
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcppunit-dev
|
||||
- libboost-dev
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j2"
|
||||
|
||||
before_install:
|
||||
# C++14
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get update -qq
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || brew update
|
||||
|
||||
install:
|
||||
# C++14
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get install -qq g++-5
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || brew install cppunit
|
||||
|
||||
script:
|
||||
- OPTIONS="--enable-test"
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || export CC=gcc-5 CXX=g++-5
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || OPTIONS="$OPTIONS --enable-osx"
|
||||
- ./autogen.sh
|
||||
- ./configure --disable-silent-rules --disable-dependency-tracking $OPTIONS
|
||||
- make
|
||||
- make check
|
6
AUTHORS
6
AUTHORS
@@ -1,11 +1,11 @@
|
||||
Music Player Daemon - http://www.musicpd.org
|
||||
Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
Copyright 2003-2017 The Music Player Daemon Project
|
||||
|
||||
The following people have contributed code to MPD:
|
||||
|
||||
Warren Dukes <warren.dukes@gmail.com>
|
||||
Avuton Olrich <avuton@gmail.com>
|
||||
Max Kellermann <max@duempel.org>
|
||||
Max Kellermann <max.kellermann@gmail.com>
|
||||
Laszlo Ashin <kodest@gmail.com>
|
||||
Viliam Mateicka <viliam.mateicka@gmail.com>
|
||||
Eric Wollesen <encoded@xmtp.net>
|
||||
@@ -29,3 +29,5 @@ The following people have contributed code to MPD:
|
||||
Denis Krjuchkov <denis@crazydev.net>
|
||||
Jurgen Kramer <gtmkramer@xs4all.nl>
|
||||
Jean-Francois Dockes <jf@dockes.org>
|
||||
Yue Wang <yuleopen@gmail.com>
|
||||
Matthew Leon Grinshpun <ml@matthewleon.com>
|
||||
|
209
INSTALL
209
INSTALL
@@ -1,209 +0,0 @@
|
||||
Music Player Daemon (MPD) - INSTALL
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This document is a very small amount of documentation about what is needed to
|
||||
install MPD. If more information is desired, read the user manual:
|
||||
|
||||
http://www.musicpd.org/doc/user/
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
gcc 4.7 or later - http://gcc.gnu.org/
|
||||
clang 3.2 or later - http://clang.llvm.org/
|
||||
Any other C++11 compliant compiler should also work.
|
||||
|
||||
Boost 1.46 - http://www.boost.org/
|
||||
|
||||
GLib 2.28 - http://www.gtk.org/
|
||||
General-purpose utility library.
|
||||
|
||||
|
||||
Optional Output Dependencies
|
||||
----------------------------
|
||||
|
||||
You will need at least one of these to compile MPD.
|
||||
|
||||
Most of these are available as packages on major distributions. Be sure to
|
||||
install both the library package as well as the development package.
|
||||
|
||||
AO - http://www.xiph.org/ao/
|
||||
A portable library that abstracts many audio output types as one API. Should
|
||||
be used only if there is no native plugin available or if the native plugin
|
||||
doesn't work. You will need libao.
|
||||
|
||||
ALSA - http://www.alsa-project.org/
|
||||
The Advanced Linux Sound Architecture. Recommended audio output if you use
|
||||
Linux. You will need libasound.
|
||||
|
||||
FIFO
|
||||
This is a mostly undocumented, developer plugin to transmit raw data.
|
||||
|
||||
OSS - http://www.opensound.com
|
||||
Open Sound System.
|
||||
|
||||
PulseAudio - http://www.pulseaudio.org/
|
||||
An advanced sound daemon. You will need libpulse.
|
||||
|
||||
JACK - http://www.jackaudio.org/
|
||||
A low-latency sound daemon.
|
||||
|
||||
libshout - http://www.icecast.org/
|
||||
For streaming to an Icecast or Shoutcast server.
|
||||
You also need an encoder: either libvorbisenc (ogg), or liblame (mp3).
|
||||
|
||||
OpenAL - http://kcat.strangesoft.net/openal.html
|
||||
Open Audio Library
|
||||
|
||||
|
||||
Optional Input Dependencies
|
||||
---------------------------
|
||||
|
||||
You will need at least one of these to compile MPD.
|
||||
|
||||
Most of these are available as packages on major distributions. Be sure to
|
||||
install both the library package as well as the development package.
|
||||
|
||||
MAD - http://www.underbit.com/products/mad/
|
||||
For MP3 support. You will need libmad, and optionally libid3tag if you want
|
||||
ID3 tag support.
|
||||
|
||||
libmpg123 - http://www.mpg123.de/
|
||||
Alternative for MP3 support.
|
||||
|
||||
Ogg Vorbis - http://www.xiph.org/ogg/vorbis/
|
||||
For Ogg Vorbis support. You will need libogg and libvorbis.
|
||||
|
||||
libopus - http://www.opus-codec.org/
|
||||
Opus codec support
|
||||
|
||||
FLAC - http://flac.sourceforge.net/
|
||||
For FLAC support. You will need version 1.2 or higher of libFLAC.
|
||||
|
||||
Audio File - http://www.68k.org/~michael/audiofile/
|
||||
For WAVE, AIFF, and AU support. You will need libaudiofile.
|
||||
|
||||
FAAD2 - http://www.audiocoding.com/
|
||||
For MP4/AAC support.
|
||||
|
||||
libmpcdec - http://www.musepack.net/
|
||||
For Musepack support.
|
||||
|
||||
MikMod - http://mikmod.raphnet.net/
|
||||
For MOD support. You will need libmikmod.
|
||||
|
||||
libavcodec, libavformat (ffmpeg or libav) - http://ffmpeg.mplayerhq.hu/ http://libav.org/
|
||||
Multi-codec library.
|
||||
|
||||
libsidplay2 - http://sidplay2.sourceforge.net/
|
||||
For C64 SID support.
|
||||
|
||||
libfluidsynth - http://fluidsynth.resonance.org/
|
||||
For MIDI support.
|
||||
|
||||
libwildmidi 0.2.3 - http://wildmidi.sourceforge.net/
|
||||
For MIDI support.
|
||||
|
||||
libsndfile - http://www.mega-nerd.com/libsndfile/
|
||||
WAVE, AIFF, and many others.
|
||||
|
||||
libwavpack - http://www.wavpack.com/
|
||||
For WavPack playback.
|
||||
|
||||
libadplug - http://adplug.sourceforge.net/
|
||||
For AdLib playback.
|
||||
|
||||
|
||||
Optional Miscellaneous Dependencies
|
||||
-----------------------------------
|
||||
|
||||
Avahi - http://www.avahi.org/
|
||||
For Zeroconf support.
|
||||
|
||||
libsamplerate - http://www.mega-nerd.com/SRC/
|
||||
For advanced samplerate conversions.
|
||||
|
||||
libcurl - http://curl.haxx.se/
|
||||
For playing HTTP streams.
|
||||
|
||||
libmms - https://launchpad.net/libmms
|
||||
For playing MMS streams.
|
||||
|
||||
SQLite - http://www.sqlite.org/
|
||||
For the sticker database.
|
||||
|
||||
libcdio - http://www.gnu.org/software/libcdio/
|
||||
For playing audio CDs.
|
||||
|
||||
libsystemd-daemon - http://freedesktop.org/wiki/Software/systemd/
|
||||
For systemd activation.
|
||||
|
||||
|
||||
pkg-config
|
||||
----------
|
||||
|
||||
MPD uses pkg-config to locate most external libraries. If you do not
|
||||
have pkg-config, or if your version of the library does not ship the
|
||||
".pc" file, you have to provide the library's build options in
|
||||
environment variables. These variables are documented in "./configure
|
||||
--help". Example:
|
||||
|
||||
FLAC_CFLAGS=-I/usr/include/FLAC FLAC_LIBS=-lFLAC ./configure
|
||||
|
||||
|
||||
Download
|
||||
--------
|
||||
|
||||
Get the latest release from of MPD from <http://www.musicpd.org/>.
|
||||
|
||||
Compile
|
||||
-------
|
||||
|
||||
1) unpack the archive
|
||||
|
||||
$ tar xf mpd-x.x.x.tar.xz
|
||||
|
||||
2) change to directory created
|
||||
|
||||
$ cd mpd-x.x.x
|
||||
|
||||
3) Run configure script (this will determine what dependencies you have)
|
||||
|
||||
$ ./configure
|
||||
|
||||
4) Compile
|
||||
|
||||
$ make
|
||||
|
||||
Install (Optional)
|
||||
-------
|
||||
|
||||
(as root)
|
||||
$ make install
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
1) run mpd:
|
||||
|
||||
$ mpd <config file>
|
||||
|
||||
First default is $XDG_CONFIG_HOME/mpd/mpd.conf then ~/.mpdconf then
|
||||
~/.mpd/mpd.conf then /etc/mpd.conf. If neither of these exist a mpd
|
||||
configuration file must be specified at runtime.
|
||||
|
||||
A sample config file is included with the source of MPD, mpdconf.example.
|
||||
|
||||
The first time MPD is run it will attempt to discover all music in your
|
||||
music root, recursively. This can be affected by the symbolic link
|
||||
options specified in the example mpd.conf.
|
||||
|
||||
Using MPD
|
||||
---------
|
||||
|
||||
You can download many different interfaces for MPD at
|
||||
|
||||
http://www.musicpd.org/clients/
|
791
Makefile.am
791
Makefile.am
File diff suppressed because it is too large
Load Diff
246
NEWS
246
NEWS
@@ -1,3 +1,249 @@
|
||||
ver 0.20.16 (2018/02/03)
|
||||
* output
|
||||
- pulse: fix crash during auto-detection
|
||||
* database
|
||||
- simple: fix search within mount points
|
||||
- upnp: enable IPv6
|
||||
* archive
|
||||
- iso9660: libcdio 2.0 compatibility
|
||||
* fix crash in debug build on Haiku and other operating systems
|
||||
|
||||
ver 0.20.15 (2018/01/05)
|
||||
* queue: fix crash after seek failure
|
||||
* resampler
|
||||
- soxr: clear internal state after manual song change
|
||||
* state file
|
||||
- make mount point restore errors non-fatal
|
||||
- fix crash when restoring mounts with incompatible database plugin
|
||||
* Android
|
||||
- build without Ant
|
||||
- fix for SIGSYS crash
|
||||
|
||||
ver 0.20.14 (2018/01/01)
|
||||
* database
|
||||
- simple: fix file corruption in the presence of mount points
|
||||
* archive
|
||||
- bz2: fix deadlock
|
||||
- reduce lock contention, fixing lots of xrun problems
|
||||
* fix Solaris build failure
|
||||
|
||||
ver 0.20.13 (2017/12/18)
|
||||
* output
|
||||
- osx: set up ring buffer to hold at least 100ms
|
||||
* mixer
|
||||
- alsa: fix rounding errors
|
||||
* database
|
||||
- simple: don't purge mount points on update/rescan
|
||||
- simple: fix "mount" bug caused by bad compiler optimization
|
||||
- simple: fix "lsinfo" into mount points
|
||||
- upnp: work around libupnp 1.6.24 API breakage
|
||||
* queue: fix spuriously misplaced prioritized songs
|
||||
* save and restore mountpoints within the state file
|
||||
* include Windows cross-build script in source tarball
|
||||
* fix Windows build failures
|
||||
|
||||
ver 0.20.12 (2017/11/25)
|
||||
* database
|
||||
- upnp: adapt to libupnp 1.8 API changes
|
||||
* input
|
||||
- cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention,
|
||||
fixing lots of xrun problems
|
||||
- curl: fix seeking
|
||||
* decoder
|
||||
- ffmpeg: fix GCC 8 warning
|
||||
- vorbis: fix Tremor support
|
||||
* player
|
||||
- log message when decoder is too slow
|
||||
* encoder
|
||||
- vorbis: default to quality 3
|
||||
* output
|
||||
- fix hanging playback with soxr resampler
|
||||
- httpd: flush encoder after tag; fixes corrupt Vorbis stream
|
||||
|
||||
ver 0.20.11 (2017/10/18)
|
||||
* storage
|
||||
- curl: support Content-Type application/xml
|
||||
* decoder
|
||||
- ffmpeg: more reliable song duration
|
||||
- gme: fix track numbering
|
||||
* improve random song order when switching songs manually
|
||||
* fix case insensitive search without libicu
|
||||
* fix Unicode file names in playlists on Windows
|
||||
* fix endless loop when accessing malformed file names in ZIP files
|
||||
|
||||
ver 0.20.10 (2017/08/24)
|
||||
* decoder
|
||||
- ffmpeg: support MusicBrainz ID3v2 tags
|
||||
* tags
|
||||
- aiff: fix FORM chunk size endianess (is big-endian)
|
||||
* mixer
|
||||
- osx: add a mixer for OSX.
|
||||
* fix crash when resuming playback before decoder is ready
|
||||
* fix crash on Windows
|
||||
|
||||
ver 0.20.9 (2017/06/04)
|
||||
* decoder
|
||||
- ffmpeg: support *.adx
|
||||
* fix byte order detection on FreeBSD/aarch64
|
||||
* fix more random crashes when compiled with clang
|
||||
|
||||
ver 0.20.8 (2017/05/19)
|
||||
* output
|
||||
- osx: fix build failure due to missing "noexcept"
|
||||
* playlist
|
||||
- m3u: support MIME type `audio/mpegurl`
|
||||
* fix build failure with GCC 4.x
|
||||
|
||||
ver 0.20.7 (2017/05/15)
|
||||
* database
|
||||
- simple: fix false positive directory loop detection with NFS
|
||||
* enforce a reasonable minimum audio_buffer_size setting
|
||||
* cap buffer_before_play at 80% to prevent deadlock
|
||||
* fix random crashes when compiled with clang
|
||||
|
||||
ver 0.20.6 (2017/03/10)
|
||||
* input
|
||||
- curl: fix headers after HTTP redirect to Shoutcast server
|
||||
* decoder
|
||||
- ffmpeg: re-enable as fallback
|
||||
- mpcdec: fix crash (division by zero) after seeking
|
||||
- sidplay: make compatible with libsidplayfp < 1.8
|
||||
* fix stream tags after automatic song change
|
||||
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
|
||||
|
||||
ver 0.20.5 (2017/02/20)
|
||||
* tags
|
||||
- id3: fix memory leak on corrupt ID3 tags
|
||||
* decoder
|
||||
- sidplay: don't require libsidutils when building with libsidplayfp
|
||||
* output
|
||||
- httpd: fix two buffer overflows in IcyMetaData length calculation
|
||||
* mixer
|
||||
- alsa: fix crash bug
|
||||
|
||||
ver 0.20.4 (2017/02/01)
|
||||
* input
|
||||
- nfs: fix freeze after reconnect
|
||||
* output
|
||||
- sndio: work around a libroar C++ incompatibility
|
||||
* workaround for GCC 4.9 "constexpr" bug
|
||||
* fix FreeBSD build failure
|
||||
|
||||
ver 0.20.3 (2017/01/25)
|
||||
* protocol
|
||||
- "playlistadd" creates new playlist if it does not exist, as documented
|
||||
* database
|
||||
- proxy: fix error "terminate called after throwing ..."
|
||||
- proxy: make connect errors during startup non-fatal
|
||||
* neighbor
|
||||
- upnp: fix premature expiry
|
||||
* replay gain: don't reset ReplayGain levels when unpausing playback
|
||||
* silence surround channels when converting from stereo
|
||||
* use shortcuts such as "dsd64" in log messages
|
||||
|
||||
ver 0.20.2 (2017/01/15)
|
||||
* input
|
||||
- alsa: fix crash bug
|
||||
- alsa: fix buffer overruns
|
||||
* decoder
|
||||
- flac: add options "probesize" and "analyzeduration"
|
||||
* resampler
|
||||
- libsamplerate: reset state after seeking
|
||||
* output
|
||||
- fix static noise after changing to a different audio format
|
||||
- alsa: fix the DSD_U32 sample rate
|
||||
- alsa: fix the DSD_U32 byte order
|
||||
- alsa: support DSD_U16
|
||||
- recorder: fix error "Failed to create : No such file or directory"
|
||||
* playlist
|
||||
- cue: fix skipping songs
|
||||
|
||||
ver 0.20.1 (2017/01/09)
|
||||
* input
|
||||
- curl: fix crash bug
|
||||
- curl: fix freeze bug
|
||||
* decoder
|
||||
- wavpack: fix crash bug
|
||||
* storage
|
||||
- curl: new storage plugin for WebDAV (work in progress)
|
||||
* mixer
|
||||
- alsa: normalize displayed volume according to human perception
|
||||
* fix crash with volume_normalization enabled
|
||||
|
||||
ver 0.20 (2017/01/04)
|
||||
* protocol
|
||||
- "commands" returns playlist commands only if playlist_directory configured
|
||||
- "search"/"find" have a "window" parameter
|
||||
- report song duration with milliseconds precision
|
||||
- "sticker find" can match sticker values
|
||||
- drop the "file:///" prefix for absolute file paths
|
||||
- add range parameter to command "plchanges" and "plchangesposid"
|
||||
- send verbose error message to client
|
||||
* input
|
||||
- curl: fix memory leak
|
||||
* tags
|
||||
- ape, ogg: drop support for non-standard tag "album artist"
|
||||
affected filetypes: vorbis, flac, opus & all files with ape2 tags
|
||||
(most importantly some mp3s)
|
||||
- id3: remove the "id3v1_encoding" setting; by definition, all ID3v1 tags
|
||||
are ISO-Latin-1
|
||||
- ape: support APE replay gain on remote files
|
||||
- read ID3 tags from NFS/SMB
|
||||
* decoder
|
||||
- improved error logging
|
||||
- report I/O errors to clients
|
||||
- ffmpeg: support ReplayGain and MixRamp
|
||||
- ffmpeg: support stream tags
|
||||
- gme: add option "accuracy"
|
||||
- gme: provide the TRACK tag
|
||||
- gme: faster scanning
|
||||
- mad: reduce memory usage while scanning tags
|
||||
- mpcdec: read the bit rate
|
||||
- pcm: support audio/L16 (RFC 2586) and audio/x-mpd-float
|
||||
- sidplay: faster scanning
|
||||
- wavpack: large file support
|
||||
- wavpack: support DSD (WavPack 5)
|
||||
- wavpack: archive support
|
||||
* playlist
|
||||
- cue: don't skip pregap
|
||||
- embcue: fix last track
|
||||
- flac: new plugin which reads the "CUESHEET" metadata block
|
||||
* output
|
||||
- alsa: fix multi-channel order
|
||||
- alsa: remove option "use_mmap"
|
||||
- alsa: support DSD_U32
|
||||
- alsa: disable DoP if it fails
|
||||
- jack: reduce CPU usage
|
||||
- pulse: set channel map to WAVE-EX
|
||||
- recorder: record tags
|
||||
- recorder: allow dynamic file names
|
||||
- sndio: new output plugin
|
||||
* mixer
|
||||
- null: new plugin
|
||||
* resampler
|
||||
- new block "resampler" in configuration file
|
||||
replacing the old "samplerate_converter" setting
|
||||
- soxr: allow multi-threaded resampling
|
||||
* player
|
||||
- reset song priority on playback
|
||||
- reduce xruns
|
||||
* write database and state file atomically
|
||||
* always write UTF-8 to the log file.
|
||||
* remove dependency on GLib
|
||||
* support libsystemd (instead of the older libsystemd-daemon)
|
||||
* database
|
||||
- proxy: add TCP keepalive option
|
||||
* update
|
||||
- apply .mpdignore matches to subdirectories
|
||||
* switch the code base to C++14
|
||||
- GCC 4.9 or clang 3.4 (or newer) recommended
|
||||
|
||||
ver 0.19.21 (2016/12/13)
|
||||
* decoder
|
||||
- ffmpeg: fix crash bug
|
||||
* fix unit test failure after recent "setprio" change
|
||||
* systemd: add user unit
|
||||
|
||||
ver 0.19.20 (2016/12/09)
|
||||
* protocol
|
||||
- "setprio" re-enqueues old song if priority has been raised
|
||||
|
17
README
17
README
@@ -1,17 +0,0 @@
|
||||
|
||||
Music Player Daemon (MPD)
|
||||
http://www.musicpd.org
|
||||
|
||||
A daemon for playing music of various formats. Music is played through the
|
||||
server's audio device. The daemon stores info about all available music,
|
||||
and this info can be easily searched and retrieved. Player control, info
|
||||
retrieval, and playlist management can all be managed remotely.
|
||||
|
||||
For basic installation information see the INSTALL file.
|
||||
|
||||
MPD is released under the GNU General Public License version 2, which is
|
||||
distributed in the COPYING file.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
29
README.md
Normal file
29
README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Music Player Daemon
|
||||
|
||||
http://www.musicpd.org
|
||||
|
||||
A daemon for playing music of various formats. Music is played through the
|
||||
server's audio device. The daemon stores info about all available music,
|
||||
and this info can be easily searched and retrieved. Player control, info
|
||||
retrieval, and playlist management can all be managed remotely.
|
||||
|
||||
For basic installation instructions
|
||||
[read the manual](https://www.musicpd.org/doc/user/install.html).
|
||||
|
||||
# Users
|
||||
|
||||
- [Manual](http://www.musicpd.org/doc/user/)
|
||||
- [Forum](http://forum.musicpd.org/)
|
||||
- [IRC](irc://chat.freenode.net/#mpd)
|
||||
- [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
|
||||
|
||||
# Developers
|
||||
|
||||
- [Protocol specification](http://www.musicpd.org/doc/protocol/)
|
||||
- [Developer manual](http://www.musicpd.org/doc/developer/)
|
||||
|
||||
# Legal
|
||||
|
||||
MPD is released under the
|
||||
[GNU General Public License version 2](https://www.gnu.org/licenses/gpl-2.0.txt),
|
||||
which is distributed in the COPYING file.
|
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="13"
|
||||
android:versionName="0.19.9">
|
||||
android:versionCode="15"
|
||||
android:versionName="0.20.16">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>
|
||||
|
||||
|
487
android/build.py
487
android/build.py
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, os.path
|
||||
import sys, shutil, subprocess
|
||||
import urllib.request
|
||||
import hashlib
|
||||
import re
|
||||
import sys, subprocess
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: build.py SDK_PATH NDK_PATH [configure_args...]", file=sys.stderr)
|
||||
@@ -22,412 +19,154 @@ if not os.path.isdir(ndk_path):
|
||||
print("NDK not found in", ndk_path, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# select the NDK target
|
||||
arch = 'arm-linux-androideabi'
|
||||
|
||||
# the path to the MPD sources
|
||||
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
|
||||
sys.path[0] = os.path.join(mpd_path, 'python')
|
||||
|
||||
# output directories
|
||||
lib_path = os.path.abspath('lib')
|
||||
tarball_path = lib_path
|
||||
src_path = os.path.join(lib_path, 'src')
|
||||
build_path = os.path.join(lib_path, 'build')
|
||||
root_path = os.path.join(lib_path, 'root')
|
||||
from build.dirs import lib_path, tarball_path, src_path
|
||||
|
||||
arch_path = os.path.join(lib_path, arch)
|
||||
build_path = os.path.join(arch_path, 'build')
|
||||
|
||||
# build host configuration
|
||||
build_arch = 'linux-x86_64'
|
||||
|
||||
# redirect pkg-config to use our root directory instead of the default
|
||||
# one on the build host
|
||||
os.environ['PKG_CONFIG_LIBDIR'] = os.path.join(root_path, 'lib/pkgconfig')
|
||||
|
||||
# select the NDK compiler
|
||||
gcc_version = '4.9'
|
||||
llvm_version = '3.5'
|
||||
|
||||
# select the NDK target
|
||||
ndk_arch = 'arm'
|
||||
host_arch = 'arm-linux-androideabi'
|
||||
android_abi = 'armeabi-v7a'
|
||||
ndk_platform = 'android-14'
|
||||
|
||||
# set up the NDK toolchain
|
||||
|
||||
gcc_toolchain = os.path.join(ndk_path, 'toolchains', host_arch + '-' + gcc_version, 'prebuilt', build_arch)
|
||||
llvm_toolchain = os.path.join(ndk_path, 'toolchains', 'llvm-' + llvm_version, 'prebuilt', build_arch)
|
||||
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
|
||||
target_root = os.path.join(ndk_platform_path, 'arch-' + ndk_arch)
|
||||
class AndroidNdkToolchain:
|
||||
def __init__(self, tarball_path, src_path, build_path,
|
||||
use_cxx):
|
||||
self.tarball_path = tarball_path
|
||||
self.src_path = src_path
|
||||
self.build_path = build_path
|
||||
|
||||
llvm_triple = 'armv7-none-linux-androideabi'
|
||||
self.ndk_arch = 'arm'
|
||||
android_abi = 'armeabi-v7a'
|
||||
ndk_platform = 'android-21'
|
||||
|
||||
def select_toolchain(use_cxx, use_clang):
|
||||
global cc, cxx, ar, strip, cflags, cxxflags, cppflags, ldflags, libs
|
||||
# select the NDK compiler
|
||||
gcc_version = '4.9'
|
||||
|
||||
target_arch = '-march=armv7-a -mfloat-abi=softfp'
|
||||
if use_clang:
|
||||
cc = os.path.join(llvm_toolchain, 'bin/clang')
|
||||
cxx = os.path.join(llvm_toolchain, 'bin/clang++')
|
||||
target_arch += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + gcc_toolchain
|
||||
else:
|
||||
cc = os.path.join(gcc_toolchain, 'bin', host_arch + '-gcc')
|
||||
cxx = os.path.join(gcc_toolchain, 'bin', host_arch + '-g++')
|
||||
ar = os.path.join(gcc_toolchain, 'bin', host_arch + '-ar')
|
||||
strip = os.path.join(gcc_toolchain, 'bin', host_arch + '-strip')
|
||||
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
|
||||
sysroot = os.path.join(ndk_path, 'sysroot')
|
||||
target_root = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
|
||||
|
||||
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
|
||||
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
|
||||
if use_clang:
|
||||
libstdcxx_cppflags += ' -D__STRICT_ANSI__'
|
||||
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
|
||||
install_prefix = os.path.join(arch_path, 'root')
|
||||
|
||||
cflags = '-Os -g ' + target_arch
|
||||
cxxflags = '-Os -g ' + target_arch
|
||||
cppflags = '--sysroot=' + target_root + ' -I' + root_path + '/include'
|
||||
ldflags = '--sysroot=' + target_root + ' -L' + root_path + '/lib'
|
||||
libs = ''
|
||||
self.arch = arch
|
||||
self.install_prefix = install_prefix
|
||||
self.sysroot = sysroot
|
||||
|
||||
toolchain_path = os.path.join(ndk_path, 'toolchains', arch + '-' + gcc_version, 'prebuilt', build_arch)
|
||||
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
||||
llvm_triple = 'armv7-none-linux-androideabi'
|
||||
|
||||
common_flags = '-Os -g'
|
||||
common_flags += ' -fPIC'
|
||||
common_flags += ' -march=armv7-a -mfloat-abi=softfp'
|
||||
|
||||
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||
llvm_bin = os.path.join(llvm_path, 'bin')
|
||||
self.cc = os.path.join(llvm_bin, 'clang')
|
||||
self.cxx = os.path.join(llvm_bin, 'clang++')
|
||||
common_flags += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + toolchain_path
|
||||
|
||||
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
||||
|
||||
self.ar = os.path.join(toolchain_bin, arch + '-ar')
|
||||
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
|
||||
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
||||
self.strip = os.path.join(toolchain_bin, arch + '-strip')
|
||||
|
||||
self.cflags = common_flags
|
||||
self.cxxflags = common_flags
|
||||
self.cppflags = '--sysroot=' + sysroot + \
|
||||
' -isystem ' + os.path.join(install_prefix, 'include') + \
|
||||
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
|
||||
' -D__ANDROID_API__=21'
|
||||
self.ldflags = '--sysroot=' + sysroot + \
|
||||
' -L' + os.path.join(install_prefix, 'lib') + \
|
||||
' -L' + os.path.join(target_root, 'usr', 'lib') + \
|
||||
' -B' + os.path.join(target_root, 'usr', 'lib') + \
|
||||
' ' + common_flags
|
||||
self.libs = ''
|
||||
|
||||
self.is_arm = self.ndk_arch == 'arm'
|
||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||
self.is_windows = False
|
||||
|
||||
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
|
||||
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
|
||||
|
||||
libstdcxx_flags = '-stdlib=libc++'
|
||||
libstdcxx_cxxflags = libstdcxx_flags + ' -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
||||
libstdcxx_ldflags = libstdcxx_flags + ' -static-libstdc++ -L' + libcxx_libs_path
|
||||
|
||||
if use_cxx:
|
||||
libs += ' ' + libstdcxx_ldadd
|
||||
cppflags += ' ' + libstdcxx_cppflags
|
||||
self.cxxflags += ' ' + libstdcxx_cxxflags
|
||||
self.ldflags += ' ' + libstdcxx_ldflags
|
||||
|
||||
def file_md5(path):
|
||||
"""Calculate the MD5 checksum of a file and return it in hexadecimal notation."""
|
||||
self.env = dict(os.environ)
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
m = hashlib.md5()
|
||||
while True:
|
||||
data = f.read(65536)
|
||||
if len(data) == 0:
|
||||
# end of file
|
||||
return m.hexdigest()
|
||||
m.update(data)
|
||||
|
||||
def download_tarball(url, md5):
|
||||
"""Download a tarball, verify its MD5 checksum and return the local path."""
|
||||
|
||||
global tarball_path
|
||||
os.makedirs(tarball_path, exist_ok=True)
|
||||
path = os.path.join(tarball_path, os.path.basename(url))
|
||||
|
||||
try:
|
||||
calculated_md5 = file_md5(path)
|
||||
if md5 == calculated_md5: return path
|
||||
os.unlink(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
tmp_path = path + '.tmp'
|
||||
|
||||
print("download", url)
|
||||
urllib.request.urlretrieve(url, tmp_path)
|
||||
calculated_md5 = file_md5(tmp_path)
|
||||
if calculated_md5 != md5:
|
||||
os.unlink(tmp_path)
|
||||
raise "MD5 mismatch"
|
||||
|
||||
os.rename(tmp_path, path)
|
||||
return path
|
||||
|
||||
class Project:
|
||||
def __init__(self, url, md5, installed, name=None, version=None,
|
||||
base=None,
|
||||
use_cxx=False, use_clang=False):
|
||||
if base is None:
|
||||
basename = os.path.basename(url)
|
||||
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
||||
if not m: raise
|
||||
self.base = m.group(1)
|
||||
else:
|
||||
self.base = base
|
||||
|
||||
if name is None or version is None:
|
||||
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?)$', self.base)
|
||||
if name is None: name = m.group(1)
|
||||
if version is None: version = m.group(2)
|
||||
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
self.url = url
|
||||
self.md5 = md5
|
||||
self.installed = installed
|
||||
|
||||
self.use_cxx = use_cxx
|
||||
self.use_clang = use_clang
|
||||
|
||||
def download(self):
|
||||
return download_tarball(self.url, self.md5)
|
||||
|
||||
def is_installed(self):
|
||||
global root_path
|
||||
tarball = self.download()
|
||||
installed = os.path.join(root_path, self.installed)
|
||||
tarball_mtime = os.path.getmtime(tarball)
|
||||
try:
|
||||
return os.path.getmtime(installed) >= tarball_mtime
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
def unpack(self):
|
||||
global src_path
|
||||
tarball = self.download()
|
||||
path = os.path.join(src_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(src_path, exist_ok=True)
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball, src_path])
|
||||
return path
|
||||
|
||||
def make_build_path(self):
|
||||
path = os.path.join(build_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(path, exist_ok=True)
|
||||
return path
|
||||
|
||||
class AutotoolsProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
autogen=False,
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.autogen = autogen
|
||||
self.cppflags = cppflags
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
if self.autogen:
|
||||
subprocess.check_call(['/usr/bin/aclocal'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/autoconf'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/libtoolize', '--force'], cwd=src)
|
||||
|
||||
build = self.make_build_path()
|
||||
|
||||
select_toolchain(use_cxx=self.use_cxx, use_clang=self.use_clang)
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'CC=' + cc,
|
||||
'CXX=' + cxx,
|
||||
'CFLAGS=' + cflags,
|
||||
'CXXFLAGS=' + cxxflags,
|
||||
'CPPFLAGS=' + cppflags + ' ' + self.cppflags,
|
||||
'LDFLAGS=' + ldflags,
|
||||
'LIBS=' + libs,
|
||||
'AR=' + ar,
|
||||
'STRIP=' + strip,
|
||||
'--host=' + host_arch,
|
||||
'--prefix=' + root_path,
|
||||
'--with-sysroot=' + target_root,
|
||||
'--enable-silent-rules',
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build)
|
||||
|
||||
class FfmpegProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.cppflags = cppflags
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
build = self.make_build_path()
|
||||
|
||||
select_toolchain(use_cxx=self.use_cxx, use_clang=self.use_clang)
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'--cc=' + cc,
|
||||
'--cxx=' + cxx,
|
||||
'--extra-cflags=' + cflags + ' ' + cppflags + ' ' + self.cppflags,
|
||||
'--extra-cxxflags=' + cxxflags + ' ' + cppflags + ' ' + self.cppflags,
|
||||
'--extra-ldflags=' + ldflags,
|
||||
'--extra-libs=' + libs,
|
||||
'--ar=' + ar,
|
||||
'--enable-cross-compile',
|
||||
'--target-os=linux',
|
||||
'--arch=' + ndk_arch,
|
||||
'--cpu=cortex-a8',
|
||||
'--prefix=' + root_path,
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build)
|
||||
|
||||
class BoostProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
m = re.match(r'.*/boost_(\d+)_(\d+)_(\d+)\.tar\.bz2$', url)
|
||||
version = "%s.%s.%s" % (m.group(1), m.group(2), m.group(3))
|
||||
Project.__init__(self, url, md5, installed,
|
||||
name='boost', version=version,
|
||||
**kwargs)
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
|
||||
# install the headers manually; don't build any library
|
||||
# (because right now, we only use header-only libraries)
|
||||
includedir = os.path.join(root_path, 'include')
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.join(src, 'boost')):
|
||||
relpath = dirpath[len(src)+1:]
|
||||
destdir = os.path.join(includedir, relpath)
|
||||
try:
|
||||
os.mkdir(destdir)
|
||||
except:
|
||||
pass
|
||||
for name in filenames:
|
||||
if name[-4:] == '.hpp':
|
||||
shutil.copyfile(os.path.join(dirpath, name),
|
||||
os.path.join(destdir, name))
|
||||
# redirect pkg-config to use our root directory instead of the
|
||||
# default one on the build host
|
||||
self.env['PKG_CONFIG_LIBDIR'] = os.path.join(install_prefix, 'lib/pkgconfig')
|
||||
|
||||
# a list of third-party libraries to be used by MPD on Android
|
||||
from build.libs import *
|
||||
thirdparty_libs = [
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz',
|
||||
'5c3a34309d8b98640827e5d0991a4015',
|
||||
'lib/libogg.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.4.tar.xz',
|
||||
'55f2288055e44754275a17c9a2497391',
|
||||
'lib/libvorbis.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/opus/opus-1.1.tar.gz',
|
||||
'c5a8cf7c0b066759542bc4ca46817ac6',
|
||||
'lib/libopus.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/flac/flac-1.3.1.tar.xz',
|
||||
'b9922c9a0378c88d3e901b234f852698',
|
||||
'lib/libFLAC.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||
],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
|
||||
'e5808ad997ba32c498803822078748c3',
|
||||
'lib/libid3tag.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
|
||||
'1be543bc30c56fb6bea1d7bf6a64e66c',
|
||||
'lib/libmad.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
),
|
||||
|
||||
FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-2.5.tar.bz2',
|
||||
'4346fe710cc6bdd981f6534d2420d1ab',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--enable-gpl',
|
||||
'--enable-small',
|
||||
'--disable-pthreads',
|
||||
'--disable-runtime-cpudetect',
|
||||
'--disable-programs',
|
||||
'--disable-doc',
|
||||
'--disable-avdevice',
|
||||
'--disable-swresample',
|
||||
'--disable-swscale',
|
||||
'--disable-postproc',
|
||||
'--disable-avfilter',
|
||||
'--disable-network',
|
||||
'--disable-encoders',
|
||||
'--disable-protocols',
|
||||
'--disable-outdevs',
|
||||
'--disable-filters',
|
||||
],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.39.0.tar.lzma',
|
||||
'e9aa6dec29920eba8ef706ea5823bad7',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-debug',
|
||||
'--enable-http',
|
||||
'--enable-ipv6',
|
||||
'--disable-ftp', '--disable-file',
|
||||
'--disable-ldap', '--disable-ldaps',
|
||||
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
|
||||
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
|
||||
'--disable-gopher',
|
||||
'--disable-manual',
|
||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
||||
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
||||
],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
BoostProject(
|
||||
'http://netcologne.dl.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2',
|
||||
'd6eef4b4cacb2183f2bf265a5a03a354',
|
||||
'include/boost/version.hpp',
|
||||
),
|
||||
libogg,
|
||||
libvorbis,
|
||||
opus,
|
||||
flac,
|
||||
libid3tag,
|
||||
libmad,
|
||||
ffmpeg,
|
||||
curl,
|
||||
boost,
|
||||
]
|
||||
|
||||
# build the third-party libraries
|
||||
for x in thirdparty_libs:
|
||||
if not x.is_installed():
|
||||
x.build()
|
||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
||||
use_cxx=x.use_cxx)
|
||||
if not x.is_installed(toolchain):
|
||||
x.build(toolchain)
|
||||
|
||||
# configure and build MPD
|
||||
select_toolchain(use_cxx=True, use_clang=True)
|
||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
||||
use_cxx=True)
|
||||
|
||||
configure = [
|
||||
os.path.join(mpd_path, 'configure'),
|
||||
'CC=' + cc,
|
||||
'CXX=' + cxx,
|
||||
'CFLAGS=' + cflags,
|
||||
'CXXFLAGS=' + cxxflags,
|
||||
'CPPFLAGS=' + cppflags,
|
||||
'LDFLAGS=' + ldflags,
|
||||
'LIBS=' + libs,
|
||||
'AR=' + ar,
|
||||
'STRIP=' + strip,
|
||||
'--host=' + host_arch,
|
||||
'--prefix=' + root_path,
|
||||
'--with-sysroot=' + target_root,
|
||||
'CC=' + toolchain.cc,
|
||||
'CXX=' + toolchain.cxx,
|
||||
'CFLAGS=' + toolchain.cflags,
|
||||
'CXXFLAGS=' + toolchain.cxxflags,
|
||||
'CPPFLAGS=' + toolchain.cppflags,
|
||||
'LDFLAGS=' + toolchain.ldflags,
|
||||
'LIBS=' + toolchain.libs,
|
||||
'AR=' + toolchain.ar,
|
||||
'RANLIB=' + toolchain.ranlib,
|
||||
'STRIP=' + toolchain.strip,
|
||||
'--host=' + toolchain.arch,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
'--with-sysroot=' + toolchain.sysroot,
|
||||
'--with-android-sdk=' + sdk_path,
|
||||
|
||||
'--enable-silent-rules',
|
||||
|
||||
'--disable-glib',
|
||||
'--disable-icu',
|
||||
|
||||
# disabled for now because these features require GLib:
|
||||
'--disable-httpd-output',
|
||||
'--disable-vorbis-encoder',
|
||||
|
||||
] + configure_args
|
||||
|
||||
subprocess.check_call(configure)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'])
|
||||
from build.cmdline import concatenate_cmdline_variables
|
||||
configure = concatenate_cmdline_variables(configure,
|
||||
set(('CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'LIBS')))
|
||||
|
||||
subprocess.check_call(configure, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
940
configure.ac
940
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
<book>
|
||||
<title>The Music Player Daemon - Developer's Manual</title>
|
||||
|
||||
<chapter>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
@@ -21,7 +21,7 @@
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="code_style">
|
||||
<title>Code Style</title>
|
||||
|
||||
<itemizedlist>
|
||||
@@ -40,9 +40,35 @@
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
the code should be C++11 compliant, and must compile with
|
||||
<application>GCC</application> 4.7 and
|
||||
<application>clang</application> 3.2
|
||||
comment your code, document your APIs
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
the code should be C++14 compliant, and must compile with
|
||||
<application>GCC</application> 4.9 and
|
||||
<application>clang</application> 3.4
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
report error conditions with C++ exceptions, preferable
|
||||
derived from <varname>std::runtime_error</varname>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
all code must be exception-safe
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
classes and functions names use CamelCase; variables are
|
||||
lower-case with words separated by underscore
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -52,9 +78,9 @@
|
||||
</para>
|
||||
|
||||
<programlisting lang="C">static inline int
|
||||
foo(const char *abc, int xyz)
|
||||
Foo(const char *abc, int xyz)
|
||||
{
|
||||
if (abc == NULL) {
|
||||
if (abc == nullptr) {
|
||||
LogWarning("Foo happened!");
|
||||
return -1;
|
||||
}
|
||||
@@ -66,25 +92,25 @@ foo(const char *abc, int xyz)
|
||||
</itemizedlist>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="hacking">
|
||||
<title>Hacking The Source</title>
|
||||
|
||||
<para>
|
||||
MPD sources are managed in a git repository on <ulink
|
||||
url="http://git.musicpd.org/">git.musicpd.org</ulink>.
|
||||
url="https://github.com/MusicPlayerDaemon/">GitHub</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Always write your code against the latest git:
|
||||
</para>
|
||||
|
||||
<programlisting>git clone git://git.musicpd.org/master/mpd.git</programlisting>
|
||||
<programlisting>git clone git://github.com/MusicPlayerDaemon/MPD</programlisting>
|
||||
|
||||
<para>
|
||||
If you already have a clone, update it:
|
||||
</para>
|
||||
|
||||
<programlisting>git pull --rebase git://git.musicpd.org/master/mpd.git master</programlisting>
|
||||
<programlisting>git pull --rebase git://github.com/MusicPlayerDaemon/MPD master</programlisting>
|
||||
|
||||
<para>
|
||||
You can do without "--rebase", but we recommend that you rebase
|
||||
@@ -151,7 +177,7 @@ foo(const char *abc, int xyz)
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="submitting_patches">
|
||||
<title>Submitting Patches</title>
|
||||
|
||||
<para>
|
||||
@@ -162,14 +188,11 @@ foo(const char *abc, int xyz)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<command>git pull</command> requests are preferred. Regular
|
||||
contributors can get <ulink
|
||||
url="http://git.musicpd.org/account-policy.html">an account on
|
||||
git.musicpd.org</ulink>, but any public git repository will do.
|
||||
<command>git pull</command> requests are preferred.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="tools">
|
||||
<title>Development Tools</title>
|
||||
|
||||
<section>
|
||||
|
2473
doc/doxygen.conf.in
2473
doc/doxygen.conf.in
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,8 @@
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>track</varname>: the track number within the album.
|
||||
<varname>track</varname>: the decimal track number within the
|
||||
album.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -103,7 +104,8 @@
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>disc</varname>: the disc number in a multi-disc album.
|
||||
<varname>disc</varname>: the decimal disc number in a multi-disc
|
||||
album.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -111,7 +113,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_artistid</varname>: the artist id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -120,7 +122,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_albumid</varname>: the album id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -129,7 +131,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_albumartistid</varname>: the album artist
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -138,7 +140,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_trackid</varname>: the track id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -147,7 +149,7 @@
|
||||
<para>
|
||||
<varname>musicbrainz_releasetrackid</varname>: the release track
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
@@ -48,8 +48,8 @@ mpd.conf(5), mpc(1)
|
||||
.SH BUGS
|
||||
If you find a bug, please report it at
|
||||
.br
|
||||
<\fBhttp://bugs.musicpd.org/bug_report_page.php\fP>.
|
||||
<\fBhttps://github.com/MusicPlayerDaemon/MPD/issues/\fP>.
|
||||
.SH AUTHORS
|
||||
Max Kellermann <max@duempel.org>
|
||||
Max Kellermann <max.kellermann@gmail.com>
|
||||
|
||||
Special thanks to all the people that provided feedback and patches.
|
||||
|
@@ -156,12 +156,6 @@ This specifies the character set used for the filesystem. A list of supported
|
||||
character sets can be obtained by running "iconv \-l". The default is
|
||||
determined from the locale when the db was originally created.
|
||||
.TP
|
||||
.B id3v1_encoding <charset>
|
||||
This specifies the character set which ID3v1 tags are encoded in. A list of
|
||||
supported character sets can be obtained by running "iconv \-l". The default is
|
||||
to let libid3tag convert them (from ISO-8859-1, as the standard specifies) and
|
||||
do no additional conversion.
|
||||
.TP
|
||||
.B gapless_mp3_playback <yes or no>
|
||||
This specifies whether to support gapless playback of MP3s which have the
|
||||
necessary headers. Useful if your MP3s have headers with incorrect
|
||||
@@ -232,11 +226,6 @@ probably only useful if your alsa device has more than one
|
||||
identically\-named mixer control. The default is "0". Use "amixer
|
||||
scontrols" to see the list of controls with their indexes.
|
||||
.TP
|
||||
.B use_mmap <yes or no>
|
||||
Setting this allows you to use memory-mapped I/O. Certain hardware setups may
|
||||
benefit from this, but most do not. Most users do not need to set this. The
|
||||
default is to not use memory-mapped I/O.
|
||||
.TP
|
||||
.B auto_resample <yes or no>
|
||||
Setting this to "no" disables ALSA's software resampling, if the
|
||||
hardware does not support a specific sample rate. This lets MPD do
|
||||
|
@@ -75,7 +75,8 @@
|
||||
#
|
||||
# This setting sets the address for the daemon to listen on. Careful attention
|
||||
# should be paid if this is assigned to anything other then the default, any.
|
||||
# This setting can deny access to control of the daemon.
|
||||
# This setting can deny access to control of the daemon. Not effective if
|
||||
# systemd socket activiation is in use.
|
||||
#
|
||||
# For network
|
||||
#bind_to_address "any"
|
||||
@@ -304,6 +305,23 @@ input {
|
||||
## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
|
||||
#}
|
||||
#
|
||||
# An example of an sndio output.
|
||||
#
|
||||
#audio_output {
|
||||
# type "sndio"
|
||||
# name "sndio output"
|
||||
# mixer_type "software"
|
||||
#}
|
||||
#
|
||||
# An example of an OS X output:
|
||||
#
|
||||
#audio_output {
|
||||
# type "osx"
|
||||
# name "My OS X Device"
|
||||
## device "Built-in Output" # optional
|
||||
## channel_map "-1,-1,0,1" # optional
|
||||
#}
|
||||
#
|
||||
## Example "pipe" output:
|
||||
#
|
||||
#audio_output {
|
||||
@@ -325,13 +343,6 @@ input {
|
||||
# mixer_type "none" # optional
|
||||
#}
|
||||
#
|
||||
# If MPD has been compiled with libsamplerate support, this setting specifies
|
||||
# the sample rate converter to use. Possible values can be found in the
|
||||
# mpd.conf man page or the libsamplerate documentation. By default, this is
|
||||
# setting is disabled.
|
||||
#
|
||||
#samplerate_converter "Fastest Sinc Interpolator"
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
@@ -380,34 +391,4 @@ input {
|
||||
#
|
||||
#filesystem_charset "UTF-8"
|
||||
#
|
||||
# This setting controls the encoding that ID3v1 tags should be converted from.
|
||||
#
|
||||
#id3v1_encoding "ISO-8859-1"
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# SIDPlay decoder #############################################################
|
||||
#
|
||||
# songlength_database:
|
||||
# Location of your songlengths file, as distributed with the HVSC.
|
||||
# The sidplay plugin checks this for matching MD5 fingerprints.
|
||||
# See http://www.c64.org/HVSC/DOCUMENTS/Songlengths.faq
|
||||
#
|
||||
# default_songlength:
|
||||
# This is the default playing time in seconds for songs not in the
|
||||
# songlength database, or in case you're not using a database.
|
||||
# A value of 0 means play indefinitely.
|
||||
#
|
||||
# filter:
|
||||
# Turns the SID filter emulation on or off.
|
||||
#
|
||||
#decoder {
|
||||
# plugin "sidplay"
|
||||
# songlength_database "/media/C64Music/DOCUMENTS/Songlengths.txt"
|
||||
# default_songlength "120"
|
||||
# filter "true"
|
||||
#}
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
@@ -258,9 +258,10 @@
|
||||
"before" the current song in that sequence) will only be
|
||||
scheduled for repeated playback if its priority has become
|
||||
bigger than the priority of the current song. Decreasing the
|
||||
priority of a song will moved it farther to the end of the
|
||||
priority of a song will move it farther to the end of the
|
||||
sequence. Changing the priority of the current song has no
|
||||
effect on the sequence.
|
||||
effect on the sequence. During playback, a song's priority is
|
||||
reset to zero.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -402,6 +403,15 @@
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>
|
||||
Change events accumulate, even while the connection is
|
||||
not in "idle" mode; no events gets lost while the client
|
||||
is doing something else with the connection. If an
|
||||
event had already occurred since the last call, the new
|
||||
<command>idle</command> command will return immediately.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While a client is waiting for <command>idle</command>
|
||||
results, the server disables timeouts, allowing a client
|
||||
@@ -435,7 +445,9 @@
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>volume</varname>:
|
||||
<returnvalue>0-100</returnvalue>
|
||||
<returnvalue>0-100</returnvalue> or
|
||||
<returnvalue>-1</returnvalue> if the volume cannot
|
||||
be determined
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -535,6 +547,15 @@
|
||||
</returnvalue>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>duration</varname>:
|
||||
<footnote id="since_0_20"><simpara>Introduced with <application>MPD</application> 0.20</simpara></footnote>
|
||||
<returnvalue>
|
||||
Duration of the current song in seconds.
|
||||
</returnvalue>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>bitrate</varname>:
|
||||
@@ -563,7 +584,12 @@
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>audio</varname>:
|
||||
<returnvalue>sampleRate:bits:channels</returnvalue>
|
||||
<returnvalue>
|
||||
The format emitted by the decoder plugin during
|
||||
playback, format:
|
||||
"<replaceable>samplerate:bits:channels</replaceable>".
|
||||
Check the user manual for a detailed explanation.
|
||||
</returnvalue>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -1171,12 +1197,15 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>plchanges</command>
|
||||
<arg choice="req"><replaceable>VERSION</replaceable></arg>
|
||||
<arg><replaceable>START:END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Displays changed songs currently in the playlist since
|
||||
<varname>VERSION</varname>.
|
||||
<varname>VERSION</varname>. Start and end positions may
|
||||
be given to limit the output to changes in the given
|
||||
range.
|
||||
</para>
|
||||
<para>
|
||||
To detect songs that were deleted at the end of the
|
||||
@@ -1189,6 +1218,7 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>plchangesposid</command>
|
||||
<arg choice="req"><replaceable>VERSION</replaceable></arg>
|
||||
<arg><replaceable>START:END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -1485,15 +1515,15 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>playlistmove</command>
|
||||
<arg choice="req"><replaceable>NAME</replaceable></arg>
|
||||
<arg choice="req"><replaceable>SONGID</replaceable></arg>
|
||||
<arg choice="req"><replaceable>SONGPOS</replaceable></arg>
|
||||
<arg choice="req"><replaceable>FROM</replaceable></arg>
|
||||
<arg choice="req"><replaceable>TO</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Moves <varname>SONGID</varname> in the playlist
|
||||
<filename>NAME.m3u</filename> to the position
|
||||
<varname>SONGPOS</varname>.
|
||||
Moves the song at position <varname>FROM</varname> in
|
||||
the playlist <filename>NAME.m3u</filename> to the
|
||||
position <varname>TO</varname>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -1579,6 +1609,7 @@ OK
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>WHAT</replaceable></arg>
|
||||
<arg choice="opt"><replaceable>...</replaceable></arg>
|
||||
<arg choice="opt">window <replaceable>START</replaceable>:<replaceable>END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -1623,6 +1654,13 @@ OK
|
||||
<para>
|
||||
<varname>WHAT</varname> is what to find.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<varname>window</varname> can be used to query only a
|
||||
portion of the real response. The parameter is two
|
||||
zero-based record numbers; a start number and an end
|
||||
number.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="command_findadd">
|
||||
@@ -1774,7 +1812,7 @@ OK
|
||||
<para>
|
||||
Clients that are connected via UNIX domain socket may
|
||||
use this command to read the tags of an arbitrary local
|
||||
file (URI beginning with "file:///").
|
||||
file (URI is an absolute path).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -1789,8 +1827,7 @@ OK
|
||||
<para>
|
||||
Read "comments" (i.e. key-value pairs) from the file
|
||||
specified by "URI". This "URI" can be a path relative
|
||||
to the music directory or a URL in the form
|
||||
"file:///foo/bar.ogg".
|
||||
to the music directory or an absolute path.
|
||||
</para>
|
||||
<para>
|
||||
This command may be used to list metadata of remote
|
||||
@@ -1815,6 +1852,7 @@ OK
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>WHAT</replaceable></arg>
|
||||
<arg choice="opt"><replaceable>...</replaceable></arg>
|
||||
<arg choice="opt">window <replaceable>START</replaceable>:<replaceable>END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -2139,6 +2177,30 @@ OK
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="command_sticker_find_equals">
|
||||
<term>
|
||||
<cmdsynopsis>
|
||||
<command>sticker</command>
|
||||
<arg choice="plain">find</arg>
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>URI</replaceable></arg>
|
||||
<arg choice="req"><replaceable>NAME</replaceable></arg>
|
||||
<arg choice="plain">=</arg>
|
||||
<arg choice="req"><replaceable>VALUE</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Searches for stickers with the given value.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Other supported operators are:
|
||||
"<function><</function>", "<function>></function>"
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
|
1695
doc/user.xml
1695
doc/user.xml
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
|
||||
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
@@ -20,6 +20,8 @@
|
||||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
|
||||
# force the compiler to issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: This macro depends on the AX_APPEND_FLAG and
|
||||
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
|
||||
# AX_APPEND_LINK_FLAGS.
|
||||
@@ -54,12 +56,12 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 4
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
|
||||
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
for flag in $1; do
|
||||
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
|
||||
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
|
||||
done
|
||||
])dnl AX_APPEND_COMPILE_FLAGS
|
||||
|
@@ -49,21 +49,23 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 2
|
||||
#serial 6
|
||||
|
||||
AC_DEFUN([AX_APPEND_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
|
||||
AS_VAR_SET_IF(FLAGS,
|
||||
[case " AS_VAR_GET(FLAGS) " in
|
||||
*" $1 "*)
|
||||
AC_RUN_LOG([: FLAGS already contains $1])
|
||||
;;
|
||||
*)
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS $1"])
|
||||
AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
|
||||
;;
|
||||
esac],
|
||||
[AS_VAR_SET(FLAGS,["$1"])])
|
||||
[dnl
|
||||
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
|
||||
AS_VAR_SET_IF(FLAGS,[
|
||||
AS_CASE([" AS_VAR_GET(FLAGS) "],
|
||||
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
|
||||
[
|
||||
AS_VAR_APPEND(FLAGS,[" $1"])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
],
|
||||
[
|
||||
AS_VAR_SET(FLAGS,[$1])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])dnl AX_APPEND_FLAG
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
|
||||
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
@@ -19,6 +19,8 @@
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
|
||||
# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
|
||||
#
|
||||
@@ -52,12 +54,12 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 4
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_APPEND_LINK_FLAGS],
|
||||
[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
for flag in $1; do
|
||||
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3])
|
||||
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
|
||||
done
|
||||
])dnl AX_APPEND_LINK_FLAGS
|
||||
|
@@ -33,7 +33,7 @@
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 23
|
||||
#serial 27
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
@@ -92,7 +92,10 @@ if test "x$want_boost" = "xyes"; then
|
||||
libsubdirs="lib"
|
||||
ax_arch=`uname -m`
|
||||
case $ax_arch in
|
||||
x86_64|ppc64|s390x|sparc64|aarch64)
|
||||
x86_64)
|
||||
libsubdirs="lib64 libx32 lib lib64"
|
||||
;;
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le)
|
||||
libsubdirs="lib64 lib lib64"
|
||||
;;
|
||||
esac
|
||||
@@ -170,6 +173,10 @@ if test "x$want_boost" = "xyes"; then
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes"; then
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
BOOST_CPPFLAGS=
|
||||
BOOST_LDFLAGS=
|
||||
_version=0
|
||||
if test "$ac_boost_path" != ""; then
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
@@ -182,6 +189,12 @@ if test "x$want_boost" = "xyes"; then
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
dnl if nothing found search for layout used in Windows distributions
|
||||
if test -z "$BOOST_CPPFLAGS"; then
|
||||
if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test "$cross_compiling" != yes; then
|
||||
|
@@ -55,10 +55,10 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 3
|
||||
#serial 4
|
||||
|
||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
@@ -67,7 +67,7 @@ AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
|
@@ -55,10 +55,11 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 3
|
||||
#serial 4
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
@@ -66,7 +67,7 @@ AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
|
564
m4/ax_cxx_compile_stdcxx.m4
Normal file
564
m4/ax_cxx_compile_stdcxx.m4
Normal file
@@ -0,0 +1,564 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXX and
|
||||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||
# or '14' (for the C++14 standard).
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for an extended mode.
|
||||
#
|
||||
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline support for the specified C++ standard is
|
||||
# required and that the macro should error out if no mode with that
|
||||
# support is found. If specified 'optional', then configuration proceeds
|
||||
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||
# supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 4
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
m4_if([$1], [11], [],
|
||||
[$1], [14], [],
|
||||
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
[$2], [noext], [],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
|
||||
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
|
||||
ax_cv_cxx_compile_cxx$1,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[ax_cv_cxx_compile_cxx$1=yes],
|
||||
[ax_cv_cxx_compile_cxx$1=no])])
|
||||
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
|
||||
ac_success=yes
|
||||
fi
|
||||
|
||||
m4_if([$2], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for switch in -std=gnu++$1 -std=gnu++0x; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$2], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
dnl Cray's crayCC needs "-h std=c++11"
|
||||
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
|
||||
fi
|
||||
fi
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX$1=0
|
||||
AC_MSG_NOTICE([No compiler with C++$1 support was found])
|
||||
else
|
||||
HAVE_CXX$1=1
|
||||
AC_DEFINE(HAVE_CXX$1,1,
|
||||
[define if the compiler supports basic C++$1 syntax])
|
||||
fi
|
||||
AC_SUBST(HAVE_CXX$1)
|
||||
])
|
||||
|
||||
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
)
|
||||
|
||||
|
||||
dnl Test body for checking C++14 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
)
|
||||
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++11, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx11
|
||||
{
|
||||
|
||||
namespace test_static_assert
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_final_override
|
||||
{
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual void f() {}
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_double_right_angle_brackets
|
||||
{
|
||||
|
||||
template < typename T >
|
||||
struct check {};
|
||||
|
||||
typedef check<void> single_type;
|
||||
typedef check<check<void>> double_type;
|
||||
typedef check<check<check<void>>> triple_type;
|
||||
typedef check<check<check<check<void>>>> quadruple_type;
|
||||
|
||||
}
|
||||
|
||||
namespace test_decltype
|
||||
{
|
||||
|
||||
int
|
||||
f()
|
||||
{
|
||||
int a = 1;
|
||||
decltype(a) b = 2;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_type_deduction
|
||||
{
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
auto
|
||||
add(T1 a1, T2 a2) -> decltype(a1 + a2)
|
||||
{
|
||||
return a1 + a2;
|
||||
}
|
||||
|
||||
int
|
||||
test(const int c, volatile int v)
|
||||
{
|
||||
static_assert(is_same<int, decltype(0)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(c)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(v)>::value == false, "");
|
||||
auto ac = c;
|
||||
auto av = v;
|
||||
auto sumi = ac + av + 'x';
|
||||
auto sumf = ac + av + 1.0;
|
||||
static_assert(is_same<int, decltype(ac)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(av)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumi)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumf)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
|
||||
return (sumf > 0.0) ? sumi : add(c, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_noexcept
|
||||
{
|
||||
|
||||
int f() { return 0; }
|
||||
int g() noexcept { return 0; }
|
||||
|
||||
static_assert(noexcept(f()) == false, "");
|
||||
static_assert(noexcept(g()) == true, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
|
||||
{
|
||||
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
|
||||
}
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
return strlen_c_r(s, 0UL);
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("1") == 1UL, "");
|
||||
static_assert(strlen_c("example") == 7UL, "");
|
||||
static_assert(strlen_c("another\0example") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_rvalue_references
|
||||
{
|
||||
|
||||
template < int N >
|
||||
struct answer
|
||||
{
|
||||
static constexpr int value = N;
|
||||
};
|
||||
|
||||
answer<1> f(int&) { return answer<1>(); }
|
||||
answer<2> f(const int&) { return answer<2>(); }
|
||||
answer<3> f(int&&) { return answer<3>(); }
|
||||
|
||||
void
|
||||
test()
|
||||
{
|
||||
int i = 0;
|
||||
const int c = 0;
|
||||
static_assert(decltype(f(i))::value == 1, "");
|
||||
static_assert(decltype(f(c))::value == 2, "");
|
||||
static_assert(decltype(f(0))::value == 3, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_uniform_initialization
|
||||
{
|
||||
|
||||
struct test
|
||||
{
|
||||
static const int zero {};
|
||||
static const int one {1};
|
||||
};
|
||||
|
||||
static_assert(test::zero == 0, "");
|
||||
static_assert(test::one == 1, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambdas
|
||||
{
|
||||
|
||||
void
|
||||
test1()
|
||||
{
|
||||
auto lambda1 = [](){};
|
||||
auto lambda2 = lambda1;
|
||||
lambda1();
|
||||
lambda2();
|
||||
}
|
||||
|
||||
int
|
||||
test2()
|
||||
{
|
||||
auto a = [](int i, int j){ return i + j; }(1, 2);
|
||||
auto b = []() -> int { return '0'; }();
|
||||
auto c = [=](){ return a + b; }();
|
||||
auto d = [&](){ return c; }();
|
||||
auto e = [a, &b](int x) mutable {
|
||||
const auto identity = [](int y){ return y; };
|
||||
for (auto i = 0; i < a; ++i)
|
||||
a += b--;
|
||||
return x + identity(a + b);
|
||||
}(0);
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
int
|
||||
test3()
|
||||
{
|
||||
const auto nullary = [](){ return 0; };
|
||||
const auto unary = [](int x){ return x; };
|
||||
using nullary_t = decltype(nullary);
|
||||
using unary_t = decltype(unary);
|
||||
const auto higher1st = [](nullary_t f){ return f(); };
|
||||
const auto higher2nd = [unary](nullary_t f1){
|
||||
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
|
||||
};
|
||||
return higher1st(nullary) + higher2nd(nullary)(unary);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_variadic_templates
|
||||
{
|
||||
|
||||
template <int...>
|
||||
struct sum;
|
||||
|
||||
template <int N0, int... N1toN>
|
||||
struct sum<N0, N1toN...>
|
||||
{
|
||||
static constexpr auto value = N0 + sum<N1toN...>::value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct sum<>
|
||||
{
|
||||
static constexpr auto value = 0;
|
||||
};
|
||||
|
||||
static_assert(sum<>::value == 0, "");
|
||||
static_assert(sum<1>::value == 1, "");
|
||||
static_assert(sum<23>::value == 23, "");
|
||||
static_assert(sum<1, 2>::value == 3, "");
|
||||
static_assert(sum<5, 5, 11>::value == 21, "");
|
||||
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
|
||||
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
{
|
||||
|
||||
struct foo {};
|
||||
|
||||
template<typename T>
|
||||
using member = typename T::member_type;
|
||||
|
||||
template<typename T>
|
||||
void func(...) {}
|
||||
|
||||
template<typename T>
|
||||
void func(member<T>*) {}
|
||||
|
||||
void test();
|
||||
|
||||
void test() { func<foo>(0); }
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx11
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++14
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++14, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201300L
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx14
|
||||
{
|
||||
|
||||
namespace test_polymorphic_lambdas
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
const auto lambda = [](auto&&... args){
|
||||
const auto istiny = [](auto x){
|
||||
return (sizeof(x) == 1UL) ? 1 : 0;
|
||||
};
|
||||
const int aretiny[] = { istiny(args)... };
|
||||
return aretiny[0];
|
||||
};
|
||||
return lambda(1, 1L, 1.0f, '1');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_binary_literals
|
||||
{
|
||||
|
||||
constexpr auto ivii = 0b0000000000101010;
|
||||
static_assert(ivii == 42, "wrong value");
|
||||
|
||||
}
|
||||
|
||||
#ifdef DISALLOW_GCC48
|
||||
namespace test_generalized_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
constexpr unsigned long
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
auto length = 0UL;
|
||||
for (auto p = s; *p; ++p)
|
||||
++length;
|
||||
return length;
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("x") == 1UL, "");
|
||||
static_assert(strlen_c("test") == 4UL, "");
|
||||
static_assert(strlen_c("another\0test") == 7UL, "");
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace test_lambda_init_capture
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
const auto lambda1 = [a = x](int b){ return a + b; };
|
||||
const auto lambda2 = [a = lambda1(x)](){ return a; };
|
||||
return lambda2();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_digit_seperators
|
||||
{
|
||||
|
||||
constexpr auto ten_million = 100'000'000;
|
||||
static_assert(ten_million == 100000000, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_return_type_deduction
|
||||
{
|
||||
|
||||
auto f(int& x) { return x; }
|
||||
decltype(auto) g(int& x) { return x; }
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
static_assert(is_same<int, decltype(f(x))>::value, "");
|
||||
static_assert(is_same<int&, decltype(g(x))>::value, "");
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx14
|
||||
|
||||
#endif // __cplusplus >= 201402L
|
||||
|
||||
]])
|
@@ -1,107 +0,0 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_0x.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_0X
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++0x
|
||||
# standard.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 7
|
||||
|
||||
AU_ALIAS([AC_CXX_COMPILE_STDCXX_0X], [AX_CXX_COMPILE_STDCXX_0X])
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_0X], [
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features without additional flags,
|
||||
ax_cv_cxx_compile_cxx0x_native,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_native=yes, ax_cv_cxx_compile_cxx0x_native=no)
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=c++0x,
|
||||
ax_cv_cxx_compile_cxx0x_cxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=c++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_cxx=yes, ax_cv_cxx_compile_cxx0x_cxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=gnu++0x,
|
||||
ax_cv_cxx_compile_cxx0x_gxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_gxx=yes, ax_cv_cxx_compile_cxx0x_gxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
if test "$ax_cv_cxx_compile_cxx0x_native" = yes ||
|
||||
test "$ax_cv_cxx_compile_cxx0x_cxx" = yes ||
|
||||
test "$ax_cv_cxx_compile_cxx0x_gxx" = yes; then
|
||||
AC_DEFINE(HAVE_STDCXX_0X,,[Define if g++ supports C++0x features. ])
|
||||
fi
|
||||
])
|
34
m4/ax_cxx_compile_stdcxx_14.m4
Normal file
34
m4/ax_cxx_compile_stdcxx_14.m4
Normal file
@@ -0,0 +1,34 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_14([ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++14
|
||||
# standard; if necessary, add switches to CXX and CXXCPP to enable
|
||||
# support.
|
||||
#
|
||||
# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
|
||||
# macro with the version set to C++14. The two optional arguments are
|
||||
# forwarded literally as the second and third argument respectively.
|
||||
# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
|
||||
# more information. If you want to use this macro, you also need to
|
||||
# download the ax_cxx_compile_stdcxx.m4 file.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 4
|
||||
|
||||
AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [AX_CXX_COMPILE_STDCXX([14], [$1], [$2])])
|
349
m4/ax_pthread.m4
349
m4/ax_pthread.m4
@@ -19,10 +19,10 @@
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
@@ -30,8 +30,8 @@
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
@@ -82,35 +82,40 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
#serial 23
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
@@ -123,7 +128,7 @@ fi
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
@@ -132,82 +137,225 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case ${host_os} in
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
darwin*)
|
||||
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clang doesn't consider unrecognized options an error unless we specify
|
||||
# -Werror. We throw in some extra Clang-specific options to ensure that
|
||||
# this doesn't happen for GCC, which also accepts -Werror.
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_extra_flags="-Werror"
|
||||
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ax_pthread_extra_flags=
|
||||
AC_MSG_RESULT([no])])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $flag in
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
ax_pthread_clang_warning=no
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
PTHREAD_CFLAGS="-pthread"
|
||||
PTHREAD_LIBS=
|
||||
|
||||
ax_pthread_ok=yes
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-mt,pthread)
|
||||
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
|
||||
PTHREAD_CFLAGS="-mt"
|
||||
PTHREAD_LIBS="-lpthread"
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
@@ -218,7 +366,11 @@ for flag in $ax_pthread_flags; do
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
@@ -230,13 +382,11 @@ for flag in $ax_pthread_flags; do
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
@@ -244,62 +394,65 @@ done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT([$attr_name])
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case ${host_os} in
|
||||
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||
osf* | hpux*) flag="-D_REENTRANT";;
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
# TODO: What about Clang on Solaris?
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$flag])
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != xyes; then
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
@@ -321,7 +474,7 @@ AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
|
73
m4/faad.m4
73
m4/faad.m4
@@ -1,73 +0,0 @@
|
||||
AC_DEFUN([AM_PATH_FAAD],
|
||||
[dnl ##
|
||||
dnl faad
|
||||
dnl ##
|
||||
|
||||
AC_ARG_ENABLE(aac,
|
||||
AS_HELP_STRING([--disable-aac],
|
||||
[disable AAC support (default: enable)]),,
|
||||
enable_aac=yes)
|
||||
|
||||
if test x$enable_aac = xyes; then
|
||||
FAAD_LIBS="-lfaad"
|
||||
FAAD_CFLAGS=""
|
||||
|
||||
oldcflags=$CFLAGS
|
||||
oldlibs=$LIBS
|
||||
oldcppflags=$CPPFLAGS
|
||||
CFLAGS="$CFLAGS $FAAD_CFLAGS"
|
||||
LIBS="$LIBS $FAAD_LIBS"
|
||||
CPPFLAGS=$CFLAGS
|
||||
AC_CHECK_HEADER(faad.h,,enable_aac=no)
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_CHECK_DECL(FAAD2_VERSION,,enable_aac=no,[#include <faad.h>])
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_CHECK_LIB(faad,NeAACDecInit2,,enable_aac=no)
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_MSG_CHECKING(that FAAD2 can even be used)
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <faad.h>
|
||||
|
||||
int main() {
|
||||
char buffer;
|
||||
NeAACDecHandle decoder;
|
||||
NeAACDecFrameInfo frameInfo;
|
||||
NeAACDecConfigurationPtr config;
|
||||
unsigned char channels;
|
||||
long sampleRate;
|
||||
long bufferlen = 0;
|
||||
|
||||
decoder = NeAACDecOpen();
|
||||
config = NeAACDecGetCurrentConfiguration(decoder);
|
||||
config->outputFormat = FAAD_FMT_16BIT;
|
||||
NeAACDecSetConfiguration(decoder,config);
|
||||
NeAACDecInit(decoder,&buffer,bufferlen,&sampleRate,&channels);
|
||||
NeAACDecInit2(decoder,&buffer,bufferlen,&sampleRate,&channels);
|
||||
NeAACDecDecode(decoder,&frameInfo,&buffer,bufferlen);
|
||||
NeAACDecClose(decoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
])],AC_MSG_RESULT(yes),[AC_MSG_RESULT(no);enable_aac=no])
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_DEFINE(HAVE_FAAD,1,[Define to use FAAD2 for AAC decoding])
|
||||
else
|
||||
AC_MSG_WARN([faad2 lib needed for MP4/AAC support -- disabling MP4/AAC support])
|
||||
fi
|
||||
CFLAGS=$oldcflags
|
||||
LIBS=$oldlibs
|
||||
CPPFLAGS=$oldcppflags
|
||||
fi
|
||||
|
||||
if test x$enable_aac = xno; then
|
||||
FAAD_LIBS=""
|
||||
FAAD_CFLAGS=""
|
||||
fi
|
||||
|
||||
AC_SUBST(FAAD_CFLAGS)
|
||||
AC_SUBST(FAAD_LIBS)
|
||||
|
||||
])
|
201
m4/mpd_auto.m4
201
m4/mpd_auto.m4
@@ -1,23 +1,18 @@
|
||||
dnl Parameters: varname1, description
|
||||
AC_DEFUN([MPD_AUTO_ENABLED], [
|
||||
var="enable_$1"
|
||||
feature="$2"
|
||||
|
||||
if eval "test x`echo '$'$var` = xauto"; then
|
||||
AC_MSG_NOTICE([auto-detected $feature])
|
||||
eval "$var=yes"
|
||||
if test x$[]enable_$1 = xauto; then
|
||||
AC_MSG_NOTICE([auto-detected $2])
|
||||
enable_$1=yes
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Parameters: varname1, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_DISABLED], [
|
||||
var="enable_$1"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` = xauto"; then
|
||||
AC_MSG_WARN([$msg -- disabling $feature])
|
||||
eval "$var=no"
|
||||
elif eval "test x`echo '$'$var` = xyes"; then
|
||||
AC_MSG_ERROR([$feature: $msg])
|
||||
if test x$[]enable_$1 = xauto; then
|
||||
AC_MSG_WARN([$3 -- disabling $2])
|
||||
enable_$1=no
|
||||
elif test x$[]enable_$1 = xyes; then
|
||||
AC_MSG_ERROR([$2: $3])
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -25,59 +20,59 @@ dnl Check whether a prerequisite for a feature was found. This is
|
||||
dnl very similar to MPD_AUTO_RESULT, but does not finalize the
|
||||
dnl detection; it assumes that more checks will follow.
|
||||
AC_DEFUN([MPD_AUTO_PRE], [
|
||||
name="$1"
|
||||
var="enable_$1"
|
||||
found="found_$name"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` != xno" && eval "test x`echo '$'$found` = xno"; then
|
||||
MPD_AUTO_DISABLED([$name], [$feature], [$msg])
|
||||
if test x$[]enable_$1 != xno && test x$[]found_$1 = xno; then
|
||||
MPD_AUTO_DISABLED([$1], [$2], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Evaluate a check's result. Abort if the feature was requested
|
||||
dnl explicitly but is unavailable.
|
||||
dnl
|
||||
dnl Parameters: varname1, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_RESULT], [
|
||||
name="$1"
|
||||
var="enable_$1"
|
||||
found="found_$name"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` = xno"; then
|
||||
eval "$found=no"
|
||||
if test x$[]enable_$1 = xno; then
|
||||
found_$1=no
|
||||
fi
|
||||
|
||||
if eval "test x`echo '$'$found` = xyes"; then
|
||||
MPD_AUTO_ENABLED([$name], [$feature])
|
||||
if test x$[]found_$1 = xyes; then
|
||||
MPD_AUTO_ENABLED([$1], [$2])
|
||||
else
|
||||
MPD_AUTO_DISABLED([$name], [$feature], [$msg])
|
||||
MPD_AUTO_DISABLED([$1], [$2], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([MPD_AUTO_PKG], [
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
PKG_CHECK_MODULES([$2], [$3],
|
||||
[eval "found_$1=yes"],
|
||||
[eval "found_$1=no"])
|
||||
dnl Invoke a check if its configuration is "yes" or "auto" and call
|
||||
dnl MPD_AUTO_RESULT.
|
||||
dnl
|
||||
dnl Parameters: varname1, description, errmsg, check
|
||||
AC_DEFUN([MPD_AUTO], [
|
||||
if test x$[]enable_$1 != xno; then
|
||||
$4
|
||||
fi
|
||||
MPD_AUTO_RESULT([$1], [$2], [$3])
|
||||
])
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$4], [$5])
|
||||
dnl Wrapper for MPD_AUTO and PKG_CHECK_MODULES.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkgname, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_PKG], [
|
||||
MPD_AUTO([$1], [$4], [$5],
|
||||
[PKG_CHECK_MODULES([$2], [$3],
|
||||
[found_$1=yes],
|
||||
[found_$1=no])])
|
||||
])
|
||||
|
||||
dnl Check with pkg-config first, fall back to AC_CHECK_LIB.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkgname, libname, symname, libs, cflags, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_PKG_LIB], [
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
PKG_CHECK_MODULES([$2], [$3],
|
||||
[eval "found_$1=yes"],
|
||||
MPD_AUTO([$1], [$8], [$9],
|
||||
[PKG_CHECK_MODULES([$2], [$3],
|
||||
[found_$1=yes],
|
||||
AC_CHECK_LIB($4, $5,
|
||||
[eval "found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'"],
|
||||
[eval "found_$1=no"],
|
||||
[$6]))
|
||||
fi
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$8], [$9])
|
||||
[found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'],
|
||||
[found_$1=no],
|
||||
[$6]))])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_CHECK_LIB.
|
||||
@@ -87,12 +82,104 @@ AC_DEFUN([MPD_AUTO_LIB], [
|
||||
AC_SUBST([$2_LIBS], [])
|
||||
AC_SUBST([$2_CFLAGS], [])
|
||||
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
AC_CHECK_LIB($3, $4,
|
||||
[eval "found_$1=yes $2_LIBS='$5' $2_CFLAGS='$6'"],
|
||||
[eval "found_$1=no"],
|
||||
[$5])
|
||||
fi
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$7], [$8])
|
||||
MPD_AUTO([$1], [$7], [$8],
|
||||
[AC_CHECK_LIB($3, $4,
|
||||
[found_$1=yes $2_LIBS='$5' $2_CFLAGS='$6'],
|
||||
[found_$1=no],
|
||||
[$5])])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_CHECK_HEADER.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, header, libs, cflags, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_HEADER], [
|
||||
AC_SUBST([$2_LIBS], [])
|
||||
AC_SUBST([$2_CFLAGS], [])
|
||||
|
||||
MPD_AUTO([$1], [$6], [$7],
|
||||
[AC_CHECK_HEADER([$3],
|
||||
[found_$1=yes $2_LIBS='$4' $2_CFLAGS='$5'],
|
||||
[found_$1=no])])
|
||||
])
|
||||
|
||||
dnl Convert the given string into a string for the "default value" in
|
||||
dnl the help text. If the string is a literal, then it is returned
|
||||
dnl as-is; if it contains a variable reference, just "auto" is
|
||||
dnl emitted.
|
||||
dnl
|
||||
dnl Parameters: varname1
|
||||
AC_DEFUN([MPD_FORMAT_DEFAULT],
|
||||
[ifelse([$1], [], [auto],
|
||||
index([$1], [$]), [-1], [$1],
|
||||
[auto])])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE, AC_DEFINE and AM_CONDITIONAL
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description, default, check
|
||||
AC_DEFUN([MPD_ARG_ENABLE], [
|
||||
AC_ARG_ENABLE(translit([$1], [_], [-]),
|
||||
AS_HELP_STRING([--enable-]translit([$1], [_], [-]),
|
||||
[enable $3 (default: ]MPD_FORMAT_DEFAULT([$4])[)]),,
|
||||
[enable_$1=]ifelse([$4], [], [auto], [$4]))
|
||||
|
||||
$5
|
||||
|
||||
MPD_DEFINE_CONDITIONAL(enable_$1, ENABLE_$2, [$3])
|
||||
])
|
||||
|
||||
dnl Wrapper for MPD_ARG_ENABLE and MPD_AUTO
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description, errmsg, default, check
|
||||
AC_DEFUN([MPD_ENABLE_AUTO], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$3], [$5], [
|
||||
MPD_AUTO([$1], [$3], [$4], [$6])
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_PKG
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$4], [$6], [
|
||||
$7
|
||||
MPD_AUTO_PKG($1, $2, $3, $4, $5)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_PKG_LIB
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, libname, symname, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG_LIB], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$8], [$10], [
|
||||
$11
|
||||
MPD_AUTO_PKG_LIB($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_LIB
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, libname, symname, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_LIB], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$7], [$9], [
|
||||
$10
|
||||
MPD_AUTO_LIB($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_HEADER
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, header, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_HEADER], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$6], [$8], [
|
||||
$9
|
||||
MPD_AUTO_HEADER($1, $2, $3, $4, $5, $6, $7)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for MPD_ENABLE_AUTO_PKG and MPD_DEPENDS
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, description, errmsg, default, dep_variable, dep_errmsg
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG_DEPENDS], [
|
||||
MPD_ENABLE_AUTO_PKG([$1], [$2], [$3], [$4], [$5], [$6],
|
||||
[MPD_DEPENDS([enable_$1], [$7], [$8])])
|
||||
])
|
||||
|
8
m4/mpd_define_conditional.m4
Normal file
8
m4/mpd_define_conditional.m4
Normal file
@@ -0,0 +1,8 @@
|
||||
dnl Wrapper for AC_DEFINE and AM_CONDITIONAL
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description
|
||||
AC_DEFUN([MPD_DEFINE_CONDITIONAL], [dnl
|
||||
AM_CONDITIONAL($2, test x$[]$1 = xyes)
|
||||
if test x$[]$1 = xyes; then
|
||||
AC_DEFINE($2, 1, [Define to enable $3])
|
||||
fi])
|
@@ -6,7 +6,7 @@ AC_DEFUN([MPD_OPTIONAL_FUNC], [
|
||||
AC_ARG_ENABLE([$1],
|
||||
AS_HELP_STRING([--enable-$1],
|
||||
[use the function "$1" (default: auto)]),
|
||||
[test xenable_$1 = xyes && AC_DEFINE([$3], 1, [Define to use $1])],
|
||||
[test x$[]enable_$1 = xyes && AC_DEFINE([$3], 1, [Define to use $1])],
|
||||
[AC_CHECK_FUNC([$2],
|
||||
[AC_DEFINE([$3], 1, [Define to use $1])],)])
|
||||
])
|
||||
|
23
m4/mpd_with_flags.m4
Normal file
23
m4/mpd_with_flags.m4
Normal file
@@ -0,0 +1,23 @@
|
||||
dnl Run code with the specified CFLAGS/CXXFLAGS and LIBS appended.
|
||||
dnl Restores the old values afterwards.
|
||||
dnl
|
||||
dnl Parameters: cflags, libs, code
|
||||
AC_DEFUN([MPD_WITH_FLAGS], [
|
||||
ac_save_CFLAGS="$[]CFLAGS"
|
||||
ac_save_CXXFLAGS="$[]CXXFLAGS"
|
||||
ac_save_LIBS="$[]LIBS"
|
||||
CFLAGS="$[]CFLAGS $1"
|
||||
CXXFLAGS="$[]CXXFLAGS $1"
|
||||
LIBS="$[]LIBS $2"
|
||||
$3
|
||||
CFLAGS="$[]ac_save_CFLAGS"
|
||||
CXXFLAGS="$[]ac_save_CXXFLAGS"
|
||||
LIBS="$[]ac_save_LIBS"
|
||||
])
|
||||
|
||||
dnl Run code with the specified library's CFLAGS/CXXFLAGS and LIBS
|
||||
dnl appended. Restores the old values afterwards.
|
||||
dnl
|
||||
dnl Parameters: libname, code
|
||||
AC_DEFUN([MPD_WITH_LIBRARY],
|
||||
[MPD_WITH_FLAGS([$[]$1_CFLAGS], [$[]$1_LIBS], [$2])])
|
209
m4/pkg.m4
209
m4/pkg.m4
@@ -1,29 +1,60 @@
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program 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 Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29)
|
||||
dnl
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
dnl 02111-1307, USA.
|
||||
dnl
|
||||
dnl As a special exception to the GNU General Public License, if you
|
||||
dnl distribute this file as part of a program that contains a
|
||||
dnl configuration script generated by Autoconf, you may include it under
|
||||
dnl the same distribution terms that you use for the rest of that
|
||||
dnl program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
dnl PKG_PREREQ(MIN-VERSION)
|
||||
dnl -----------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Verify that the version of the pkg-config macros are at least
|
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||
dnl installed version of pkg-config, this checks the developer's version
|
||||
dnl of pkg.m4 when generating configure.
|
||||
dnl
|
||||
dnl To ensure that this macro is defined, also add:
|
||||
dnl m4_ifndef([PKG_PREREQ],
|
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||
dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
dnl ----------------------------------
|
||||
dnl Since: 0.16
|
||||
dnl
|
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||
dnl first found in the path. Checks that the version of pkg-config found
|
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||
dnl used since that's the first version where most current features of
|
||||
dnl pkg-config existed.
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
@@ -45,18 +76,19 @@ if test -n "$PKG_CONFIG"; then
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
])dnl PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------------------------------
|
||||
dnl Since: 0.18
|
||||
dnl
|
||||
dnl Check to see whether a particular set of modules exists. Similar to
|
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
dnl
|
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
dnl only at the first occurence in configure.ac, so if the first place
|
||||
dnl it's called might be skipped (such as if it is within an "if", you
|
||||
dnl have to call PKG_CHECK_EXISTS manually
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
@@ -66,8 +98,10 @@ m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
dnl ---------------------------------------------
|
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||
dnl pkg_failed based on the result.
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
@@ -79,10 +113,11 @@ m4_define([_PKG_CONFIG],
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
])dnl _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
dnl ---------------------------
|
||||
dnl Internal check to see if pkg-config supports short errors.
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
@@ -90,19 +125,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Since: 0.4.0
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
@@ -156,16 +189,40 @@ else
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
])dnl PKG_CHECK_MODULES
|
||||
|
||||
|
||||
# PKG_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable pkgconfigdir as the location where a module
|
||||
# should install pkg-config .pc files. By default the directory is
|
||||
# $libdir/pkgconfig, but the default can be changed by passing
|
||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
# parameter.
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Checks for existence of MODULES and gathers its build flags with
|
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||
dnl configure.ac.
|
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
_save_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES($@)
|
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||
])dnl PKG_CHECK_MODULES_STATIC
|
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||
dnl -------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||
dnl should install pkg-config .pc files. By default the directory is
|
||||
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
dnl parameter.
|
||||
AC_DEFUN([PKG_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -176,16 +233,18 @@ AC_ARG_WITH([pkgconfigdir],
|
||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_INSTALLDIR
|
||||
])dnl PKG_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
# module should install arch-independent pkg-config .pc files. By
|
||||
# default the directory is $datadir/pkgconfig, but the default can be
|
||||
# changed by passing DIRECTORY. The user can override through the
|
||||
# --with-noarch-pkgconfigdir parameter.
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||
dnl --------------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
dnl module should install arch-independent pkg-config .pc files. By
|
||||
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||
dnl changed by passing DIRECTORY. The user can override through the
|
||||
dnl --with-noarch-pkgconfigdir parameter.
|
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -196,13 +255,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
|
||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_NOARCH_INSTALLDIR
|
||||
])dnl PKG_NOARCH_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# -------------------------------------------
|
||||
# Retrieves the value of the pkg-config variable for the given module.
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------
|
||||
dnl Since: 0.28
|
||||
dnl
|
||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
@@ -211,4 +272,4 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
@@ -1,16 +1,6 @@
|
||||
AC_DEFUN([results], [
|
||||
dnl This is a hack to allow "with" names, otherwise "enable".
|
||||
num=`expr $1 : 'with'`
|
||||
if test "$num" != "0"; then
|
||||
var="`echo '$'$1`"
|
||||
else
|
||||
var="`echo '$'enable_$1`"
|
||||
fi
|
||||
|
||||
printf '('
|
||||
if eval "test x$var = xyes"; then
|
||||
printf '+'
|
||||
elif test -n "$3" && eval "test x$var = x$3"; then
|
||||
if test x$[]enable_$1 = xyes; then
|
||||
printf '+'
|
||||
else
|
||||
printf '-'
|
||||
|
@@ -1,6 +1,6 @@
|
||||
# Check if "struct ucred" is available.
|
||||
#
|
||||
# Author: Max Kellermann <max@duempel.org>
|
||||
# Author: Max Kellermann <max.kellermann@gmail.com>
|
||||
|
||||
AC_DEFUN([STRUCT_UCRED],[
|
||||
AC_MSG_CHECKING([for struct ucred])
|
||||
|
60
python/build/autotools.py
Normal file
60
python/build/autotools.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import os.path, subprocess, sys
|
||||
|
||||
from build.makeproject import MakeProject
|
||||
|
||||
class AutotoolsProject(MakeProject):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
autogen=False,
|
||||
cppflags='',
|
||||
ldflags='',
|
||||
libs='',
|
||||
subdirs=None,
|
||||
**kwargs):
|
||||
MakeProject.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.autogen = autogen
|
||||
self.cppflags = cppflags
|
||||
self.ldflags = ldflags
|
||||
self.libs = libs
|
||||
self.subdirs = subdirs
|
||||
|
||||
def configure(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
if self.autogen:
|
||||
if sys.platform == 'darwin':
|
||||
subprocess.check_call(['glibtoolize', '--force'], cwd=src)
|
||||
else:
|
||||
subprocess.check_call(['libtoolize', '--force'], cwd=src)
|
||||
subprocess.check_call(['aclocal'], cwd=src)
|
||||
subprocess.check_call(['automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
|
||||
subprocess.check_call(['autoconf'], cwd=src)
|
||||
|
||||
build = self.make_build_path(toolchain)
|
||||
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'CC=' + toolchain.cc,
|
||||
'CXX=' + toolchain.cxx,
|
||||
'CFLAGS=' + toolchain.cflags,
|
||||
'CXXFLAGS=' + toolchain.cxxflags,
|
||||
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
|
||||
'LIBS=' + toolchain.libs + ' ' + self.libs,
|
||||
'AR=' + toolchain.ar,
|
||||
'RANLIB=' + toolchain.ranlib,
|
||||
'STRIP=' + toolchain.strip,
|
||||
'--host=' + toolchain.arch,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
'--enable-silent-rules',
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||
return build
|
||||
|
||||
def build(self, toolchain):
|
||||
build = self.configure(toolchain)
|
||||
if self.subdirs is not None:
|
||||
for subdir in self.subdirs:
|
||||
MakeProject.build(self, toolchain, os.path.join(build, subdir))
|
||||
else:
|
||||
MakeProject.build(self, toolchain, build)
|
23
python/build/boost.py
Normal file
23
python/build/boost.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import os, shutil
|
||||
import re
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class BoostProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
m = re.match(r'.*/boost_(\d+)_(\d+)_(\d+)\.tar\.bz2$', url)
|
||||
version = "%s.%s.%s" % (m.group(1), m.group(2), m.group(3))
|
||||
Project.__init__(self, url, md5, installed,
|
||||
name='boost', version=version,
|
||||
**kwargs)
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
|
||||
# install the headers manually; don't build any library
|
||||
# (because right now, we only use header-only libraries)
|
||||
includedir = os.path.join(toolchain.install_prefix, 'include')
|
||||
dest = os.path.join(includedir, 'boost')
|
||||
shutil.rmtree(dest, ignore_errors=True)
|
||||
shutil.copytree(os.path.join(src, 'boost'), dest)
|
29
python/build/cmdline.py
Normal file
29
python/build/cmdline.py
Normal file
@@ -0,0 +1,29 @@
|
||||
def concatenate_cmdline_variables(src, names):
|
||||
"""Find duplicate variable declarations on the given source list, and
|
||||
concatenate the values of those in the 'names' list."""
|
||||
|
||||
# the result list being constructed
|
||||
dest = []
|
||||
|
||||
# a map of variable name to destination list index
|
||||
positions = {}
|
||||
|
||||
for item in src:
|
||||
i = item.find('=')
|
||||
if i > 0:
|
||||
# it's a variable
|
||||
name = item[:i]
|
||||
if name in names:
|
||||
# it's a known variable
|
||||
if name in positions:
|
||||
# already specified: concatenate instead of
|
||||
# appending it
|
||||
dest[positions[name]] += ' ' + item[i + 1:]
|
||||
continue
|
||||
else:
|
||||
# not yet seen: append it and remember the list
|
||||
# index
|
||||
positions[name] = len(dest)
|
||||
dest.append(item)
|
||||
|
||||
return dest
|
9
python/build/dirs.py
Normal file
9
python/build/dirs.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import os.path
|
||||
|
||||
lib_path = os.path.abspath('lib')
|
||||
|
||||
shared_path = lib_path
|
||||
if 'MPD_SHARED_LIB' in os.environ:
|
||||
shared_path = os.environ['MPD_SHARED_LIB']
|
||||
tarball_path = os.path.join(shared_path, 'download')
|
||||
src_path = os.path.join(shared_path, 'src')
|
26
python/build/download.py
Normal file
26
python/build/download.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from build.verify import verify_file_digest
|
||||
import os
|
||||
import urllib.request
|
||||
|
||||
def download_and_verify(url, md5, parent_path):
|
||||
"""Download a file, verify its MD5 checksum and return the local path."""
|
||||
|
||||
os.makedirs(parent_path, exist_ok=True)
|
||||
path = os.path.join(parent_path, os.path.basename(url))
|
||||
|
||||
try:
|
||||
if verify_file_digest(path, md5): return path
|
||||
os.unlink(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
tmp_path = path + '.tmp'
|
||||
|
||||
print("download", url)
|
||||
urllib.request.urlretrieve(url, tmp_path)
|
||||
if not verify_file_digest(tmp_path, md5):
|
||||
os.unlink(tmp_path)
|
||||
raise RuntimeError("Digest mismatch")
|
||||
|
||||
os.rename(tmp_path, path)
|
||||
return path
|
54
python/build/ffmpeg.py
Normal file
54
python/build/ffmpeg.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import os.path, subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class FfmpegProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.cppflags = cppflags
|
||||
|
||||
def _filter_cflags(self, flags):
|
||||
# FFmpeg expects the GNU as syntax
|
||||
flags = flags.replace(' -integrated-as ', ' -no-integrated-as ')
|
||||
return flags
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
build = self.make_build_path(toolchain)
|
||||
|
||||
if toolchain.is_arm:
|
||||
arch = 'arm'
|
||||
else:
|
||||
arch = 'x86'
|
||||
|
||||
if toolchain.is_windows:
|
||||
target_os = 'mingw32'
|
||||
else:
|
||||
target_os = 'linux'
|
||||
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'--cc=' + toolchain.cc,
|
||||
'--cxx=' + toolchain.cxx,
|
||||
'--nm=' + toolchain.nm,
|
||||
'--extra-cflags=' + self._filter_cflags(toolchain.cflags) + ' ' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'--extra-cxxflags=' + self._filter_cflags(toolchain.cxxflags) + ' ' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'--extra-ldflags=' + toolchain.ldflags,
|
||||
'--extra-libs=' + toolchain.libs,
|
||||
'--ar=' + toolchain.ar,
|
||||
'--ranlib=' + toolchain.ranlib,
|
||||
'--enable-cross-compile',
|
||||
'--arch=' + arch,
|
||||
'--target-os=' + target_os,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
] + self.configure_args
|
||||
|
||||
if toolchain.is_armv7:
|
||||
configure.append('--cpu=cortex-a8')
|
||||
|
||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build, env=toolchain.env)
|
367
python/build/libs.py
Normal file
367
python/build/libs.py
Normal file
@@ -0,0 +1,367 @@
|
||||
import re
|
||||
from build.project import Project
|
||||
from build.zlib import ZlibProject
|
||||
from build.autotools import AutotoolsProject
|
||||
from build.ffmpeg import FfmpegProject
|
||||
from build.boost import BoostProject
|
||||
|
||||
libogg = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz',
|
||||
'4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08',
|
||||
'lib/libogg.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
],
|
||||
)
|
||||
|
||||
libvorbis = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz',
|
||||
'28cb28097c07a735d6af56e598e1c90f',
|
||||
'lib/libvorbis.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
],
|
||||
)
|
||||
|
||||
opus = AutotoolsProject(
|
||||
'https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz',
|
||||
'cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732',
|
||||
'lib/libopus.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-doc',
|
||||
'--disable-extra-programs',
|
||||
],
|
||||
|
||||
# suppress "visibility default" from opus_defines.h
|
||||
cppflags='-DOPUS_EXPORT=',
|
||||
)
|
||||
|
||||
flac = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/flac/flac-1.3.2.tar.xz',
|
||||
'91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f',
|
||||
'lib/libFLAC.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||
'--disable-doxygen-docs',
|
||||
],
|
||||
subdirs=['include', 'src/libFLAC'],
|
||||
)
|
||||
|
||||
zlib = ZlibProject(
|
||||
'http://zlib.net/zlib-1.2.11.tar.xz',
|
||||
'4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066',
|
||||
'lib/libz.a',
|
||||
)
|
||||
|
||||
libid3tag = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
|
||||
'e5808ad997ba32c498803822078748c3',
|
||||
'lib/libid3tag.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
|
||||
# without this, libid3tag's configure.ac ignores -O* and -f*
|
||||
'--disable-debugging',
|
||||
],
|
||||
autogen=True,
|
||||
|
||||
edits={
|
||||
# fix bug in libid3tag's configure.ac which discards all but the last optimization flag
|
||||
'configure.ac': lambda data: re.sub(r'optimize="\$1"', r'optimize="$optimize $1"', data, count=1),
|
||||
}
|
||||
)
|
||||
|
||||
libmad = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
|
||||
'1be543bc30c56fb6bea1d7bf6a64e66c',
|
||||
'lib/libmad.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
|
||||
# without this, libmad's configure.ac ignores -O* and -f*
|
||||
'--disable-debugging',
|
||||
],
|
||||
autogen=True,
|
||||
)
|
||||
|
||||
liblame = AutotoolsProject(
|
||||
'http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz',
|
||||
'ddfe36cab873794038ae2c1210557ad34857a4b6bdc515785d1da9e175b1da1e',
|
||||
'lib/libmp3lame.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-gtktest', '--disable-analyzer-hooks',
|
||||
'--disable-decoder', '--disable-frontend',
|
||||
],
|
||||
)
|
||||
|
||||
ffmpeg = FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.xz',
|
||||
'5a77278a63741efa74e26bf197b9bb09ac6381b9757391b922407210f0f991c0',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--enable-gpl',
|
||||
'--enable-small',
|
||||
'--disable-pthreads',
|
||||
'--disable-programs',
|
||||
'--disable-doc',
|
||||
'--disable-avdevice',
|
||||
'--disable-swresample',
|
||||
'--disable-swscale',
|
||||
'--disable-postproc',
|
||||
'--disable-avfilter',
|
||||
'--disable-lzo',
|
||||
'--disable-faan',
|
||||
'--disable-pixelutils',
|
||||
'--disable-network',
|
||||
'--disable-encoders',
|
||||
'--disable-muxers',
|
||||
'--disable-protocols',
|
||||
'--disable-devices',
|
||||
'--disable-filters',
|
||||
'--disable-filters',
|
||||
'--disable-v4l2_m2m',
|
||||
|
||||
'--disable-parser=bmp',
|
||||
'--disable-parser=cavsvideo',
|
||||
'--disable-parser=dvbsub',
|
||||
'--disable-parser=dvdsub',
|
||||
'--disable-parser=dvd_nav',
|
||||
'--disable-parser=flac',
|
||||
'--disable-parser=g729',
|
||||
'--disable-parser=gsm',
|
||||
'--disable-parser=h261',
|
||||
'--disable-parser=h263',
|
||||
'--disable-parser=h264',
|
||||
'--disable-parser=hevc',
|
||||
'--disable-parser=mjpeg',
|
||||
'--disable-parser=mlp',
|
||||
'--disable-parser=mpeg4video',
|
||||
'--disable-parser=mpegaudio',
|
||||
'--disable-parser=mpegvideo',
|
||||
'--disable-parser=opus',
|
||||
'--disable-parser=vc1',
|
||||
'--disable-parser=vp3',
|
||||
'--disable-parser=vp8',
|
||||
'--disable-parser=vp9',
|
||||
'--disable-parser=png',
|
||||
'--disable-parser=pnm',
|
||||
'--disable-parser=xma',
|
||||
|
||||
'--disable-demuxer=aqtitle',
|
||||
'--disable-demuxer=ass',
|
||||
'--disable-demuxer=bethsoftvid',
|
||||
'--disable-demuxer=bink',
|
||||
'--disable-demuxer=cavsvideo',
|
||||
'--disable-demuxer=cdxl',
|
||||
'--disable-demuxer=dvbsub',
|
||||
'--disable-demuxer=dvbtxt',
|
||||
'--disable-demuxer=h261',
|
||||
'--disable-demuxer=h263',
|
||||
'--disable-demuxer=h264',
|
||||
'--disable-demuxer=ico',
|
||||
'--disable-demuxer=image2',
|
||||
'--disable-demuxer=jacosub',
|
||||
'--disable-demuxer=lrc',
|
||||
'--disable-demuxer=microdvd',
|
||||
'--disable-demuxer=mjpeg',
|
||||
'--disable-demuxer=mjpeg_2000',
|
||||
'--disable-demuxer=mpegps',
|
||||
'--disable-demuxer=mpegvideo',
|
||||
'--disable-demuxer=mpl2',
|
||||
'--disable-demuxer=mpsub',
|
||||
'--disable-demuxer=pjs',
|
||||
'--disable-demuxer=rawvideo',
|
||||
'--disable-demuxer=realtext',
|
||||
'--disable-demuxer=sami',
|
||||
'--disable-demuxer=scc',
|
||||
'--disable-demuxer=srt',
|
||||
'--disable-demuxer=stl',
|
||||
'--disable-demuxer=subviewer',
|
||||
'--disable-demuxer=subviewer1',
|
||||
'--disable-demuxer=swf',
|
||||
'--disable-demuxer=tedcaptions',
|
||||
'--disable-demuxer=vobsub',
|
||||
'--disable-demuxer=vplayer',
|
||||
'--disable-demuxer=webvtt',
|
||||
'--disable-demuxer=yuv4mpegpipe',
|
||||
|
||||
# we don't need these decoders, because we have the dedicated
|
||||
# libraries
|
||||
'--disable-decoder=flac',
|
||||
'--disable-decoder=mp1',
|
||||
'--disable-decoder=mp1float',
|
||||
'--disable-decoder=mp2',
|
||||
'--disable-decoder=mp2float',
|
||||
'--disable-decoder=mp3',
|
||||
'--disable-decoder=mp3adu',
|
||||
'--disable-decoder=mp3adufloat',
|
||||
'--disable-decoder=mp3float',
|
||||
'--disable-decoder=mp3on4',
|
||||
'--disable-decoder=mp3on4float',
|
||||
'--disable-decoder=opus',
|
||||
'--disable-decoder=vorbis',
|
||||
|
||||
# audio codecs nobody uses
|
||||
'--disable-decoder=atrac1',
|
||||
'--disable-decoder=atrac3',
|
||||
'--disable-decoder=atrac3al',
|
||||
'--disable-decoder=atrac3p',
|
||||
'--disable-decoder=atrac3pal',
|
||||
'--disable-decoder=binkaudio_dct',
|
||||
'--disable-decoder=binkaudio_rdft',
|
||||
'--disable-decoder=bmv_audio',
|
||||
'--disable-decoder=dsicinaudio',
|
||||
'--disable-decoder=dvaudio',
|
||||
'--disable-decoder=metasound',
|
||||
'--disable-decoder=paf_audio',
|
||||
'--disable-decoder=ra_144',
|
||||
'--disable-decoder=ra_288',
|
||||
'--disable-decoder=ralf',
|
||||
'--disable-decoder=qdm2',
|
||||
'--disable-decoder=qdmc',
|
||||
|
||||
# disable lots of image and video codecs
|
||||
'--disable-decoder=ass',
|
||||
'--disable-decoder=asv1',
|
||||
'--disable-decoder=asv2',
|
||||
'--disable-decoder=apng',
|
||||
'--disable-decoder=avrn',
|
||||
'--disable-decoder=avrp',
|
||||
'--disable-decoder=bethsoftvid',
|
||||
'--disable-decoder=bink',
|
||||
'--disable-decoder=bmp',
|
||||
'--disable-decoder=bmv_video',
|
||||
'--disable-decoder=cavs',
|
||||
'--disable-decoder=ccaption',
|
||||
'--disable-decoder=cdgraphics',
|
||||
'--disable-decoder=clearvideo',
|
||||
'--disable-decoder=dirac',
|
||||
'--disable-decoder=dsicinvideo',
|
||||
'--disable-decoder=dvbsub',
|
||||
'--disable-decoder=dvdsub',
|
||||
'--disable-decoder=dvvideo',
|
||||
'--disable-decoder=exr',
|
||||
'--disable-decoder=ffv1',
|
||||
'--disable-decoder=ffvhuff',
|
||||
'--disable-decoder=ffwavesynth',
|
||||
'--disable-decoder=flic',
|
||||
'--disable-decoder=flv',
|
||||
'--disable-decoder=fraps',
|
||||
'--disable-decoder=gif',
|
||||
'--disable-decoder=h261',
|
||||
'--disable-decoder=h263',
|
||||
'--disable-decoder=h263i',
|
||||
'--disable-decoder=h263p',
|
||||
'--disable-decoder=h264',
|
||||
'--disable-decoder=hevc',
|
||||
'--disable-decoder=hnm4_video',
|
||||
'--disable-decoder=hq_hqa',
|
||||
'--disable-decoder=hqx',
|
||||
'--disable-decoder=idcin',
|
||||
'--disable-decoder=iff_ilbm',
|
||||
'--disable-decoder=indeo2',
|
||||
'--disable-decoder=indeo3',
|
||||
'--disable-decoder=indeo4',
|
||||
'--disable-decoder=indeo5',
|
||||
'--disable-decoder=interplay_video',
|
||||
'--disable-decoder=jacosub',
|
||||
'--disable-decoder=jpeg2000',
|
||||
'--disable-decoder=jpegls',
|
||||
'--disable-decoder=microdvd',
|
||||
'--disable-decoder=mimic',
|
||||
'--disable-decoder=mjpeg',
|
||||
'--disable-decoder=mmvideo',
|
||||
'--disable-decoder=mpl2',
|
||||
'--disable-decoder=motionpixels',
|
||||
'--disable-decoder=mpeg1video',
|
||||
'--disable-decoder=mpeg2video',
|
||||
'--disable-decoder=mpeg4',
|
||||
'--disable-decoder=mpegvideo',
|
||||
'--disable-decoder=mscc',
|
||||
'--disable-decoder=msmpeg4_crystalhd',
|
||||
'--disable-decoder=msmpeg4v1',
|
||||
'--disable-decoder=msmpeg4v2',
|
||||
'--disable-decoder=msmpeg4v3',
|
||||
'--disable-decoder=msvideo1',
|
||||
'--disable-decoder=mszh',
|
||||
'--disable-decoder=mvc1',
|
||||
'--disable-decoder=mvc2',
|
||||
'--disable-decoder=on2avc',
|
||||
'--disable-decoder=paf_video',
|
||||
'--disable-decoder=png',
|
||||
'--disable-decoder=qdraw',
|
||||
'--disable-decoder=qpeg',
|
||||
'--disable-decoder=rawvideo',
|
||||
'--disable-decoder=realtext',
|
||||
'--disable-decoder=roq',
|
||||
'--disable-decoder=roq_dpcm',
|
||||
'--disable-decoder=rscc',
|
||||
'--disable-decoder=rv10',
|
||||
'--disable-decoder=rv20',
|
||||
'--disable-decoder=rv30',
|
||||
'--disable-decoder=rv40',
|
||||
'--disable-decoder=sami',
|
||||
'--disable-decoder=sheervideo',
|
||||
'--disable-decoder=snow',
|
||||
'--disable-decoder=srt',
|
||||
'--disable-decoder=stl',
|
||||
'--disable-decoder=subrip',
|
||||
'--disable-decoder=subviewer',
|
||||
'--disable-decoder=subviewer1',
|
||||
'--disable-decoder=svq1',
|
||||
'--disable-decoder=svq3',
|
||||
'--disable-decoder=tiff',
|
||||
'--disable-decoder=mottiertexseqvideo',
|
||||
'--disable-decoder=truemotion1',
|
||||
'--disable-decoder=truemotion2',
|
||||
'--disable-decoder=truemotion2rt',
|
||||
'--disable-decoder=twinvq',
|
||||
'--disable-decoder=utvideo',
|
||||
'--disable-decoder=vc1',
|
||||
'--disable-decoder=vmdvideo',
|
||||
'--disable-decoder=vp3',
|
||||
'--disable-decoder=vp5',
|
||||
'--disable-decoder=vp6',
|
||||
'--disable-decoder=vp7',
|
||||
'--disable-decoder=vp8',
|
||||
'--disable-decoder=vp9',
|
||||
'--disable-decoder=vqa',
|
||||
'--disable-decoder=webvtt',
|
||||
'--disable-decoder=wmv1',
|
||||
'--disable-decoder=wmv2',
|
||||
'--disable-decoder=wmv3',
|
||||
'--disable-decoder=yuv4',
|
||||
],
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.58.0.tar.xz',
|
||||
'6a813875243609eb75f37fa72044e4ad618b55ec15a4eafdac2df6a7e800e3e3',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-debug',
|
||||
'--enable-http',
|
||||
'--enable-ipv6',
|
||||
'--disable-ftp', '--disable-file',
|
||||
'--disable-ldap', '--disable-ldaps',
|
||||
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
|
||||
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
|
||||
'--disable-smb',
|
||||
'--disable-gopher',
|
||||
'--disable-manual',
|
||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
||||
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
||||
],
|
||||
)
|
||||
|
||||
boost = BoostProject(
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.bz2',
|
||||
'5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9',
|
||||
'include/boost/version.hpp',
|
||||
)
|
28
python/build/makeproject.py
Normal file
28
python/build/makeproject.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class MakeProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
install_target='install',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.install_target = install_target
|
||||
|
||||
def get_simultaneous_jobs(self):
|
||||
return 12
|
||||
|
||||
def get_make_args(self, toolchain):
|
||||
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
|
||||
|
||||
def get_make_install_args(self, toolchain):
|
||||
return ['--quiet', self.install_target]
|
||||
|
||||
def make(self, toolchain, wd, args):
|
||||
subprocess.check_call(['/usr/bin/make'] + args,
|
||||
cwd=wd, env=toolchain.env)
|
||||
|
||||
def build(self, toolchain, wd, install=True):
|
||||
self.make(toolchain, wd, self.get_make_args(toolchain))
|
||||
if install:
|
||||
self.make(toolchain, wd, self.get_make_install_args(toolchain))
|
72
python/build/project.py
Normal file
72
python/build/project.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import os, shutil
|
||||
import re
|
||||
|
||||
from build.download import download_and_verify
|
||||
from build.tar import untar
|
||||
|
||||
class Project:
|
||||
def __init__(self, url, md5, installed, name=None, version=None,
|
||||
base=None,
|
||||
edits=None,
|
||||
use_cxx=False):
|
||||
if base is None:
|
||||
basename = os.path.basename(url)
|
||||
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
||||
if not m: raise
|
||||
self.base = m.group(1)
|
||||
else:
|
||||
self.base = base
|
||||
|
||||
if name is None or version is None:
|
||||
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?)$', self.base)
|
||||
if name is None: name = m.group(1)
|
||||
if version is None: version = m.group(2)
|
||||
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
self.url = url
|
||||
self.md5 = md5
|
||||
self.installed = installed
|
||||
|
||||
self.edits = edits
|
||||
self.use_cxx = use_cxx
|
||||
|
||||
def download(self, toolchain):
|
||||
return download_and_verify(self.url, self.md5, toolchain.tarball_path)
|
||||
|
||||
def is_installed(self, toolchain):
|
||||
tarball = self.download(toolchain)
|
||||
installed = os.path.join(toolchain.install_prefix, self.installed)
|
||||
tarball_mtime = os.path.getmtime(tarball)
|
||||
try:
|
||||
return os.path.getmtime(installed) >= tarball_mtime
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
def unpack(self, toolchain, out_of_tree=True):
|
||||
if out_of_tree:
|
||||
parent_path = toolchain.src_path
|
||||
else:
|
||||
parent_path = toolchain.build_path
|
||||
path = untar(self.download(toolchain), parent_path, self.base)
|
||||
|
||||
if self.edits is not None:
|
||||
for filename, function in self.edits.items():
|
||||
with open(os.path.join(path, filename), 'r+t') as f:
|
||||
old_data = f.read()
|
||||
new_data = function(old_data)
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
f.write(new_data)
|
||||
|
||||
return path
|
||||
|
||||
def make_build_path(self, toolchain):
|
||||
path = os.path.join(toolchain.build_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(path, exist_ok=True)
|
||||
return path
|
11
python/build/tar.py
Normal file
11
python/build/tar.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import os, shutil, subprocess
|
||||
|
||||
def untar(tarball_path, parent_path, base):
|
||||
path = os.path.join(parent_path, base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(parent_path, exist_ok=True)
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
|
||||
return path
|
42
python/build/verify.py
Normal file
42
python/build/verify.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import hashlib
|
||||
|
||||
def feed_file(h, f):
|
||||
"""Feed data read from an open file into the hashlib instance."""
|
||||
|
||||
while True:
|
||||
data = f.read(65536)
|
||||
if len(data) == 0:
|
||||
# end of file
|
||||
break
|
||||
h.update(data)
|
||||
|
||||
def feed_file_path(h, path):
|
||||
"""Feed data read from a file (to be opened by this function) into the hashlib instance."""
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
feed_file(h, f)
|
||||
|
||||
def file_digest(algorithm, path):
|
||||
"""Calculate the digest of a file and return it in hexadecimal notation."""
|
||||
|
||||
h = algorithm()
|
||||
feed_file_path(h, path)
|
||||
return h.hexdigest()
|
||||
|
||||
def guess_digest_algorithm(digest):
|
||||
l = len(digest)
|
||||
if l == 32:
|
||||
return hashlib.md5
|
||||
elif l == 40:
|
||||
return hashlib.sha1
|
||||
elif l == 64:
|
||||
return hashlib.sha256
|
||||
else:
|
||||
return None
|
||||
|
||||
def verify_file_digest(path, expected_digest):
|
||||
"""Verify the digest of a file, and return True if the digest matches with the given expected digest."""
|
||||
|
||||
algorithm = guess_digest_algorithm(expected_digest)
|
||||
assert(algorithm is not None)
|
||||
return file_digest(algorithm, path) == expected_digest
|
22
python/build/zlib.py
Normal file
22
python/build/zlib.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os.path, subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class ZlibProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain, out_of_tree=False)
|
||||
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet',
|
||||
'-f', 'win32/Makefile.gcc',
|
||||
'PREFIX=' + toolchain.arch + '-',
|
||||
'-j12',
|
||||
'install',
|
||||
'INCLUDE_PATH='+ os.path.join(toolchain.install_prefix, 'include'),
|
||||
'LIBRARY_PATH=' + os.path.join(toolchain.install_prefix, 'lib'),
|
||||
'BINARY_PATH=' + os.path.join(toolchain.install_prefix, 'bin'),
|
||||
'SHARED_MODE=1'],
|
||||
cwd=src, env=toolchain.env)
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "AudioConfig.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "AudioParser.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
static AudioFormat configured_audio_format;
|
||||
|
||||
AudioFormat
|
||||
getOutputAudioFormat(AudioFormat inAudioFormat)
|
||||
{
|
||||
AudioFormat out_audio_format = inAudioFormat;
|
||||
out_audio_format.ApplyMask(configured_audio_format);
|
||||
return out_audio_format;
|
||||
}
|
||||
|
||||
void initAudioConfig(void)
|
||||
{
|
||||
const struct config_param *param = config_get_param(CONF_AUDIO_OUTPUT_FORMAT);
|
||||
|
||||
if (param == nullptr)
|
||||
return;
|
||||
|
||||
Error error;
|
||||
if (!audio_format_parse(configured_audio_format, param->value.c_str(),
|
||||
true, error))
|
||||
FormatFatalError("error parsing line %i: %s",
|
||||
param->line, error.GetMessage());
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -18,12 +18,13 @@
|
||||
*/
|
||||
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/StringBuffer.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
AudioFormat::ApplyMask(AudioFormat mask)
|
||||
AudioFormat::ApplyMask(AudioFormat mask) noexcept
|
||||
{
|
||||
assert(IsValid());
|
||||
assert(mask.IsMaskValid());
|
||||
@@ -40,46 +41,24 @@ AudioFormat::ApplyMask(AudioFormat mask)
|
||||
assert(IsValid());
|
||||
}
|
||||
|
||||
const char *
|
||||
sample_format_to_string(SampleFormat format)
|
||||
StringBuffer<24>
|
||||
ToString(const AudioFormat af) noexcept
|
||||
{
|
||||
switch (format) {
|
||||
case SampleFormat::UNDEFINED:
|
||||
return "?";
|
||||
StringBuffer<24> buffer;
|
||||
|
||||
case SampleFormat::S8:
|
||||
return "8";
|
||||
|
||||
case SampleFormat::S16:
|
||||
return "16";
|
||||
|
||||
case SampleFormat::S24_P32:
|
||||
return "24";
|
||||
|
||||
case SampleFormat::S32:
|
||||
return "32";
|
||||
|
||||
case SampleFormat::FLOAT:
|
||||
return "f";
|
||||
|
||||
case SampleFormat::DSD:
|
||||
return "dsd";
|
||||
if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
|
||||
af.sample_rate % 44100 == 0) {
|
||||
/* use shortcuts such as "dsd64" which implies the
|
||||
sample rate */
|
||||
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u",
|
||||
af.sample_rate * 8 / 44100,
|
||||
af.channels);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* unreachable */
|
||||
assert(false);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
const char *
|
||||
audio_format_to_string(const AudioFormat af,
|
||||
struct audio_format_string *s)
|
||||
{
|
||||
assert(s != nullptr);
|
||||
|
||||
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
|
||||
snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u",
|
||||
af.sample_rate, sample_format_to_string(af.format),
|
||||
af.channels);
|
||||
|
||||
return s->buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,47 +20,14 @@
|
||||
#ifndef MPD_AUDIO_FORMAT_HXX
|
||||
#define MPD_AUDIO_FORMAT_HXX
|
||||
|
||||
#include "pcm/SampleFormat.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
||||
/* on WIN32, "FLOAT" is already defined, and this triggers -Wshadow */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wshadow"
|
||||
#endif
|
||||
|
||||
enum class SampleFormat : uint8_t {
|
||||
UNDEFINED = 0,
|
||||
|
||||
S8,
|
||||
S16,
|
||||
|
||||
/**
|
||||
* Signed 24 bit integer samples, packed in 32 bit integers
|
||||
* (the most significant byte is filled with the sign bit).
|
||||
*/
|
||||
S24_P32,
|
||||
|
||||
S32,
|
||||
|
||||
/**
|
||||
* 32 bit floating point samples in the host's format. The
|
||||
* range is -1.0f to +1.0f.
|
||||
*/
|
||||
FLOAT,
|
||||
|
||||
/**
|
||||
* Direct Stream Digital. 1-bit samples; each frame has one
|
||||
* byte (8 samples) per channel.
|
||||
*/
|
||||
DSD,
|
||||
};
|
||||
|
||||
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
template<size_t CAPACITY> class StringBuffer;
|
||||
|
||||
static constexpr unsigned MAX_CHANNELS = 8;
|
||||
|
||||
@@ -82,8 +49,19 @@ struct AudioFormat {
|
||||
SampleFormat format;
|
||||
|
||||
/**
|
||||
* The number of channels. Only mono (1) and stereo (2) are
|
||||
* fully supported currently.
|
||||
* The number of channels.
|
||||
*
|
||||
* Channel order follows the FLAC convention
|
||||
* (https://xiph.org/flac/format.html):
|
||||
*
|
||||
* - 1 channel: mono
|
||||
* - 2 channels: left, right
|
||||
* - 3 channels: left, right, center
|
||||
* - 4 channels: front left, front right, back left, back right
|
||||
* - 5 channels: front left, front right, front center, back/surround left, back/surround right
|
||||
* - 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
|
||||
* - 7 channels: front left, front right, front center, LFE, back center, side left, side right
|
||||
* - 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
|
||||
*/
|
||||
uint8_t channels;
|
||||
|
||||
@@ -99,8 +77,8 @@ struct AudioFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the #audio_format object, i.e. sets all attributes to an
|
||||
* undefined (invalid) value.
|
||||
* Clears the object, i.e. sets all attributes to an undefined
|
||||
* (invalid) value.
|
||||
*/
|
||||
void Clear() {
|
||||
sample_rate = 0;
|
||||
@@ -146,7 +124,14 @@ struct AudioFormat {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void ApplyMask(AudioFormat mask);
|
||||
void ApplyMask(AudioFormat mask) noexcept;
|
||||
|
||||
gcc_pure
|
||||
AudioFormat WithMask(AudioFormat mask) const noexcept {
|
||||
AudioFormat result = *this;
|
||||
result.ApplyMask(mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of each (mono) sample in bytes.
|
||||
@@ -165,13 +150,6 @@ struct AudioFormat {
|
||||
double GetTimeToSize() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Buffer for audio_format_string().
|
||||
*/
|
||||
struct audio_format_string {
|
||||
char buffer[24];
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether the sample rate is valid.
|
||||
*
|
||||
@@ -183,30 +161,6 @@ audio_valid_sample_rate(unsigned sample_rate)
|
||||
return sample_rate > 0 && sample_rate < (1 << 30);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the sample format is valid.
|
||||
*
|
||||
* @param bits the number of significant bits per sample
|
||||
*/
|
||||
static inline bool
|
||||
audio_valid_sample_format(SampleFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case SampleFormat::S8:
|
||||
case SampleFormat::S16:
|
||||
case SampleFormat::S24_P32:
|
||||
case SampleFormat::S32:
|
||||
case SampleFormat::FLOAT:
|
||||
case SampleFormat::DSD:
|
||||
return true;
|
||||
|
||||
case SampleFormat::UNDEFINED:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the number of channels is valid.
|
||||
*/
|
||||
@@ -242,34 +196,6 @@ AudioFormat::IsMaskValid() const
|
||||
(channels == 0 || audio_valid_channel_count(channels));
|
||||
}
|
||||
|
||||
gcc_const
|
||||
static inline unsigned
|
||||
sample_format_size(SampleFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
case SampleFormat::S8:
|
||||
return 1;
|
||||
|
||||
case SampleFormat::S16:
|
||||
return 2;
|
||||
|
||||
case SampleFormat::S24_P32:
|
||||
case SampleFormat::S32:
|
||||
case SampleFormat::FLOAT:
|
||||
return 4;
|
||||
|
||||
case SampleFormat::DSD:
|
||||
/* each frame has 8 samples per channel */
|
||||
return 1;
|
||||
|
||||
case SampleFormat::UNDEFINED:
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(false);
|
||||
gcc_unreachable();
|
||||
}
|
||||
|
||||
inline unsigned
|
||||
AudioFormat::GetSampleSize() const
|
||||
{
|
||||
@@ -289,27 +215,14 @@ AudioFormat::GetTimeToSize() const
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a #sample_format enum into a string, e.g. for printing it
|
||||
* in a log file.
|
||||
*
|
||||
* @param format a #sample_format enum value
|
||||
* @return the string
|
||||
*/
|
||||
gcc_pure gcc_malloc
|
||||
const char *
|
||||
sample_format_to_string(SampleFormat format);
|
||||
|
||||
/**
|
||||
* Renders the #audio_format object into a string, e.g. for printing
|
||||
* Renders the #AudioFormat object into a string, e.g. for printing
|
||||
* it in a log file.
|
||||
*
|
||||
* @param af the #audio_format object
|
||||
* @param s a buffer to print into
|
||||
* @return the string, or nullptr if the #audio_format object is invalid
|
||||
* @param af the #AudioFormat object
|
||||
* @return the string buffer
|
||||
*/
|
||||
gcc_pure gcc_malloc
|
||||
const char *
|
||||
audio_format_to_string(AudioFormat af,
|
||||
struct audio_format_string *s);
|
||||
gcc_const
|
||||
StringBuffer<24>
|
||||
ToString(AudioFormat af) noexcept;
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,73 +25,59 @@
|
||||
#include "config.h"
|
||||
#include "AudioParser.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "CheckAudioFormat.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "Compiler.h"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool
|
||||
parse_sample_rate(const char *src, bool mask, uint32_t *sample_rate_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static uint32_t
|
||||
ParseSampleRate(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*sample_rate_r = 0;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the sample rate");
|
||||
return false;
|
||||
} else if (!audio_check_sample_rate(value, error))
|
||||
return false;
|
||||
throw std::runtime_error("Failed to parse the sample rate");
|
||||
} else if (!audio_valid_sample_rate(value))
|
||||
throw FormatRuntimeError("Invalid sample rate: %lu",
|
||||
value);
|
||||
|
||||
*sample_rate_r = value;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_sample_format(const char *src, bool mask,
|
||||
SampleFormat *sample_format_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static SampleFormat
|
||||
ParseSampleFormat(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
SampleFormat sample_format;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*sample_format_r = SampleFormat::UNDEFINED;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return SampleFormat::UNDEFINED;
|
||||
}
|
||||
|
||||
if (*src == 'f') {
|
||||
*sample_format_r = SampleFormat::FLOAT;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return SampleFormat::FLOAT;
|
||||
}
|
||||
|
||||
if (memcmp(src, "dsd", 3) == 0) {
|
||||
*sample_format_r = SampleFormat::DSD;
|
||||
*endptr_r = src + 3;
|
||||
return true;
|
||||
return SampleFormat::DSD;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the sample format");
|
||||
return false;
|
||||
}
|
||||
if (endptr == src)
|
||||
throw std::runtime_error("Failed to parse the sample format");
|
||||
|
||||
switch (value) {
|
||||
case 8:
|
||||
@@ -115,99 +101,85 @@ parse_sample_format(const char *src, bool mask,
|
||||
break;
|
||||
|
||||
default:
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample format: %lu", value);
|
||||
return false;
|
||||
throw FormatRuntimeError("Invalid sample format: %lu", value);
|
||||
}
|
||||
|
||||
assert(audio_valid_sample_format(sample_format));
|
||||
|
||||
*sample_format_r = sample_format;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return sample_format;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_channel_count(const char *src, bool mask, uint8_t *channels_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static uint8_t
|
||||
ParseChannelCount(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*channels_r = 0;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the channel count");
|
||||
return false;
|
||||
} else if (!audio_check_channel_count(value, error))
|
||||
return false;
|
||||
if (endptr == src)
|
||||
throw std::runtime_error("Failed to parse the channel count");
|
||||
else if (!audio_valid_channel_count(value))
|
||||
throw FormatRuntimeError("Invalid channel count: %u", value);
|
||||
|
||||
*channels_r = value;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool
|
||||
audio_format_parse(AudioFormat &dest, const char *src,
|
||||
bool mask, Error &error)
|
||||
AudioFormat
|
||||
ParseAudioFormat(const char *src, bool mask)
|
||||
{
|
||||
uint32_t rate;
|
||||
SampleFormat sample_format;
|
||||
uint8_t channels;
|
||||
|
||||
AudioFormat dest;
|
||||
dest.Clear();
|
||||
|
||||
if (strncmp(src, "dsd", 3) == 0) {
|
||||
/* allow format specifications such as "dsd64" which
|
||||
implies the sample rate */
|
||||
|
||||
char *endptr;
|
||||
auto dsd = strtoul(src + 3, &endptr, 10);
|
||||
if (endptr > src + 3 && *endptr == ':' &&
|
||||
dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
|
||||
dest.sample_rate = dsd * 44100 / 8;
|
||||
dest.format = SampleFormat::DSD;
|
||||
|
||||
src = endptr + 1;
|
||||
dest.channels = ParseChannelCount(src, mask, &src);
|
||||
if (*src != 0)
|
||||
throw FormatRuntimeError("Extra data after channel count: %s", src);
|
||||
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
/* parse sample rate */
|
||||
|
||||
#if GCC_CHECK_VERSION(4,7)
|
||||
/* workaround -Wmaybe-uninitialized false positive */
|
||||
rate = 0;
|
||||
#endif
|
||||
dest.sample_rate = ParseSampleRate(src, mask, &src);
|
||||
|
||||
if (!parse_sample_rate(src, mask, &rate, &src, error))
|
||||
return false;
|
||||
|
||||
if (*src++ != ':') {
|
||||
error.Set(audio_format_domain, "Sample format missing");
|
||||
return false;
|
||||
}
|
||||
if (*src++ != ':')
|
||||
throw std::runtime_error("Sample format missing");
|
||||
|
||||
/* parse sample format */
|
||||
|
||||
#if GCC_CHECK_VERSION(4,7)
|
||||
/* workaround -Wmaybe-uninitialized false positive */
|
||||
sample_format = SampleFormat::UNDEFINED;
|
||||
#endif
|
||||
dest.format = ParseSampleFormat(src, mask, &src);
|
||||
|
||||
if (!parse_sample_format(src, mask, &sample_format, &src, error))
|
||||
return false;
|
||||
|
||||
if (*src++ != ':') {
|
||||
error.Set(audio_format_domain, "Channel count missing");
|
||||
return false;
|
||||
}
|
||||
if (*src++ != ':')
|
||||
throw std::runtime_error("Channel count missing");
|
||||
|
||||
/* parse channel count */
|
||||
|
||||
if (!parse_channel_count(src, mask, &channels, &src, error))
|
||||
return false;
|
||||
dest.channels = ParseChannelCount(src, mask, &src);
|
||||
|
||||
if (*src != 0) {
|
||||
error.Format(audio_format_domain,
|
||||
"Extra data after channel count: %s", src);
|
||||
return false;
|
||||
}
|
||||
if (*src != 0)
|
||||
throw FormatRuntimeError("Extra data after channel count: %s", src);
|
||||
|
||||
dest = AudioFormat(rate, sample_format, channels);
|
||||
assert(mask
|
||||
? dest.IsMaskValid()
|
||||
: dest.IsValid());
|
||||
|
||||
return true;
|
||||
return dest;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,21 +26,17 @@
|
||||
#define MPD_AUDIO_PARSER_HXX
|
||||
|
||||
struct AudioFormat;
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
|
||||
* #audio_format.
|
||||
* #AudioFormat.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*
|
||||
* @param dest the destination #audio_format struct
|
||||
* @param src the input string
|
||||
* @param mask if true, then "*" is allowed for any number of items
|
||||
* @param error_r location to store the error occurring, or NULL to
|
||||
* ignore errors
|
||||
* @return true on success
|
||||
*/
|
||||
bool
|
||||
audio_format_parse(AudioFormat &dest, const char *src,
|
||||
bool mask, Error &error);
|
||||
AudioFormat
|
||||
ParseAudioFormat(const char *src, bool mask);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,61 +20,43 @@
|
||||
#include "config.h"
|
||||
#include "CheckAudioFormat.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
const Domain audio_format_domain("audio_format");
|
||||
|
||||
bool
|
||||
audio_check_sample_rate(unsigned long sample_rate, Error &error)
|
||||
void
|
||||
CheckSampleRate(unsigned long sample_rate)
|
||||
{
|
||||
if (!audio_valid_sample_rate(sample_rate)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample rate: %lu", sample_rate);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!audio_valid_sample_rate(sample_rate))
|
||||
throw FormatRuntimeError("Invalid sample rate: %lu",
|
||||
sample_rate);
|
||||
}
|
||||
|
||||
bool
|
||||
audio_check_sample_format(SampleFormat sample_format, Error &error)
|
||||
void
|
||||
CheckSampleFormat(SampleFormat sample_format)
|
||||
{
|
||||
if (!audio_valid_sample_format(sample_format)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample format: %u",
|
||||
if (!audio_valid_sample_format(sample_format))
|
||||
throw FormatRuntimeError("Invalid sample format: %u",
|
||||
unsigned(sample_format));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
audio_check_channel_count(unsigned channels, Error &error)
|
||||
void
|
||||
CheckChannelCount(unsigned channels)
|
||||
{
|
||||
if (!audio_valid_channel_count(channels)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid channel count: %u", channels);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!audio_valid_channel_count(channels))
|
||||
throw FormatRuntimeError("Invalid channel count: %u",
|
||||
channels);
|
||||
}
|
||||
|
||||
bool
|
||||
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels,
|
||||
Error &error)
|
||||
AudioFormat
|
||||
CheckAudioFormat(unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels)
|
||||
{
|
||||
if (audio_check_sample_rate(sample_rate, error) &&
|
||||
audio_check_sample_format(sample_format, error) &&
|
||||
audio_check_channel_count(channels, error)) {
|
||||
af = AudioFormat(sample_rate, sample_format, channels);
|
||||
assert(af.IsValid());
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
CheckSampleRate(sample_rate);
|
||||
CheckSampleFormat(sample_format);
|
||||
CheckChannelCount(channels);
|
||||
|
||||
return AudioFormat(sample_rate, sample_format, channels);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,25 +22,23 @@
|
||||
|
||||
#include "AudioFormat.hxx"
|
||||
|
||||
class Error;
|
||||
void
|
||||
CheckSampleRate(unsigned long sample_rate);
|
||||
|
||||
extern const class Domain audio_format_domain;
|
||||
void
|
||||
CheckSampleFormat(SampleFormat sample_format);
|
||||
|
||||
bool
|
||||
audio_check_sample_rate(unsigned long sample_rate, Error &error);
|
||||
|
||||
bool
|
||||
audio_check_sample_format(SampleFormat sample_format, Error &error);
|
||||
|
||||
bool
|
||||
audio_check_channel_count(unsigned sample_format, Error &error);
|
||||
void
|
||||
CheckChannelCount(unsigned sample_format);
|
||||
|
||||
/**
|
||||
* Wrapper for audio_format_init(), which checks all attributes.
|
||||
* Check #AudioFormat attributes and construct an #AudioFormat
|
||||
* instance.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
bool
|
||||
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels,
|
||||
Error &error);
|
||||
AudioFormat
|
||||
CheckAudioFormat(unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,19 +20,10 @@
|
||||
#ifndef MPD_CHRONO_HXX
|
||||
#define MPD_CHRONO_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
#if GCC_OLDER_THAN(4,7)
|
||||
/* std::chrono::duration operators are "constexpr" since gcc 4.7 */
|
||||
#define chrono_constexpr gcc_pure
|
||||
#else
|
||||
#define chrono_constexpr constexpr
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A time stamp within a song. Granularity is 1 millisecond and the
|
||||
* maximum value is about 49 days.
|
||||
@@ -108,11 +99,11 @@ public:
|
||||
return count() > 0;
|
||||
}
|
||||
|
||||
chrono_constexpr SongTime operator+(const SongTime &other) const {
|
||||
constexpr SongTime operator+(const SongTime &other) const {
|
||||
return SongTime(*(const Base *)this + (const Base &)other);
|
||||
}
|
||||
|
||||
chrono_constexpr SongTime operator-(const SongTime &other) const {
|
||||
constexpr SongTime operator-(const SongTime &other) const {
|
||||
return SongTime(*(const Base *)this - (const Base &)other);
|
||||
}
|
||||
};
|
||||
@@ -212,15 +203,13 @@ public:
|
||||
return count() < 0;
|
||||
}
|
||||
|
||||
chrono_constexpr SignedSongTime operator+(const SignedSongTime &other) const {
|
||||
constexpr SignedSongTime operator+(const SignedSongTime &other) const {
|
||||
return SignedSongTime(*(const Base *)this + (const Base &)other);
|
||||
}
|
||||
|
||||
chrono_constexpr SignedSongTime operator-(const SignedSongTime &other) const {
|
||||
constexpr SignedSongTime operator-(const SignedSongTime &other) const {
|
||||
return SignedSongTime(*(const Base *)this - (const Base &)other);
|
||||
}
|
||||
};
|
||||
|
||||
#undef chrono_constexpr
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -35,7 +35,9 @@
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/StandardDirectory.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/Macros.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/OptionDef.hxx"
|
||||
#include "util/OptionParser.hxx"
|
||||
@@ -65,13 +67,13 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define CONFIG_FILE_LOCATION "mpd\\mpd.conf"
|
||||
#define APP_CONFIG_FILE_LOCATION "conf\\mpd.conf"
|
||||
#ifdef _WIN32
|
||||
#define CONFIG_FILE_LOCATION PATH_LITERAL("mpd\\mpd.conf")
|
||||
#define APP_CONFIG_FILE_LOCATION PATH_LITERAL("conf\\mpd.conf")
|
||||
#else
|
||||
#define USER_CONFIG_FILE_LOCATION1 ".mpdconf"
|
||||
#define USER_CONFIG_FILE_LOCATION2 ".mpd/mpd.conf"
|
||||
#define USER_CONFIG_FILE_LOCATION_XDG "mpd/mpd.conf"
|
||||
#define USER_CONFIG_FILE_LOCATION1 PATH_LITERAL(".mpdconf")
|
||||
#define USER_CONFIG_FILE_LOCATION2 PATH_LITERAL(".mpd/mpd.conf")
|
||||
#define USER_CONFIG_FILE_LOCATION_XDG PATH_LITERAL("mpd/mpd.conf")
|
||||
#endif
|
||||
|
||||
static constexpr OptionDef opt_kill(
|
||||
@@ -98,40 +100,44 @@ static constexpr Domain cmdline_domain("cmdline");
|
||||
gcc_noreturn
|
||||
static void version(void)
|
||||
{
|
||||
puts("Music Player Daemon " VERSION
|
||||
printf("Music Player Daemon " VERSION
|
||||
#ifdef GIT_COMMIT
|
||||
" (" GIT_COMMIT ")"
|
||||
#endif
|
||||
"\n"
|
||||
"\n"
|
||||
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||
"Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\n"
|
||||
"Copyright 2008-2017 Max Kellermann <max.kellermann@gmail.com>\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
|
||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
puts("\n"
|
||||
"Database plugins:");
|
||||
"\n"
|
||||
"Database plugins:\n");
|
||||
|
||||
for (auto i = database_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Storage plugins:");
|
||||
printf("\n\n"
|
||||
"Storage plugins:\n");
|
||||
|
||||
for (auto i = storage_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
puts("\n\n"
|
||||
"Neighbor plugins:");
|
||||
"\n"
|
||||
"Neighbor plugins:\n");
|
||||
for (auto i = neighbor_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
puts("\n\n"
|
||||
"Decoders plugins:");
|
||||
"\n"
|
||||
"Decoders plugins:\n");
|
||||
|
||||
decoder_plugins_for_each([](const DecoderPlugin &plugin){
|
||||
printf(" [%s]", plugin.name);
|
||||
@@ -141,26 +147,39 @@ static void version(void)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
|
||||
puts("");
|
||||
printf("\n");
|
||||
});
|
||||
|
||||
puts("\n"
|
||||
"Output plugins:");
|
||||
printf("\n"
|
||||
"Filters:\n"
|
||||
#ifdef ENABLE_LIBSAMPLERATE
|
||||
" libsamplerate"
|
||||
#endif
|
||||
#ifdef ENABLE_SOXR
|
||||
" soxr"
|
||||
#endif
|
||||
"\n\n"
|
||||
"Tag plugins:\n"
|
||||
#ifdef ENABLE_ID3TAG
|
||||
" id3tag"
|
||||
#endif
|
||||
"\n\n"
|
||||
"Output plugins:\n");
|
||||
audio_output_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
puts("");
|
||||
printf("\n"
|
||||
|
||||
#ifdef ENABLE_ENCODER
|
||||
puts("\n"
|
||||
"Encoder plugins:");
|
||||
"\n"
|
||||
"Encoder plugins:\n");
|
||||
encoder_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
puts("");
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
puts("\n"
|
||||
"Archive plugins:");
|
||||
"\n"
|
||||
"Archive plugins:\n");
|
||||
archive_plugins_for_each(plugin) {
|
||||
printf(" [%s]", plugin->name);
|
||||
|
||||
@@ -169,24 +188,57 @@ static void version(void)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
|
||||
puts("");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf(""
|
||||
#endif
|
||||
|
||||
puts("\n"
|
||||
"Input plugins:");
|
||||
"\n"
|
||||
"Input plugins:\n");
|
||||
input_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Playlist plugins:");
|
||||
printf("\n\n"
|
||||
"Playlist plugins:\n");
|
||||
playlist_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Protocols:");
|
||||
printf("\n\n"
|
||||
"Protocols:\n");
|
||||
print_supported_uri_schemes_to_fp(stdout);
|
||||
|
||||
printf("\n"
|
||||
"Other features:\n"
|
||||
#ifdef HAVE_AVAHI
|
||||
" avahi"
|
||||
#endif
|
||||
#ifdef USE_EPOLL
|
||||
" epoll"
|
||||
#endif
|
||||
#ifdef HAVE_ICONV
|
||||
" iconv"
|
||||
#endif
|
||||
#ifdef HAVE_ICU
|
||||
" icu"
|
||||
#endif
|
||||
#ifdef ENABLE_INOTIFY
|
||||
" inotify"
|
||||
#endif
|
||||
#ifdef HAVE_IPV6
|
||||
" ipv6"
|
||||
#endif
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
" systemd"
|
||||
#endif
|
||||
#ifdef HAVE_TCP
|
||||
" tcp"
|
||||
#endif
|
||||
#ifdef HAVE_UN
|
||||
" un"
|
||||
#endif
|
||||
"\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -206,12 +258,12 @@ static void PrintOption(const OptionDef &opt)
|
||||
gcc_noreturn
|
||||
static void help(void)
|
||||
{
|
||||
puts("Usage:\n"
|
||||
printf("Usage:\n"
|
||||
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
||||
"\n"
|
||||
"Music Player Daemon - a daemon for playing music.\n"
|
||||
"\n"
|
||||
"Options:");
|
||||
"Options:\n");
|
||||
|
||||
PrintOption(opt_help);
|
||||
PrintOption(opt_kill);
|
||||
@@ -226,29 +278,23 @@ static void help(void)
|
||||
|
||||
class ConfigLoader
|
||||
{
|
||||
Error &error;
|
||||
bool result;
|
||||
public:
|
||||
ConfigLoader(Error &_error) : error(_error), result(false) { }
|
||||
|
||||
bool GetResult() const { return result; }
|
||||
|
||||
bool TryFile(const Path path);
|
||||
bool TryFile(const AllocatedPath &base_path,
|
||||
PathTraitsFS::const_pointer path);
|
||||
PathTraitsFS::const_pointer_type path);
|
||||
};
|
||||
|
||||
bool ConfigLoader::TryFile(Path path)
|
||||
{
|
||||
if (FileExists(path)) {
|
||||
result = ReadConfigFile(path, error);
|
||||
ReadConfigFile(path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfigLoader::TryFile(const AllocatedPath &base_path,
|
||||
PathTraitsFS::const_pointer path)
|
||||
PathTraitsFS::const_pointer_type path)
|
||||
{
|
||||
if (base_path.IsNull())
|
||||
return false;
|
||||
@@ -256,9 +302,8 @@ bool ConfigLoader::TryFile(const AllocatedPath &base_path,
|
||||
return TryFile(full_path);
|
||||
}
|
||||
|
||||
bool
|
||||
parse_cmdline(int argc, char **argv, struct options *options,
|
||||
Error &error)
|
||||
void
|
||||
ParseCommandLine(int argc, char **argv, struct options *options)
|
||||
{
|
||||
bool use_config_file = true;
|
||||
options->kill = false;
|
||||
@@ -296,9 +341,8 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
if (parser.CheckOption(opt_help, opt_help_alt))
|
||||
help();
|
||||
|
||||
error.Format(cmdline_domain, "invalid option: %s",
|
||||
throw FormatRuntimeError("invalid option: %s",
|
||||
parser.GetOption());
|
||||
return false;
|
||||
}
|
||||
|
||||
/* initialize the logging library, so the configuration file
|
||||
@@ -308,7 +352,7 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
if (!use_config_file) {
|
||||
LogDebug(cmdline_domain,
|
||||
"Ignoring config, using daemon defaults");
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Second pass: find non-option parameters (i.e. config file)
|
||||
@@ -320,21 +364,32 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
config_file = argv[i];
|
||||
continue;
|
||||
}
|
||||
error.Set(cmdline_domain, "too many arguments");
|
||||
return false;
|
||||
|
||||
throw std::runtime_error("too many arguments");
|
||||
}
|
||||
|
||||
if (config_file != nullptr) {
|
||||
/* use specified configuration file */
|
||||
return ReadConfigFile(Path::FromFS(config_file), error);
|
||||
#ifdef _UNICODE
|
||||
wchar_t buffer[MAX_PATH];
|
||||
auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
|
||||
buffer, ARRAY_SIZE(buffer));
|
||||
if (result <= 0)
|
||||
throw MakeLastError("MultiByteToWideChar() failed");
|
||||
|
||||
ReadConfigFile(Path::FromFS(buffer));
|
||||
#else
|
||||
ReadConfigFile(Path::FromFS(config_file));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* use default configuration file path */
|
||||
|
||||
ConfigLoader loader(error);
|
||||
ConfigLoader loader;
|
||||
|
||||
bool found =
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
loader.TryFile(GetUserConfigDir(), CONFIG_FILE_LOCATION) ||
|
||||
loader.TryFile(GetSystemConfigDir(), CONFIG_FILE_LOCATION) ||
|
||||
loader.TryFile(GetAppBaseDir(), APP_CONFIG_FILE_LOCATION);
|
||||
@@ -345,10 +400,6 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
loader.TryFile(GetHomeDir(), USER_CONFIG_FILE_LOCATION2) ||
|
||||
loader.TryFile(Path::FromFS(SYSTEM_CONFIG_FILE_LOCATION));
|
||||
#endif
|
||||
if (!found) {
|
||||
error.Set(cmdline_domain, "No configuration file found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return loader.GetResult();
|
||||
if (!found)
|
||||
throw std::runtime_error("No configuration file found");
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,8 +20,6 @@
|
||||
#ifndef MPD_COMMAND_LINE_HXX
|
||||
#define MPD_COMMAND_LINE_HXX
|
||||
|
||||
class Error;
|
||||
|
||||
struct options {
|
||||
bool kill;
|
||||
bool daemon;
|
||||
@@ -29,8 +27,7 @@ struct options {
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
bool
|
||||
parse_cmdline(int argc, char **argv, struct options *options,
|
||||
Error &error);
|
||||
void
|
||||
ParseCommandLine(int argc, char **argv, struct options *options);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -62,8 +62,8 @@
|
||||
# error Sorry, your clang version is too old. You need at least version 3.1.
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if GCC_OLDER_THAN(4,7)
|
||||
# error Sorry, your gcc version is too old. You need at least version 4.6.
|
||||
# if GCC_OLDER_THAN(4,9)
|
||||
# error Sorry, your gcc version is too old. You need at least version 4.9.
|
||||
# endif
|
||||
#else
|
||||
# warning Untested compiler. Use at your own risk!
|
||||
@@ -97,8 +97,6 @@
|
||||
#define gcc_likely(x) __builtin_expect (!!(x), 1)
|
||||
#define gcc_unlikely(x) __builtin_expect (!!(x), 0)
|
||||
|
||||
#define gcc_aligned(n) __attribute__((aligned(n)))
|
||||
|
||||
#define gcc_visibility_hidden __attribute__((visibility("hidden")))
|
||||
#define gcc_visibility_default __attribute__((visibility("default")))
|
||||
|
||||
@@ -126,8 +124,6 @@
|
||||
#define gcc_likely(x) (x)
|
||||
#define gcc_unlikely(x) (x)
|
||||
|
||||
#define gcc_aligned(n)
|
||||
|
||||
#define gcc_visibility_hidden
|
||||
#define gcc_visibility_default
|
||||
|
||||
@@ -164,24 +160,6 @@
|
||||
#define gcc_restrict
|
||||
#endif
|
||||
|
||||
/* C++11 features */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
/* support for C++11 "override" was added in gcc 4.7 */
|
||||
#if GCC_OLDER_THAN(4,7)
|
||||
#define override
|
||||
#define final
|
||||
#endif
|
||||
|
||||
#if CLANG_OR_GCC_VERSION(4,8)
|
||||
#define gcc_alignas(T, fallback) alignas(T)
|
||||
#else
|
||||
#define gcc_alignas(T, fallback) gcc_aligned(fallback)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
// define dummy macro for non-clang compilers
|
||||
#define __has_feature(x) 0
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -37,19 +37,19 @@ DetachedSong::~DetachedSong()
|
||||
}
|
||||
|
||||
bool
|
||||
DetachedSong::IsRemote() const
|
||||
DetachedSong::IsRemote() const noexcept
|
||||
{
|
||||
return uri_has_scheme(GetRealURI());
|
||||
}
|
||||
|
||||
bool
|
||||
DetachedSong::IsAbsoluteFile() const
|
||||
DetachedSong::IsAbsoluteFile() const noexcept
|
||||
{
|
||||
return PathTraitsUTF8::IsAbsolute(GetRealURI());
|
||||
}
|
||||
|
||||
bool
|
||||
DetachedSong::IsInDatabase() const
|
||||
DetachedSong::IsInDatabase() const noexcept
|
||||
{
|
||||
/* here, we use GetURI() and not GetRealURI() because
|
||||
GetRealURI() is never relative */
|
||||
@@ -59,7 +59,7 @@ DetachedSong::IsInDatabase() const
|
||||
}
|
||||
|
||||
SignedSongTime
|
||||
DetachedSong::GetDuration() const
|
||||
DetachedSong::GetDuration() const noexcept
|
||||
{
|
||||
SongTime a = start_time, b = end_time;
|
||||
if (!b.IsPositive()) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
struct LightSong;
|
||||
class Storage;
|
||||
class Path;
|
||||
|
||||
class DetachedSong {
|
||||
friend DetachedSong map_song_detach(const LightSong &song);
|
||||
friend DetachedSong DatabaseDetachSong(const Storage &db,
|
||||
const LightSong &song);
|
||||
|
||||
@@ -63,18 +63,18 @@ class DetachedSong {
|
||||
|
||||
Tag tag;
|
||||
|
||||
time_t mtime;
|
||||
time_t mtime = 0;
|
||||
|
||||
/**
|
||||
* Start of this sub-song within the file.
|
||||
*/
|
||||
SongTime start_time;
|
||||
SongTime start_time = SongTime::zero();
|
||||
|
||||
/**
|
||||
* End of this sub-song within the file.
|
||||
* Unused if zero.
|
||||
*/
|
||||
SongTime end_time;
|
||||
SongTime end_time = SongTime::zero();
|
||||
|
||||
explicit DetachedSong(const LightSong &other);
|
||||
|
||||
@@ -82,33 +82,25 @@ public:
|
||||
explicit DetachedSong(const DetachedSong &) = default;
|
||||
|
||||
explicit DetachedSong(const char *_uri)
|
||||
:uri(_uri),
|
||||
mtime(0),
|
||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
||||
:uri(_uri) {}
|
||||
|
||||
explicit DetachedSong(const std::string &_uri)
|
||||
:uri(_uri),
|
||||
mtime(0),
|
||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
||||
:uri(_uri) {}
|
||||
|
||||
explicit DetachedSong(std::string &&_uri)
|
||||
:uri(std::move(_uri)),
|
||||
mtime(0),
|
||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
||||
:uri(std::move(_uri)) {}
|
||||
|
||||
template<typename U>
|
||||
DetachedSong(U &&_uri, Tag &&_tag)
|
||||
:uri(std::forward<U>(_uri)),
|
||||
tag(std::move(_tag)),
|
||||
mtime(0),
|
||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
||||
tag(std::move(_tag)) {}
|
||||
|
||||
DetachedSong(DetachedSong &&) = default;
|
||||
|
||||
~DetachedSong();
|
||||
|
||||
gcc_pure
|
||||
const char *GetURI() const {
|
||||
const char *GetURI() const noexcept {
|
||||
return uri.c_str();
|
||||
}
|
||||
|
||||
@@ -122,7 +114,7 @@ public:
|
||||
* displayed URI?
|
||||
*/
|
||||
gcc_pure
|
||||
bool HasRealURI() const {
|
||||
bool HasRealURI() const noexcept {
|
||||
return !real_uri.empty();
|
||||
}
|
||||
|
||||
@@ -131,7 +123,7 @@ public:
|
||||
* GetURI().
|
||||
*/
|
||||
gcc_pure
|
||||
const char *GetRealURI() const {
|
||||
const char *GetRealURI() const noexcept {
|
||||
return (HasRealURI() ? real_uri : uri).c_str();
|
||||
}
|
||||
|
||||
@@ -145,34 +137,36 @@ public:
|
||||
* song.
|
||||
*/
|
||||
gcc_pure
|
||||
bool IsSame(const DetachedSong &other) const {
|
||||
return uri == other.uri;
|
||||
bool IsSame(const DetachedSong &other) const noexcept {
|
||||
return uri == other.uri &&
|
||||
start_time == other.start_time &&
|
||||
end_time == other.end_time;
|
||||
}
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
bool IsURI(const char *other_uri) const {
|
||||
bool IsURI(const char *other_uri) const noexcept {
|
||||
return uri == other_uri;
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
bool IsRemote() const;
|
||||
bool IsRemote() const noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool IsFile() const {
|
||||
bool IsFile() const noexcept {
|
||||
return !IsRemote();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
bool IsAbsoluteFile() const;
|
||||
bool IsAbsoluteFile() const noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool IsInDatabase() const;
|
||||
bool IsInDatabase() const noexcept;
|
||||
|
||||
const Tag &GetTag() const {
|
||||
const Tag &GetTag() const noexcept {
|
||||
return tag;
|
||||
}
|
||||
|
||||
Tag &WritableTag() {
|
||||
Tag &WritableTag() noexcept {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@@ -221,7 +215,7 @@ public:
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
SignedSongTime GetDuration() const;
|
||||
SignedSongTime GetDuration() const noexcept;
|
||||
|
||||
/**
|
||||
* Update the #tag and #mtime.
|
||||
@@ -229,6 +223,11 @@ public:
|
||||
* @return true on success
|
||||
*/
|
||||
bool Update();
|
||||
|
||||
/**
|
||||
* Load #tag and #mtime from a local file.
|
||||
*/
|
||||
bool LoadFile(Path path);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/Manual.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace GlobalEvents {
|
||||
class Monitor final : public DeferredMonitor {
|
||||
public:
|
||||
Monitor(EventLoop &_loop):DeferredMonitor(_loop) {}
|
||||
|
||||
protected:
|
||||
virtual void RunDeferred() override;
|
||||
};
|
||||
|
||||
static Manual<Monitor> monitor;
|
||||
|
||||
static std::atomic_uint flags;
|
||||
static Handler handlers[MAX];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the callback for a certain event.
|
||||
*/
|
||||
static void
|
||||
InvokeGlobalEvent(GlobalEvents::Event event)
|
||||
{
|
||||
assert((unsigned)event < GlobalEvents::MAX);
|
||||
assert(GlobalEvents::handlers[event] != nullptr);
|
||||
|
||||
GlobalEvents::handlers[event]();
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Monitor::RunDeferred()
|
||||
{
|
||||
const unsigned f = flags.exchange(0);
|
||||
|
||||
for (unsigned i = 0; i < MAX; ++i)
|
||||
if (f & (1u << i))
|
||||
/* invoke the event handler */
|
||||
InvokeGlobalEvent(Event(i));
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Initialize(EventLoop &loop)
|
||||
{
|
||||
monitor.Construct(loop);
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Deinitialize()
|
||||
{
|
||||
monitor.Destruct();
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Register(Event event, Handler callback)
|
||||
{
|
||||
assert((unsigned)event < MAX);
|
||||
assert(handlers[event] == nullptr);
|
||||
|
||||
handlers[event] = callback;
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Emit(Event event)
|
||||
{
|
||||
assert((unsigned)event < MAX);
|
||||
|
||||
const unsigned mask = 1u << unsigned(event);
|
||||
if (GlobalEvents::flags.fetch_or(mask) == 0)
|
||||
monitor->Schedule();
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_GLOBAL_EVENTS_HXX
|
||||
#define MPD_GLOBAL_EVENTS_HXX
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
/* DELETE is a WIN32 macro that poisons our namespace; this is a
|
||||
kludge to allow us to use it anyway */
|
||||
#ifdef DELETE
|
||||
#undef DELETE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class EventLoop;
|
||||
|
||||
namespace GlobalEvents {
|
||||
enum Event {
|
||||
/** an idle event was emitted */
|
||||
IDLE,
|
||||
|
||||
/** must call playlist_sync() */
|
||||
PLAYLIST,
|
||||
|
||||
/** the current song's tag has changed */
|
||||
TAG,
|
||||
|
||||
#ifdef WIN32
|
||||
/** shutdown requested */
|
||||
SHUTDOWN,
|
||||
#endif
|
||||
|
||||
MAX
|
||||
};
|
||||
|
||||
typedef void (*Handler)();
|
||||
|
||||
void Initialize(EventLoop &loop);
|
||||
|
||||
void Deinitialize();
|
||||
|
||||
void Register(Event event, Handler handler);
|
||||
|
||||
void Emit(Event event);
|
||||
}
|
||||
|
||||
#endif /* MAIN_NOTIFY_H */
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,17 +24,20 @@
|
||||
#include "thread/Thread.hxx"
|
||||
#include "thread/Name.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static struct {
|
||||
static struct IOThread {
|
||||
Mutex mutex;
|
||||
Cond cond;
|
||||
|
||||
EventLoop *loop;
|
||||
Thread thread;
|
||||
|
||||
IOThread():thread(BIND_THIS_METHOD(Run)) {}
|
||||
|
||||
private:
|
||||
void Run() noexcept;
|
||||
} io;
|
||||
|
||||
void
|
||||
@@ -46,15 +49,15 @@ io_thread_run(void)
|
||||
io.loop->Run();
|
||||
}
|
||||
|
||||
static void
|
||||
io_thread_func(gcc_unused void *arg)
|
||||
inline void
|
||||
IOThread::Run() noexcept
|
||||
{
|
||||
SetThreadName("io");
|
||||
|
||||
/* lock+unlock to synchronize with io_thread_start(), to be
|
||||
sure that io.thread is set */
|
||||
io.mutex.lock();
|
||||
io.mutex.unlock();
|
||||
mutex.lock();
|
||||
mutex.unlock();
|
||||
|
||||
io_thread_run();
|
||||
}
|
||||
@@ -74,11 +77,8 @@ io_thread_start()
|
||||
assert(io.loop != nullptr);
|
||||
assert(!io.thread.IsDefined());
|
||||
|
||||
const ScopeLock protect(io.mutex);
|
||||
|
||||
Error error;
|
||||
if (!io.thread.Start(io_thread_func, nullptr, error))
|
||||
FatalError(error);
|
||||
const std::lock_guard<Mutex> protect(io.mutex);
|
||||
io.thread.Start();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -101,15 +101,19 @@ io_thread_deinit(void)
|
||||
}
|
||||
|
||||
EventLoop &
|
||||
io_thread_get()
|
||||
io_thread_get() noexcept
|
||||
{
|
||||
assert(io.loop != nullptr);
|
||||
|
||||
return *io.loop;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool
|
||||
io_thread_inside(void)
|
||||
io_thread_inside() noexcept
|
||||
{
|
||||
return io.thread.IsInside();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,12 +20,13 @@
|
||||
#ifndef MPD_IO_THREAD_HXX
|
||||
#define MPD_IO_THREAD_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
class EventLoop;
|
||||
|
||||
void
|
||||
io_thread_init(void);
|
||||
io_thread_init();
|
||||
|
||||
void
|
||||
io_thread_start();
|
||||
@@ -36,7 +37,7 @@ io_thread_start();
|
||||
* only.
|
||||
*/
|
||||
void
|
||||
io_thread_run(void);
|
||||
io_thread_run();
|
||||
|
||||
/**
|
||||
* Ask the I/O thread to quit, but does not wait for it. Usually, you
|
||||
@@ -44,20 +45,24 @@ io_thread_run(void);
|
||||
* includes this.
|
||||
*/
|
||||
void
|
||||
io_thread_quit(void);
|
||||
io_thread_quit();
|
||||
|
||||
void
|
||||
io_thread_deinit(void);
|
||||
io_thread_deinit();
|
||||
|
||||
gcc_const
|
||||
EventLoop &
|
||||
io_thread_get();
|
||||
io_thread_get() noexcept;
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
/**
|
||||
* Is the current thread the I/O thread?
|
||||
*/
|
||||
gcc_pure
|
||||
bool
|
||||
io_thread_inside(void);
|
||||
io_thread_inside() noexcept;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "tag/Tag.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -76,7 +77,7 @@ icy_add_item(TagBuilder &tag, TagType type, const char *value)
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
tag.AddItem(type, value, length);
|
||||
tag.AddItem(type, {value, length});
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
59
src/Idle.cxx
59
src/Idle.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,66 +24,15 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Idle.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <atomic>
|
||||
#include "Main.hxx"
|
||||
#include "Instance.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static std::atomic_uint idle_flags;
|
||||
|
||||
static const char *const idle_names[] = {
|
||||
"database",
|
||||
"stored_playlist",
|
||||
"playlist",
|
||||
"player",
|
||||
"mixer",
|
||||
"output",
|
||||
"options",
|
||||
"sticker",
|
||||
"update",
|
||||
"subscription",
|
||||
"message",
|
||||
"neighbor",
|
||||
"mount",
|
||||
nullptr
|
||||
};
|
||||
|
||||
void
|
||||
idle_add(unsigned flags)
|
||||
{
|
||||
assert(flags != 0);
|
||||
|
||||
unsigned old_flags = idle_flags.fetch_or(flags);
|
||||
|
||||
if ((old_flags & flags) != flags)
|
||||
GlobalEvents::Emit(GlobalEvents::IDLE);
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_get(void)
|
||||
{
|
||||
return idle_flags.exchange(0);
|
||||
}
|
||||
|
||||
const char*const*
|
||||
idle_get_names(void)
|
||||
{
|
||||
return idle_names;
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_parse_name(const char *name)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(name != nullptr);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
|
||||
if (StringEqualsCaseASCII(name, idle_names[i]))
|
||||
return 1 << i;
|
||||
|
||||
return 0;
|
||||
instance->EmitIdle(flags);
|
||||
}
|
||||
|
64
src/Idle.hxx
64
src/Idle.hxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,47 +25,7 @@
|
||||
#ifndef MPD_IDLE_HXX
|
||||
#define MPD_IDLE_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
/** song database has been updated*/
|
||||
static constexpr unsigned IDLE_DATABASE = 0x1;
|
||||
|
||||
/** a stored playlist has been modified, created, deleted or
|
||||
renamed */
|
||||
static constexpr unsigned IDLE_STORED_PLAYLIST = 0x2;
|
||||
|
||||
/** the current playlist has been modified */
|
||||
static constexpr unsigned IDLE_PLAYLIST = 0x4;
|
||||
|
||||
/** the player state has changed: play, stop, pause, seek, ... */
|
||||
static constexpr unsigned IDLE_PLAYER = 0x8;
|
||||
|
||||
/** the volume has been modified */
|
||||
static constexpr unsigned IDLE_MIXER = 0x10;
|
||||
|
||||
/** an audio output device has been enabled or disabled */
|
||||
static constexpr unsigned IDLE_OUTPUT = 0x20;
|
||||
|
||||
/** options have changed: crossfade; random; repeat; ... */
|
||||
static constexpr unsigned IDLE_OPTIONS = 0x40;
|
||||
|
||||
/** a sticker has been modified. */
|
||||
static constexpr unsigned IDLE_STICKER = 0x80;
|
||||
|
||||
/** a database update has started or finished. */
|
||||
static constexpr unsigned IDLE_UPDATE = 0x100;
|
||||
|
||||
/** a client has subscribed or unsubscribed to/from a channel */
|
||||
static constexpr unsigned IDLE_SUBSCRIPTION = 0x200;
|
||||
|
||||
/** a message on the subscribed channel was received */
|
||||
static constexpr unsigned IDLE_MESSAGE = 0x400;
|
||||
|
||||
/** a neighbor was found or lost */
|
||||
static constexpr unsigned IDLE_NEIGHBOR = 0x800;
|
||||
|
||||
/** the mount list has changed */
|
||||
static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
#include "IdleFlags.hxx"
|
||||
|
||||
/**
|
||||
* Adds idle flag (with bitwise "or") and queues notifications to all
|
||||
@@ -74,24 +34,4 @@ static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
void
|
||||
idle_add(unsigned flags);
|
||||
|
||||
/**
|
||||
* Atomically reads and resets the global idle flags value.
|
||||
*/
|
||||
unsigned
|
||||
idle_get(void);
|
||||
|
||||
/**
|
||||
* Get idle names
|
||||
*/
|
||||
const char*const*
|
||||
idle_get_names(void);
|
||||
|
||||
/**
|
||||
* Parse an idle name and return its mask. Returns 0 if the given
|
||||
* name is unknown.
|
||||
*/
|
||||
gcc_nonnull_all gcc_pure
|
||||
unsigned
|
||||
idle_parse_name(const char *name);
|
||||
|
||||
#endif
|
||||
|
67
src/IdleFlags.cxx
Normal file
67
src/IdleFlags.cxx
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support library for the "idle" command.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "IdleFlags.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static const char *const idle_names[] = {
|
||||
"database",
|
||||
"stored_playlist",
|
||||
"playlist",
|
||||
"player",
|
||||
"mixer",
|
||||
"output",
|
||||
"options",
|
||||
"sticker",
|
||||
"update",
|
||||
"subscription",
|
||||
"message",
|
||||
"neighbor",
|
||||
"mount",
|
||||
nullptr
|
||||
};
|
||||
|
||||
const char*const*
|
||||
idle_get_names() noexcept
|
||||
{
|
||||
return idle_names;
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_parse_name(const char *name) noexcept
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(name != nullptr);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
|
||||
if (StringEqualsCaseASCII(name, idle_names[i]))
|
||||
return 1 << i;
|
||||
|
||||
return 0;
|
||||
}
|
85
src/IdleFlags.hxx
Normal file
85
src/IdleFlags.hxx
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support library for the "idle" command.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MPD_IDLE_FLAGS_HXX
|
||||
#define MPD_IDLE_FLAGS_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
/** song database has been updated*/
|
||||
static constexpr unsigned IDLE_DATABASE = 0x1;
|
||||
|
||||
/** a stored playlist has been modified, created, deleted or
|
||||
renamed */
|
||||
static constexpr unsigned IDLE_STORED_PLAYLIST = 0x2;
|
||||
|
||||
/** the current playlist has been modified */
|
||||
static constexpr unsigned IDLE_PLAYLIST = 0x4;
|
||||
|
||||
/** the player state has changed: play, stop, pause, seek, ... */
|
||||
static constexpr unsigned IDLE_PLAYER = 0x8;
|
||||
|
||||
/** the volume has been modified */
|
||||
static constexpr unsigned IDLE_MIXER = 0x10;
|
||||
|
||||
/** an audio output device has been enabled or disabled */
|
||||
static constexpr unsigned IDLE_OUTPUT = 0x20;
|
||||
|
||||
/** options have changed: crossfade; random; repeat; ... */
|
||||
static constexpr unsigned IDLE_OPTIONS = 0x40;
|
||||
|
||||
/** a sticker has been modified. */
|
||||
static constexpr unsigned IDLE_STICKER = 0x80;
|
||||
|
||||
/** a database update has started or finished. */
|
||||
static constexpr unsigned IDLE_UPDATE = 0x100;
|
||||
|
||||
/** a client has subscribed or unsubscribed to/from a channel */
|
||||
static constexpr unsigned IDLE_SUBSCRIPTION = 0x200;
|
||||
|
||||
/** a message on the subscribed channel was received */
|
||||
static constexpr unsigned IDLE_MESSAGE = 0x400;
|
||||
|
||||
/** a neighbor was found or lost */
|
||||
static constexpr unsigned IDLE_NEIGHBOR = 0x800;
|
||||
|
||||
/** the mount list has changed */
|
||||
static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
|
||||
/**
|
||||
* Get idle names
|
||||
*/
|
||||
gcc_const
|
||||
const char*const*
|
||||
idle_get_names() noexcept;
|
||||
|
||||
/**
|
||||
* Parse an idle name and return its mask. Returns 0 if the given
|
||||
* name is unknown.
|
||||
*/
|
||||
gcc_nonnull_all gcc_pure
|
||||
unsigned
|
||||
idle_parse_name(const char *name) noexcept;
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,37 +25,27 @@
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "db/DatabaseError.hxx"
|
||||
#include "db/LightSong.hxx"
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
#include "sticker/StickerDatabase.hxx"
|
||||
#include "sticker/SongSticker.hxx"
|
||||
#endif
|
||||
|
||||
Database *
|
||||
Instance::GetDatabase(Error &error)
|
||||
{
|
||||
if (database == nullptr)
|
||||
error.Set(db_domain, DB_DISABLED, "No database");
|
||||
return database;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
Instance::TagModified()
|
||||
{
|
||||
partition->TagModified();
|
||||
}
|
||||
|
||||
void
|
||||
Instance::SyncWithPlayer()
|
||||
{
|
||||
partition->SyncWithPlayer();
|
||||
}
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
const Database &
|
||||
Instance::GetDatabaseOrThrow() const
|
||||
{
|
||||
if (database == nullptr)
|
||||
throw DatabaseError(DatabaseErrorCode::DISABLED,
|
||||
"No database");
|
||||
|
||||
return *database;
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseModified()
|
||||
{
|
||||
@@ -65,22 +55,24 @@ Instance::OnDatabaseModified()
|
||||
|
||||
stats_invalidate();
|
||||
partition->DatabaseModified(*database);
|
||||
idle_add(IDLE_DATABASE);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseSongRemoved(const LightSong &song)
|
||||
Instance::OnDatabaseSongRemoved(const char *uri)
|
||||
{
|
||||
assert(database != nullptr);
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
/* if the song has a sticker, remove it */
|
||||
if (sticker_enabled())
|
||||
sticker_song_delete(song);
|
||||
if (sticker_enabled()) {
|
||||
try {
|
||||
sticker_song_delete(uri);
|
||||
} catch (const std::runtime_error &) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto uri = song.GetURI();
|
||||
partition->DeleteSong(uri.c_str());
|
||||
partition->StaleSong(uri);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -90,13 +82,13 @@ Instance::OnDatabaseSongRemoved(const LightSong &song)
|
||||
void
|
||||
Instance::FoundNeighbor(gcc_unused const NeighborInfo &info)
|
||||
{
|
||||
idle_add(IDLE_NEIGHBOR);
|
||||
partition->EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::LostNeighbor(gcc_unused const NeighborInfo &info)
|
||||
{
|
||||
idle_add(IDLE_NEIGHBOR);
|
||||
partition->EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,6 +21,8 @@
|
||||
#define MPD_INSTANCE_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "event/Loop.hxx"
|
||||
#include "event/MaskMonitor.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
@@ -35,14 +37,22 @@ class Storage;
|
||||
class UpdateService;
|
||||
#endif
|
||||
|
||||
class EventLoop;
|
||||
class Error;
|
||||
class ClientList;
|
||||
struct Partition;
|
||||
class StateFile;
|
||||
|
||||
/**
|
||||
* A utility class which, when used as the first base class, ensures
|
||||
* that the #EventLoop gets initialized before the other base classes.
|
||||
*/
|
||||
struct EventLoopHolder {
|
||||
EventLoop event_loop;
|
||||
};
|
||||
|
||||
struct Instance final
|
||||
: EventLoopHolder
|
||||
#if defined(ENABLE_DATABASE) || defined(ENABLE_NEIGHBOR_PLUGINS)
|
||||
:
|
||||
,
|
||||
#endif
|
||||
#ifdef ENABLE_DATABASE
|
||||
public DatabaseListener
|
||||
@@ -54,7 +64,7 @@ struct Instance final
|
||||
public NeighborListener
|
||||
#endif
|
||||
{
|
||||
EventLoop *event_loop;
|
||||
MaskMonitor idle_monitor;
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
NeighborGlue *neighbors;
|
||||
@@ -67,20 +77,29 @@ struct Instance final
|
||||
* This is really a #CompositeStorage. To avoid heavy include
|
||||
* dependencies, we declare it as just #Storage.
|
||||
*/
|
||||
Storage *storage;
|
||||
Storage *storage = nullptr;
|
||||
|
||||
UpdateService *update;
|
||||
UpdateService *update = nullptr;
|
||||
#endif
|
||||
|
||||
ClientList *client_list;
|
||||
|
||||
Partition *partition;
|
||||
|
||||
Instance() {
|
||||
#ifdef ENABLE_DATABASE
|
||||
storage = nullptr;
|
||||
update = nullptr;
|
||||
#endif
|
||||
StateFile *state_file;
|
||||
|
||||
Instance()
|
||||
:idle_monitor(event_loop, BIND_THIS_METHOD(OnIdle)), state_file(nullptr) {}
|
||||
|
||||
/**
|
||||
* Initiate shutdown. Wrapper for EventLoop::Break().
|
||||
*/
|
||||
void Shutdown() {
|
||||
event_loop.Break();
|
||||
}
|
||||
|
||||
void EmitIdle(unsigned mask) {
|
||||
idle_monitor.OrMask(mask);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
@@ -89,31 +108,32 @@ struct Instance final
|
||||
* if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
Database *GetDatabase(Error &error);
|
||||
Database *GetDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global #Database instance. Throws
|
||||
* DatabaseError if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
const Database &GetDatabaseOrThrow() const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A tag in the play queue has been modified by the player
|
||||
* thread. Propagate the change to all subsystems.
|
||||
*/
|
||||
void TagModified();
|
||||
|
||||
/**
|
||||
* Synchronize the player with the play queue.
|
||||
*/
|
||||
void SyncWithPlayer();
|
||||
|
||||
private:
|
||||
#ifdef ENABLE_DATABASE
|
||||
virtual void OnDatabaseModified() override;
|
||||
virtual void OnDatabaseSongRemoved(const LightSong &song) override;
|
||||
void OnDatabaseModified() override;
|
||||
void OnDatabaseSongRemoved(const char *uri) override;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
/* virtual methods from class NeighborListener */
|
||||
virtual void FoundNeighbor(const NeighborInfo &info) override;
|
||||
virtual void LostNeighbor(const NeighborInfo &info) override;
|
||||
void FoundNeighbor(const NeighborInfo &info) override;
|
||||
void LostNeighbor(const NeighborInfo &info) override;
|
||||
#endif
|
||||
|
||||
/* callback for #idle_monitor */
|
||||
void OnIdle(unsigned mask);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,11 +20,13 @@
|
||||
#include "config.h"
|
||||
#include "Listen.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "net/SocketAddress.hxx"
|
||||
#include "event/ServerSocket.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "Log.hxx"
|
||||
@@ -48,73 +50,65 @@ public:
|
||||
:ServerSocket(_loop), partition(_partition) {}
|
||||
|
||||
private:
|
||||
virtual void OnAccept(int fd, const sockaddr &address,
|
||||
size_t address_length, int uid) {
|
||||
void OnAccept(int fd, SocketAddress address, int uid) override {
|
||||
client_new(GetEventLoop(), partition,
|
||||
fd, &address, address_length, uid);
|
||||
fd, address, uid);
|
||||
}
|
||||
};
|
||||
|
||||
static ClientListener *listen_socket;
|
||||
int listen_port;
|
||||
|
||||
static bool
|
||||
/**
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
static void
|
||||
listen_add_config_param(unsigned int port,
|
||||
const struct config_param *param,
|
||||
Error &error_r)
|
||||
const ConfigParam *param)
|
||||
{
|
||||
assert(param != nullptr);
|
||||
|
||||
if (0 == strcmp(param->value.c_str(), "any")) {
|
||||
return listen_socket->AddPort(port, error_r);
|
||||
listen_socket->AddPort(port);
|
||||
} else if (param->value[0] == '/' || param->value[0] == '~') {
|
||||
auto path = config_parse_path(param, error_r);
|
||||
return !path.IsNull() &&
|
||||
listen_socket->AddPath(std::move(path), error_r);
|
||||
listen_socket->AddPath(param->GetPath());
|
||||
} else {
|
||||
return listen_socket->AddHost(param->value.c_str(), port,
|
||||
error_r);
|
||||
listen_socket->AddHost(param->value.c_str(), port);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
|
||||
static bool
|
||||
listen_systemd_activation(Error &error_r)
|
||||
listen_systemd_activation()
|
||||
{
|
||||
int n = sd_listen_fds(true);
|
||||
if (n <= 0) {
|
||||
if (n < 0)
|
||||
FormatErrno(listen_domain, -n,
|
||||
"sd_listen_fds() failed");
|
||||
throw MakeErrno(-n, "sd_listen_fds() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = SD_LISTEN_FDS_START, end = SD_LISTEN_FDS_START + n;
|
||||
i != end; ++i)
|
||||
if (!listen_socket->AddFD(i, error_r))
|
||||
return false;
|
||||
listen_socket->AddFD(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
listen_global_init(EventLoop &loop, Partition &partition, Error &error)
|
||||
void
|
||||
listen_global_init(EventLoop &loop, Partition &partition)
|
||||
{
|
||||
int port = config_get_positive(CONF_PORT, DEFAULT_PORT);
|
||||
const struct config_param *param =
|
||||
config_get_param(CONF_BIND_TO_ADDRESS);
|
||||
int port = config_get_positive(ConfigOption::PORT, DEFAULT_PORT);
|
||||
const auto *param = config_get_param(ConfigOption::BIND_TO_ADDRESS);
|
||||
|
||||
listen_socket = new ClientListener(loop, partition);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
if (listen_systemd_activation(error))
|
||||
return true;
|
||||
|
||||
if (error.IsDefined())
|
||||
return false;
|
||||
if (listen_systemd_activation())
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (param != nullptr) {
|
||||
@@ -122,32 +116,35 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error)
|
||||
for all values */
|
||||
|
||||
do {
|
||||
if (!listen_add_config_param(port, param, error)) {
|
||||
try {
|
||||
listen_add_config_param(port, param);
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
error.FormatPrefix("Failed to listen on %s (line %i): ",
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to listen on %s (line %i)",
|
||||
param->value.c_str(),
|
||||
param->line);
|
||||
return false;
|
||||
param->line));
|
||||
}
|
||||
} while ((param = param->next) != nullptr);
|
||||
} else {
|
||||
/* no "bind_to_address" configured, bind the
|
||||
configured port on all interfaces */
|
||||
|
||||
if (!listen_socket->AddPort(port, error)) {
|
||||
try {
|
||||
listen_socket->AddPort(port);
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
error.FormatPrefix("Failed to listen on *:%d: ", port);
|
||||
return false;
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to listen on *:%d: ", port));
|
||||
}
|
||||
}
|
||||
|
||||
if (!listen_socket->Open(error)) {
|
||||
try {
|
||||
listen_socket->Open();
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
return false;
|
||||
throw;
|
||||
}
|
||||
|
||||
listen_port = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
void listen_global_finish(void)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,14 +21,14 @@
|
||||
#define MPD_LISTEN_HXX
|
||||
|
||||
class EventLoop;
|
||||
class Error;
|
||||
struct Partition;
|
||||
|
||||
extern int listen_port;
|
||||
|
||||
bool
|
||||
listen_global_init(EventLoop &loop, Partition &partition, Error &error);
|
||||
void
|
||||
listen_global_init(EventLoop &loop, Partition &partition);
|
||||
|
||||
void listen_global_finish(void);
|
||||
void
|
||||
listen_global_finish();
|
||||
|
||||
#endif
|
||||
|
110
src/LocateUri.cxx
Normal file
110
src/LocateUri.cxx
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "LocateUri.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "ls.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
#endif
|
||||
|
||||
static LocatedUri
|
||||
LocateFileUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
auto path = AllocatedPath::FromUTF8Throw(uri);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
/* this path was relative to the music
|
||||
directory */
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (client != nullptr)
|
||||
client->AllowFile(path);
|
||||
|
||||
return LocatedUri(LocatedUri::Type::PATH, uri, std::move(path));
|
||||
}
|
||||
|
||||
static LocatedUri
|
||||
LocateAbsoluteUri(const char *uri
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (!uri_supported_scheme(uri))
|
||||
throw std::runtime_error("Unsupported URI scheme");
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
return LocatedUri(LocatedUri::Type::ABSOLUTE, uri);
|
||||
}
|
||||
|
||||
LocatedUri
|
||||
LocateUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* skip the obsolete "file://" prefix */
|
||||
const char *path_utf8 = StringAfterPrefix(uri, "file://");
|
||||
if (path_utf8 != nullptr) {
|
||||
if (!PathTraitsUTF8::IsAbsolute(path_utf8))
|
||||
throw std::runtime_error("Malformed file:// URI");
|
||||
|
||||
return LocateFileUri(path_utf8, client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
} else if (PathTraitsUTF8::IsAbsolute(uri))
|
||||
return LocateFileUri(uri, client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
else if (uri_has_scheme(uri))
|
||||
return LocateAbsoluteUri(uri
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
else
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, uri);
|
||||
}
|
93
src/LocateUri.hxx
Normal file
93
src/LocateUri.hxx
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_LOCATE_URI_HXX
|
||||
#define MPD_LOCATE_URI_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
/* damn you, windows.h! */
|
||||
#ifdef ABSOLUTE
|
||||
#undef ABSOLUTE
|
||||
#endif
|
||||
#ifdef RELATIVE
|
||||
#undef RELATIVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Client;
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
class Storage;
|
||||
#endif
|
||||
|
||||
struct LocatedUri {
|
||||
enum class Type {
|
||||
/**
|
||||
* An absolute URI with a supported scheme.
|
||||
*/
|
||||
ABSOLUTE,
|
||||
|
||||
/**
|
||||
* A relative URI path.
|
||||
*/
|
||||
RELATIVE,
|
||||
|
||||
/**
|
||||
* A local file. The #path attribute is valid.
|
||||
*/
|
||||
PATH,
|
||||
} type;
|
||||
|
||||
const char *canonical_uri;
|
||||
|
||||
/**
|
||||
* Contains the local file path if type==FILE.
|
||||
*/
|
||||
AllocatedPath path;
|
||||
|
||||
LocatedUri(Type _type, const char *_uri,
|
||||
AllocatedPath &&_path=AllocatedPath::Null())
|
||||
:type(_type), canonical_uri(_uri), path(std::move(_path)) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Classify a URI.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*
|
||||
* @param client the #Client that is used to determine whether a local
|
||||
* file is allowed; nullptr disables the check and allows all local
|
||||
* files
|
||||
* @param storage a #Storage instance which may be used to convert
|
||||
* absolute URIs to relative ones, using Storage::MapToRelativeUTF8();
|
||||
* that feature is disabled if this parameter is nullptr
|
||||
*/
|
||||
LocatedUri
|
||||
LocateUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif
|
78
src/Log.cxx
78
src/Log.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,13 +19,16 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "LogV.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
static constexpr Domain exception_domain("exception");
|
||||
|
||||
void
|
||||
LogFormatV(const Domain &domain, LogLevel level, const char *fmt, va_list ap)
|
||||
{
|
||||
@@ -89,20 +92,37 @@ FormatError(const Domain &domain, const char *fmt, ...)
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const Error &error)
|
||||
LogError(const std::exception &e)
|
||||
{
|
||||
Log(error.GetDomain(), LogLevel::ERROR, error.GetMessage());
|
||||
Log(exception_domain, LogLevel::ERROR, e.what());
|
||||
|
||||
try {
|
||||
std::rethrow_if_nested(e);
|
||||
} catch (const std::exception &nested) {
|
||||
LogError(nested, "nested");
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized nested exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const Error &error, const char *msg)
|
||||
LogError(const std::exception &e, const char *msg)
|
||||
{
|
||||
LogFormat(error.GetDomain(), LogLevel::ERROR, "%s: %s",
|
||||
msg, error.GetMessage());
|
||||
FormatError(exception_domain, "%s: %s", msg, e.what());
|
||||
|
||||
try {
|
||||
std::rethrow_if_nested(e);
|
||||
} catch (const std::exception &nested) {
|
||||
LogError(nested);
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized nested exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const Error &error, const char *fmt, ...)
|
||||
FormatError(const std::exception &e, const char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
@@ -110,7 +130,45 @@ FormatError(const Error &error, const char *fmt, ...)
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(error, msg);
|
||||
LogError(e, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep)
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg)
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e, msg);
|
||||
} catch (...) {
|
||||
FormatError(exception_domain,
|
||||
"%s: Unrecognized exception", msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(ep, msg);
|
||||
}
|
||||
|
||||
void
|
||||
|
35
src/Log.hxx
35
src/Log.hxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "LogLevel.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
class Error;
|
||||
#include <exception>
|
||||
|
||||
class Domain;
|
||||
|
||||
void
|
||||
@@ -79,20 +80,30 @@ LogError(const Domain &domain, const char *msg)
|
||||
Log(domain, LogLevel::ERROR, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e);
|
||||
|
||||
void
|
||||
LogError(const std::exception &e, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception &e, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep);
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const Domain &domain, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogError(const Error &error);
|
||||
|
||||
void
|
||||
LogError(const Error &error, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const Error &error, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogErrno(const Domain &domain, int e, const char *msg);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,10 +23,6 @@
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -65,10 +61,6 @@ ToAndroidLogLevel(LogLevel log_level)
|
||||
|
||||
static LogLevel log_threshold = LogLevel::INFO;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
static const char *log_charset;
|
||||
#endif
|
||||
|
||||
static bool enable_timestamp;
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
@@ -81,16 +73,6 @@ SetLogThreshold(LogLevel _threshold)
|
||||
log_threshold = _threshold;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
void
|
||||
SetLogCharset(const char *_charset)
|
||||
{
|
||||
log_charset = _charset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
EnableLogTimestamp()
|
||||
{
|
||||
@@ -175,34 +157,16 @@ LogFinishSysLog()
|
||||
static void
|
||||
FileLog(const Domain &domain, const char *message)
|
||||
{
|
||||
#ifdef HAVE_GLIB
|
||||
char *converted;
|
||||
|
||||
if (log_charset != nullptr) {
|
||||
converted = g_convert_with_fallback(message, -1,
|
||||
log_charset, "utf-8",
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (converted != nullptr)
|
||||
message = converted;
|
||||
} else
|
||||
converted = nullptr;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s%s: %.*s\n",
|
||||
enable_timestamp ? log_date() : "",
|
||||
domain.GetName(),
|
||||
chomp_length(message), message);
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
/* force-flush the log file, because setvbuf() does not seem
|
||||
to have an effect on WIN32 */
|
||||
fflush(stderr);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
g_free(converted);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !ANDROID */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,13 +26,6 @@
|
||||
void
|
||||
SetLogThreshold(LogLevel _threshold);
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
void
|
||||
SetLogCharset(const char *_charset);
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
EnableLogTimestamp();
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,25 +21,19 @@
|
||||
#include "LogInit.hxx"
|
||||
#include "LogBackend.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LOG_LEVEL_SECURE LogLevel::INFO
|
||||
@@ -58,9 +52,9 @@ static void redirect_logs(int fd)
|
||||
{
|
||||
assert(fd >= 0);
|
||||
if (dup2(fd, STDOUT_FILENO) < 0)
|
||||
FatalSystemError("Failed to dup2 stdout");
|
||||
throw MakeErrno("Failed to dup2 stdout");
|
||||
if (dup2(fd, STDERR_FILENO) < 0)
|
||||
FatalSystemError("Failed to dup2 stderr");
|
||||
throw MakeErrno("Failed to dup2 stderr");
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -71,25 +65,30 @@ open_log_file(void)
|
||||
return OpenFile(out_path, O_CREAT | O_WRONLY | O_APPEND, 0666);
|
||||
}
|
||||
|
||||
static bool
|
||||
log_init_file(unsigned line, Error &error)
|
||||
static void
|
||||
log_init_file(int line)
|
||||
{
|
||||
assert(!out_path.IsNull());
|
||||
|
||||
out_fd = open_log_file();
|
||||
if (out_fd < 0) {
|
||||
#ifdef _WIN32
|
||||
const std::string out_path_utf8 = out_path.ToUTF8();
|
||||
error.FormatErrno("failed to open log file \"%s\" (config line %u)",
|
||||
throw FormatRuntimeError("failed to open log file \"%s\" (config line %d)",
|
||||
out_path_utf8.c_str(), line);
|
||||
return false;
|
||||
#else
|
||||
int e = errno;
|
||||
const std::string out_path_utf8 = out_path.ToUTF8();
|
||||
throw FormatErrno(e, "failed to open log file \"%s\" (config line %d)",
|
||||
out_path_utf8.c_str(), line);
|
||||
#endif
|
||||
}
|
||||
|
||||
EnableLogTimestamp();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline LogLevel
|
||||
parse_log_level(const char *value, unsigned line)
|
||||
parse_log_level(const char *value, int line)
|
||||
{
|
||||
if (0 == strcmp(value, "default"))
|
||||
return LogLevel::DEFAULT;
|
||||
@@ -97,10 +96,9 @@ parse_log_level(const char *value, unsigned line)
|
||||
return LOG_LEVEL_SECURE;
|
||||
else if (0 == strcmp(value, "verbose"))
|
||||
return LogLevel::DEBUG;
|
||||
else {
|
||||
FormatFatalError("unknown log level \"%s\" at line %u",
|
||||
else
|
||||
throw FormatRuntimeError("unknown log level \"%s\" at line %d",
|
||||
value, line);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -119,54 +117,36 @@ log_early_init(bool verbose)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
log_init(bool verbose, bool use_stdout, Error &error)
|
||||
void
|
||||
log_init(bool verbose, bool use_stdout)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
(void)verbose;
|
||||
(void)use_stdout;
|
||||
(void)error;
|
||||
|
||||
return true;
|
||||
#else
|
||||
const struct config_param *param;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
const char *charset;
|
||||
g_get_charset(&charset);
|
||||
SetLogCharset(charset);
|
||||
#endif
|
||||
|
||||
if (verbose)
|
||||
SetLogThreshold(LogLevel::DEBUG);
|
||||
else if ((param = config_get_param(CONF_LOG_LEVEL)) != nullptr)
|
||||
else if (const auto ¶m = config_get_param(ConfigOption::LOG_LEVEL))
|
||||
SetLogThreshold(parse_log_level(param->value.c_str(),
|
||||
param->line));
|
||||
|
||||
if (use_stdout) {
|
||||
return true;
|
||||
out_fd = STDOUT_FILENO;
|
||||
} else {
|
||||
param = config_get_param(CONF_LOG_FILE);
|
||||
const auto *param = config_get_param(ConfigOption::LOG_FILE);
|
||||
if (param == nullptr) {
|
||||
#ifdef HAVE_SYSLOG
|
||||
/* no configuration: default to syslog (if
|
||||
available) */
|
||||
LogInitSysLog();
|
||||
return true;
|
||||
#else
|
||||
error.Set(log_domain,
|
||||
"config parameter 'log_file' not found");
|
||||
return false;
|
||||
#ifndef HAVE_SYSLOG
|
||||
throw std::runtime_error("config parameter 'log_file' not found");
|
||||
#endif
|
||||
#ifdef HAVE_SYSLOG
|
||||
} else if (strcmp(param->value.c_str(), "syslog") == 0) {
|
||||
LogInitSysLog();
|
||||
return true;
|
||||
#endif
|
||||
} else {
|
||||
out_path = config_get_path(CONF_LOG_FILE, error);
|
||||
return !out_path.IsNull() &&
|
||||
log_init_file(param->line, error);
|
||||
out_path = param->GetPath();
|
||||
log_init_file(param->line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -193,18 +173,16 @@ log_deinit(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup_log_output(bool use_stdout)
|
||||
void setup_log_output()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
(void)use_stdout;
|
||||
#else
|
||||
if (use_stdout)
|
||||
#ifndef ANDROID
|
||||
if (out_fd == STDOUT_FILENO)
|
||||
return;
|
||||
|
||||
fflush(nullptr);
|
||||
|
||||
if (out_fd < 0) {
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
return;
|
||||
#else
|
||||
out_fd = open("/dev/null", O_WRONLY);
|
||||
@@ -216,10 +194,6 @@ void setup_log_output(bool use_stdout)
|
||||
redirect_logs(out_fd);
|
||||
close(out_fd);
|
||||
out_fd = -1;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
SetLogCharset(nullptr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,8 +20,6 @@
|
||||
#ifndef MPD_LOG_INIT_HXX
|
||||
#define MPD_LOG_INIT_HXX
|
||||
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* Configure a logging destination for daemon startup, before the
|
||||
* configuration file is read. This allows the daemon to use the
|
||||
@@ -33,14 +31,19 @@ class Error;
|
||||
void
|
||||
log_early_init(bool verbose);
|
||||
|
||||
bool
|
||||
log_init(bool verbose, bool use_stdout, Error &error);
|
||||
/**
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
void
|
||||
log_init(bool verbose, bool use_stdout);
|
||||
|
||||
void
|
||||
log_deinit(void);
|
||||
log_deinit();
|
||||
|
||||
void setup_log_output(bool use_stdout);
|
||||
void
|
||||
setup_log_output();
|
||||
|
||||
int cycle_log_files(void);
|
||||
int
|
||||
cycle_log_files();
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef MPD_LOG_LEVEL_HXX
|
||||
#define MPD_LOG_LEVEL_HXX
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
/* damn you, windows.h! */
|
||||
#ifdef ERROR
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
427
src/Main.cxx
427
src/Main.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,10 +22,9 @@
|
||||
#include "Instance.hxx"
|
||||
#include "CommandLine.hxx"
|
||||
#include "PlaylistFile.hxx"
|
||||
#include "PlaylistGlobal.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
#include "StateFile.hxx"
|
||||
#include "PlayerThread.hxx"
|
||||
#include "player/Thread.hxx"
|
||||
#include "Mapper.hxx"
|
||||
#include "Permission.hxx"
|
||||
#include "Listen.hxx"
|
||||
@@ -34,11 +33,10 @@
|
||||
#include "command/AllCommands.hxx"
|
||||
#include "Partition.hxx"
|
||||
#include "tag/TagConfig.hxx"
|
||||
#include "ReplayGainConfig.hxx"
|
||||
#include "ReplayGainGlobal.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "LogInit.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "input/Init.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "IOThread.hxx"
|
||||
@@ -47,22 +45,22 @@
|
||||
#include "playlist/PlaylistRegistry.hxx"
|
||||
#include "zeroconf/ZeroconfGlue.hxx"
|
||||
#include "decoder/DecoderList.hxx"
|
||||
#include "AudioConfig.hxx"
|
||||
#include "AudioParser.hxx"
|
||||
#include "pcm/PcmConvert.hxx"
|
||||
#include "unix/SignalHandlers.hxx"
|
||||
#include "unix/Daemon.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "thread/Id.hxx"
|
||||
#include "thread/Slack.hxx"
|
||||
#include "lib/icu/Init.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigDefaults.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "config/ConfigError.hxx"
|
||||
#include "Stats.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
#include "unix/Daemon.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "db/update/Service.hxx"
|
||||
@@ -98,8 +96,8 @@
|
||||
#include "org_musicpd_Bridge.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -108,7 +106,7 @@
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
@@ -119,7 +117,21 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
|
||||
static constexpr size_t KILOBYTE = 1024;
|
||||
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||
|
||||
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
|
||||
|
||||
static
|
||||
#if GCC_OLDER_THAN(5,0)
|
||||
/* gcc 4.x has no "constexpr" for std::max() */
|
||||
const
|
||||
#else
|
||||
constexpr
|
||||
#endif
|
||||
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
|
||||
64 * KILOBYTE);
|
||||
|
||||
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -128,55 +140,49 @@ Context *context;
|
||||
|
||||
Instance *instance;
|
||||
|
||||
static StateFile *state_file;
|
||||
struct Config {
|
||||
ReplayGainConfig replay_gain;
|
||||
};
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
static bool
|
||||
glue_daemonize_init(const struct options *options, Error &error)
|
||||
static Config
|
||||
LoadConfig()
|
||||
{
|
||||
auto pid_file = config_get_path(CONF_PID_FILE, error);
|
||||
if (pid_file.IsNull() && error.IsDefined())
|
||||
return false;
|
||||
return {LoadReplayGainConfig()};
|
||||
}
|
||||
|
||||
daemonize_init(config_get_string(CONF_USER, nullptr),
|
||||
config_get_string(CONF_GROUP, nullptr),
|
||||
std::move(pid_file));
|
||||
#ifdef ENABLE_DAEMON
|
||||
|
||||
static void
|
||||
glue_daemonize_init(const struct options *options)
|
||||
{
|
||||
daemonize_init(config_get_string(ConfigOption::USER, nullptr),
|
||||
config_get_string(ConfigOption::GROUP, nullptr),
|
||||
config_get_path(ConfigOption::PID_FILE));
|
||||
|
||||
if (options->kill)
|
||||
daemonize_kill();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool
|
||||
glue_mapper_init(Error &error)
|
||||
static void
|
||||
glue_mapper_init()
|
||||
{
|
||||
auto playlist_dir = config_get_path(CONF_PLAYLIST_DIR, error);
|
||||
if (playlist_dir.IsNull() && error.IsDefined())
|
||||
return false;
|
||||
|
||||
mapper_init(std::move(playlist_dir));
|
||||
return true;
|
||||
mapper_init(config_get_path(ConfigOption::PLAYLIST_DIR));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
static bool
|
||||
InitStorage(Error &error)
|
||||
static void
|
||||
InitStorage()
|
||||
{
|
||||
Storage *storage = CreateConfiguredStorage(io_thread_get(), error);
|
||||
Storage *storage = CreateConfiguredStorage(io_thread_get());
|
||||
if (storage == nullptr)
|
||||
return !error.IsDefined();
|
||||
|
||||
assert(!error.IsDefined());
|
||||
return;
|
||||
|
||||
CompositeStorage *composite = new CompositeStorage();
|
||||
instance->storage = composite;
|
||||
composite->Mount("", storage);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,20 +193,13 @@ InitStorage(Error &error)
|
||||
static bool
|
||||
glue_db_init_and_load(void)
|
||||
{
|
||||
Error error;
|
||||
instance->database =
|
||||
CreateConfiguredDatabase(*instance->event_loop, *instance,
|
||||
error);
|
||||
if (instance->database == nullptr) {
|
||||
if (error.IsDefined())
|
||||
FatalError(error);
|
||||
else
|
||||
CreateConfiguredDatabase(instance->event_loop, *instance);
|
||||
if (instance->database == nullptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (instance->database->GetPlugin().flags & DatabasePlugin::FLAG_REQUIRE_STORAGE) {
|
||||
if (!InitStorage(error))
|
||||
FatalError(error);
|
||||
InitStorage();
|
||||
|
||||
if (instance->storage == nullptr) {
|
||||
delete instance->database;
|
||||
@@ -217,14 +216,17 @@ glue_db_init_and_load(void)
|
||||
"because the database does not need it");
|
||||
}
|
||||
|
||||
if (!instance->database->Open(error))
|
||||
FatalError(error);
|
||||
try {
|
||||
instance->database->Open();
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
|
||||
}
|
||||
|
||||
if (!instance->database->IsPlugin(simple_db_plugin))
|
||||
return true;
|
||||
|
||||
SimpleDatabase &db = *(SimpleDatabase *)instance->database;
|
||||
instance->update = new UpdateService(*instance->event_loop, db,
|
||||
instance->update = new UpdateService(instance->event_loop, db,
|
||||
static_cast<CompositeStorage &>(*instance->storage),
|
||||
*instance);
|
||||
|
||||
@@ -245,49 +247,41 @@ InitDatabaseAndStorage()
|
||||
* Configure and initialize the sticker subsystem.
|
||||
*/
|
||||
static void
|
||||
glue_sticker_init(void)
|
||||
glue_sticker_init()
|
||||
{
|
||||
#ifdef ENABLE_SQLITE
|
||||
Error error;
|
||||
auto sticker_file = config_get_path(CONF_STICKER_FILE, error);
|
||||
if (sticker_file.IsNull()) {
|
||||
if (error.IsDefined())
|
||||
FatalError(error);
|
||||
auto sticker_file = config_get_path(ConfigOption::STICKER_FILE);
|
||||
if (sticker_file.IsNull())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sticker_global_init(std::move(sticker_file), error))
|
||||
FatalError(error);
|
||||
sticker_global_init(std::move(sticker_file));
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
glue_state_file_init(Error &error)
|
||||
static void
|
||||
glue_state_file_init()
|
||||
{
|
||||
auto path_fs = config_get_path(CONF_STATE_FILE, error);
|
||||
auto path_fs = config_get_path(ConfigOption::STATE_FILE);
|
||||
if (path_fs.IsNull()) {
|
||||
if (error.IsDefined())
|
||||
return false;
|
||||
|
||||
#ifdef ANDROID
|
||||
const auto cache_dir = GetUserCacheDir();
|
||||
if (cache_dir.IsNull())
|
||||
return true;
|
||||
return;
|
||||
|
||||
path_fs = AllocatedPath::Build(cache_dir, "state");
|
||||
#else
|
||||
return true;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned interval = config_get_unsigned(CONF_STATE_FILE_INTERVAL,
|
||||
const auto interval =
|
||||
config_get_unsigned(ConfigOption::STATE_FILE_INTERVAL,
|
||||
StateFile::DEFAULT_INTERVAL);
|
||||
|
||||
state_file = new StateFile(std::move(path_fs), interval,
|
||||
instance->state_file = new StateFile(std::move(path_fs), interval,
|
||||
*instance->partition,
|
||||
*instance->event_loop);
|
||||
state_file->Read();
|
||||
return true;
|
||||
instance->event_loop);
|
||||
instance->state_file->Read();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,7 +289,7 @@ glue_state_file_init(Error &error)
|
||||
*/
|
||||
static void winsock_init(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
WSADATA sockinfo;
|
||||
|
||||
int retval = WSAStartup(MAKEWORD(2, 2), &sockinfo);
|
||||
@@ -313,12 +307,12 @@ static void winsock_init(void)
|
||||
* Initialize the decoder and player core, including the music pipe.
|
||||
*/
|
||||
static void
|
||||
initialize_decoder_and_player(void)
|
||||
initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
|
||||
{
|
||||
const struct config_param *param;
|
||||
const ConfigParam *param;
|
||||
|
||||
size_t buffer_size;
|
||||
param = config_get_param(CONF_AUDIO_BUFFER_SIZE);
|
||||
param = config_get_param(ConfigOption::AUDIO_BUFFER_SIZE);
|
||||
if (param != nullptr) {
|
||||
char *test;
|
||||
long tmp = strtol(param->value.c_str(), &test, 10);
|
||||
@@ -326,12 +320,17 @@ initialize_decoder_and_player(void)
|
||||
FormatFatalError("buffer size \"%s\" is not a "
|
||||
"positive integer, line %i",
|
||||
param->value.c_str(), param->line);
|
||||
buffer_size = tmp;
|
||||
buffer_size = tmp * KILOBYTE;
|
||||
|
||||
if (buffer_size < MIN_BUFFER_SIZE) {
|
||||
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
|
||||
(unsigned long)buffer_size,
|
||||
(unsigned long)MIN_BUFFER_SIZE);
|
||||
buffer_size = MIN_BUFFER_SIZE;
|
||||
}
|
||||
} else
|
||||
buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
buffer_size *= 1024;
|
||||
|
||||
const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
|
||||
|
||||
if (buffered_chunks >= 1 << 15)
|
||||
@@ -339,7 +338,7 @@ initialize_decoder_and_player(void)
|
||||
(unsigned long)buffer_size);
|
||||
|
||||
float perc;
|
||||
param = config_get_param(CONF_BUFFER_BEFORE_PLAY);
|
||||
param = config_get_param(ConfigOption::BUFFER_BEFORE_PLAY);
|
||||
if (param != nullptr) {
|
||||
char *test;
|
||||
perc = strtod(param->value.c_str(), &test);
|
||||
@@ -349,6 +348,19 @@ initialize_decoder_and_player(void)
|
||||
"than 100 percent, line %i",
|
||||
param->value.c_str(), param->line);
|
||||
}
|
||||
|
||||
if (perc > 80) {
|
||||
/* this upper limit should avoid deadlocks
|
||||
which can occur because the DecoderThread
|
||||
cannot ever fill the music buffer to
|
||||
exactly 100%; a few chunks always need to
|
||||
be available to generate silence in
|
||||
Player::SendSilence() */
|
||||
FormatError(config_domain,
|
||||
"buffer_before_play is too large (%f%%), capping at 80%%; please fix your configuration",
|
||||
perc);
|
||||
perc = 80;
|
||||
}
|
||||
} else
|
||||
perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
||||
|
||||
@@ -357,50 +369,56 @@ initialize_decoder_and_player(void)
|
||||
buffered_before_play = buffered_chunks;
|
||||
|
||||
const unsigned max_length =
|
||||
config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
|
||||
config_get_positive(ConfigOption::MAX_PLAYLIST_LENGTH,
|
||||
DEFAULT_PLAYLIST_MAX_LENGTH);
|
||||
|
||||
AudioFormat configured_audio_format = AudioFormat::Undefined();
|
||||
param = config_get_param(ConfigOption::AUDIO_OUTPUT_FORMAT);
|
||||
if (param != nullptr) {
|
||||
try {
|
||||
configured_audio_format = ParseAudioFormat(param->value.c_str(),
|
||||
true);
|
||||
} catch (const std::runtime_error &) {
|
||||
std::throw_with_nested(FormatRuntimeError("error parsing line %i",
|
||||
param->line));
|
||||
}
|
||||
}
|
||||
|
||||
instance->partition = new Partition(*instance,
|
||||
max_length,
|
||||
buffered_chunks,
|
||||
buffered_before_play);
|
||||
buffered_before_play,
|
||||
configured_audio_format,
|
||||
replay_gain_config);
|
||||
|
||||
try {
|
||||
param = config_get_param(ConfigOption::REPLAYGAIN);
|
||||
if (param != nullptr)
|
||||
instance->partition->replay_gain_mode =
|
||||
FromString(param->value.c_str());
|
||||
} catch (...) {
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
|
||||
param->line));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for GlobalEvents::IDLE.
|
||||
*/
|
||||
static void
|
||||
idle_event_emitted(void)
|
||||
void
|
||||
Instance::OnIdle(unsigned flags)
|
||||
{
|
||||
/* send "idle" notifications to all subscribed
|
||||
clients */
|
||||
unsigned flags = idle_get();
|
||||
if (flags != 0)
|
||||
instance->client_list->IdleAdd(flags);
|
||||
client_list->IdleAdd(flags);
|
||||
|
||||
if (flags & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT) &&
|
||||
state_file != nullptr)
|
||||
state_file->CheckModified();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/**
|
||||
* Handler for GlobalEvents::SHUTDOWN.
|
||||
*/
|
||||
static void
|
||||
shutdown_event_emitted(void)
|
||||
{
|
||||
instance->event_loop->Break();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
return win32_main(argc, argv);
|
||||
#else
|
||||
return mpd_main(argc, argv);
|
||||
@@ -409,38 +427,29 @@ int main(int argc, char *argv[])
|
||||
|
||||
#endif
|
||||
|
||||
static int mpd_main_after_fork(struct options);
|
||||
static int
|
||||
mpd_main_after_fork(const Config &config);
|
||||
|
||||
#ifdef ANDROID
|
||||
static inline
|
||||
#endif
|
||||
int mpd_main(int argc, char *argv[])
|
||||
{
|
||||
try {
|
||||
struct options options;
|
||||
Error error;
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_close_stdin();
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
daemonize_close_stdin();
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* initialize locale */
|
||||
setlocale(LC_CTYPE,"");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
g_set_application_name("Music Player Daemon");
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,32,0)
|
||||
/* enable GLib's thread safety code */
|
||||
g_thread_init(nullptr);
|
||||
#endif
|
||||
setlocale(LC_COLLATE, "");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!IcuInit(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
IcuInit();
|
||||
|
||||
winsock_init();
|
||||
io_thread_init();
|
||||
@@ -450,47 +459,32 @@ int mpd_main(int argc, char *argv[])
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
{
|
||||
const auto sdcard = Environment::getExternalStorageDirectory();
|
||||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
AllocatedPath::Build(sdcard, "mpd.conf");
|
||||
if (FileExists(config_path) &&
|
||||
!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (FileExists(config_path))
|
||||
ReadConfigFile(config_path);
|
||||
}
|
||||
#else
|
||||
if (!parse_cmdline(argc, argv, &options, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!glue_daemonize_init(&options, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ParseCommandLine(argc, argv, &options);
|
||||
#endif
|
||||
|
||||
const auto config = LoadConfig();
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
glue_daemonize_init(&options);
|
||||
#endif
|
||||
|
||||
stats_global_init();
|
||||
TagLoadConfig();
|
||||
|
||||
if (!log_init(options.verbose, options.log_stderr, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
log_init(options.verbose, options.log_stderr);
|
||||
|
||||
instance = new Instance();
|
||||
instance->event_loop = new EventLoop();
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
instance->neighbors = new NeighborGlue();
|
||||
if (!instance->neighbors->Init(io_thread_get(), *instance, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
instance->neighbors->Init(io_thread_get(), *instance);
|
||||
|
||||
if (instance->neighbors->IsEmpty()) {
|
||||
delete instance->neighbors;
|
||||
@@ -498,18 +492,15 @@ int mpd_main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
const unsigned max_clients = config_get_positive(CONF_MAX_CONN, 10);
|
||||
const unsigned max_clients =
|
||||
config_get_positive(ConfigOption::MAX_CONN, 10);
|
||||
instance->client_list = new ClientList(max_clients);
|
||||
|
||||
initialize_decoder_and_player();
|
||||
initialize_decoder_and_player(config.replay_gain);
|
||||
|
||||
if (!listen_global_init(*instance->event_loop, *instance->partition,
|
||||
error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
listen_global_init(instance->event_loop, *instance->partition);
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_set_user();
|
||||
daemonize_begin(options.daemon);
|
||||
#endif
|
||||
@@ -522,43 +513,32 @@ int mpd_main(int argc, char *argv[])
|
||||
This must be run after forking; if dispatch is called before forking,
|
||||
the child process will have a broken internal dispatch state. */
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
exit(mpd_main_after_fork(options));
|
||||
exit(mpd_main_after_fork(config));
|
||||
});
|
||||
dispatch_main();
|
||||
return EXIT_FAILURE; // unreachable, because dispatch_main never returns
|
||||
#else
|
||||
return mpd_main_after_fork(options);
|
||||
return mpd_main_after_fork(config);
|
||||
#endif
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int mpd_main_after_fork(struct options options)
|
||||
{
|
||||
Error error;
|
||||
|
||||
GlobalEvents::Initialize(*instance->event_loop);
|
||||
GlobalEvents::Register(GlobalEvents::IDLE, idle_event_emitted);
|
||||
#ifdef WIN32
|
||||
GlobalEvents::Register(GlobalEvents::SHUTDOWN, shutdown_event_emitted);
|
||||
#endif
|
||||
|
||||
static int
|
||||
mpd_main_after_fork(const Config &config)
|
||||
try {
|
||||
ConfigureFS();
|
||||
|
||||
if (!glue_mapper_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
glue_mapper_init();
|
||||
|
||||
initPermissions();
|
||||
playlist_global_init();
|
||||
spl_global_init();
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
archive_plugin_init_all();
|
||||
#endif
|
||||
|
||||
if (!pcm_convert_global_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pcm_convert_global_init();
|
||||
|
||||
decoder_plugin_init_all();
|
||||
|
||||
@@ -569,36 +549,34 @@ static int mpd_main_after_fork(struct options options)
|
||||
glue_sticker_init();
|
||||
|
||||
command_init();
|
||||
initAudioConfig();
|
||||
instance->partition->outputs.Configure(*instance->event_loop,
|
||||
|
||||
instance->partition->outputs.Configure(instance->event_loop,
|
||||
config.replay_gain,
|
||||
instance->partition->pc);
|
||||
instance->partition->UpdateEffectiveReplayGainMode();
|
||||
|
||||
client_manager_init();
|
||||
replay_gain_global_init();
|
||||
|
||||
if (!input_stream_global_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
input_stream_global_init();
|
||||
playlist_list_global_init();
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_commit();
|
||||
#endif
|
||||
|
||||
setup_log_output(options.log_stderr);
|
||||
#ifndef ANDROID
|
||||
setup_log_output();
|
||||
|
||||
SignalHandlersInit(*instance->event_loop);
|
||||
SignalHandlersInit(instance->event_loop);
|
||||
#endif
|
||||
|
||||
io_thread_start();
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
if (instance->neighbors != nullptr &&
|
||||
!instance->neighbors->Open(error))
|
||||
FatalError(error);
|
||||
if (instance->neighbors != nullptr)
|
||||
instance->neighbors->Open();
|
||||
#endif
|
||||
|
||||
ZeroconfInit(*instance->event_loop);
|
||||
ZeroconfInit(instance->event_loop);
|
||||
|
||||
StartPlayerThread(instance->partition->pc);
|
||||
|
||||
@@ -612,22 +590,17 @@ static int mpd_main_after_fork(struct options options)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!glue_state_file_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
instance->partition->outputs.SetReplayGainMode(replay_gain_get_real_mode(instance->partition->playlist.queue.random));
|
||||
glue_state_file_init();
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (config_get_bool(CONF_AUTO_UPDATE, false)) {
|
||||
if (config_get_bool(ConfigOption::AUTO_UPDATE, false)) {
|
||||
#ifdef ENABLE_INOTIFY
|
||||
if (instance->storage != nullptr &&
|
||||
instance->update != nullptr)
|
||||
mpd_inotify_init(*instance->event_loop,
|
||||
mpd_inotify_init(instance->event_loop,
|
||||
*instance->storage,
|
||||
*instance->update,
|
||||
config_get_unsigned(CONF_AUTO_UPDATE_DEPTH,
|
||||
config_get_unsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
||||
INT_MAX));
|
||||
#else
|
||||
FormatWarning(config_domain,
|
||||
@@ -640,9 +613,9 @@ static int mpd_main_after_fork(struct options options)
|
||||
|
||||
/* enable all audio outputs (if not already done by
|
||||
playlist_state_restore() */
|
||||
instance->partition->pc.UpdateAudio();
|
||||
instance->partition->pc.LockUpdateAudio();
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
win32_app_started();
|
||||
#endif
|
||||
|
||||
@@ -650,10 +623,14 @@ static int mpd_main_after_fork(struct options options)
|
||||
a huge value to allow the kernel to reduce CPU wakeups */
|
||||
SetThreadTimerSlackMS(100);
|
||||
|
||||
/* run the main loop */
|
||||
instance->event_loop->Run();
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
sd_notify(0, "READY=1");
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
/* run the main loop */
|
||||
instance->event_loop.Run();
|
||||
|
||||
#ifdef _WIN32
|
||||
win32_app_stopping();
|
||||
#endif
|
||||
|
||||
@@ -666,9 +643,9 @@ static int mpd_main_after_fork(struct options options)
|
||||
instance->update->CancelAllAsync();
|
||||
#endif
|
||||
|
||||
if (state_file != nullptr) {
|
||||
state_file->Write();
|
||||
delete state_file;
|
||||
if (instance->state_file != nullptr) {
|
||||
instance->state_file->Write();
|
||||
delete instance->state_file;
|
||||
}
|
||||
|
||||
instance->partition->pc.Kill();
|
||||
@@ -698,8 +675,6 @@ static int mpd_main_after_fork(struct options options)
|
||||
sticker_global_finish();
|
||||
#endif
|
||||
|
||||
GlobalEvents::Deinitialize();
|
||||
|
||||
playlist_list_global_finish();
|
||||
input_stream_global_finish();
|
||||
|
||||
@@ -707,6 +682,8 @@ static int mpd_main_after_fork(struct options options)
|
||||
mapper_finish();
|
||||
#endif
|
||||
|
||||
DeinitFS();
|
||||
|
||||
delete instance->partition;
|
||||
command_finish();
|
||||
decoder_plugin_deinit_all();
|
||||
@@ -718,13 +695,14 @@ static int mpd_main_after_fork(struct options options)
|
||||
#ifndef ANDROID
|
||||
SignalHandlersFinish();
|
||||
#endif
|
||||
delete instance->event_loop;
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
#ifndef ANDROID
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_finish();
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
|
||||
@@ -732,6 +710,9 @@ static int mpd_main_after_fork(struct options options)
|
||||
|
||||
log_deinit();
|
||||
return EXIT_SUCCESS;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -757,7 +738,7 @@ JNIEXPORT void JNICALL
|
||||
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->event_loop->Break();
|
||||
instance->Shutdown();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -42,7 +42,7 @@ int mpd_main(int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef _WIN32
|
||||
|
||||
/**
|
||||
* If program is run as windows service performs nessesary initialization
|
||||
@@ -61,7 +61,7 @@ win32_main(int argc, char *argv[]);
|
||||
* This function should be called just before entering main loop.
|
||||
*/
|
||||
void
|
||||
win32_app_started(void);
|
||||
win32_app_started();
|
||||
|
||||
/**
|
||||
* When running as a service reports to service control manager
|
||||
@@ -71,7 +71,7 @@ win32_app_started(void);
|
||||
* This function should be called just after leaving main loop.
|
||||
*/
|
||||
void
|
||||
win32_app_stopping(void);
|
||||
win32_app_stopping();
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,9 +24,8 @@
|
||||
#include "config.h"
|
||||
#include "Mapper.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/Charset.hxx"
|
||||
#include "fs/CheckFile.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
@@ -59,14 +58,15 @@ mapper_init(AllocatedPath &&_playlist_dir)
|
||||
mapper_set_playlist_dir(std::move(_playlist_dir));
|
||||
}
|
||||
|
||||
void mapper_finish(void)
|
||||
void
|
||||
mapper_finish() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
AllocatedPath
|
||||
map_uri_fs(const char *uri)
|
||||
map_uri_fs(const char *uri) noexcept
|
||||
{
|
||||
assert(uri != nullptr);
|
||||
assert(*uri != '/');
|
||||
@@ -86,9 +86,9 @@ map_uri_fs(const char *uri)
|
||||
}
|
||||
|
||||
std::string
|
||||
map_fs_to_utf8(const char *path_fs)
|
||||
map_fs_to_utf8(Path path_fs) noexcept
|
||||
{
|
||||
if (PathTraitsFS::IsSeparator(path_fs[0])) {
|
||||
if (path_fs.IsAbsolute()) {
|
||||
if (instance->storage == nullptr)
|
||||
return std::string();
|
||||
|
||||
@@ -96,24 +96,26 @@ map_fs_to_utf8(const char *path_fs)
|
||||
if (music_dir_fs.IsNull())
|
||||
return std::string();
|
||||
|
||||
path_fs = music_dir_fs.RelativeFS(path_fs);
|
||||
if (path_fs == nullptr || *path_fs == 0)
|
||||
auto relative = music_dir_fs.Relative(path_fs);
|
||||
if (relative == nullptr || StringIsEmpty(relative))
|
||||
return std::string();
|
||||
|
||||
path_fs = Path::FromFS(relative);
|
||||
}
|
||||
|
||||
return PathToUTF8(path_fs);
|
||||
return path_fs.ToUTF8();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const AllocatedPath &
|
||||
map_spl_path(void)
|
||||
map_spl_path() noexcept
|
||||
{
|
||||
return playlist_dir_fs;
|
||||
}
|
||||
|
||||
AllocatedPath
|
||||
map_spl_utf8_to_fs(const char *name)
|
||||
map_spl_utf8_to_fs(const char *name) noexcept
|
||||
{
|
||||
if (playlist_dir_fs.IsNull())
|
||||
return AllocatedPath::Null();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,12 +30,14 @@
|
||||
|
||||
#define PLAYLIST_FILE_SUFFIX ".m3u"
|
||||
|
||||
class Path;
|
||||
class AllocatedPath;
|
||||
|
||||
void
|
||||
mapper_init(AllocatedPath &&playlist_dir);
|
||||
|
||||
void mapper_finish(void);
|
||||
void
|
||||
mapper_finish() noexcept;
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
@@ -46,7 +48,7 @@ void mapper_finish(void);
|
||||
*/
|
||||
gcc_pure
|
||||
AllocatedPath
|
||||
map_uri_fs(const char *uri);
|
||||
map_uri_fs(const char *uri) noexcept;
|
||||
|
||||
/**
|
||||
* Maps a file system path (relative to the music directory or
|
||||
@@ -58,7 +60,7 @@ map_uri_fs(const char *uri);
|
||||
*/
|
||||
gcc_pure
|
||||
std::string
|
||||
map_fs_to_utf8(const char *path_fs);
|
||||
map_fs_to_utf8(Path path_fs) noexcept;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,7 +69,7 @@ map_fs_to_utf8(const char *path_fs);
|
||||
*/
|
||||
gcc_const
|
||||
const AllocatedPath &
|
||||
map_spl_path(void);
|
||||
map_spl_path() noexcept;
|
||||
|
||||
/**
|
||||
* Maps a playlist name (without the ".m3u" suffix) to a file system
|
||||
@@ -77,6 +79,6 @@ map_spl_path(void);
|
||||
*/
|
||||
gcc_pure
|
||||
AllocatedPath
|
||||
map_spl_utf8_to_fs(const char *name);
|
||||
map_spl_utf8_to_fs(const char *name) noexcept;
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -31,45 +31,45 @@ class MixRampInfo {
|
||||
public:
|
||||
MixRampInfo() = default;
|
||||
|
||||
void Clear() {
|
||||
void Clear() noexcept {
|
||||
start.clear();
|
||||
end.clear();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
bool IsDefined() const {
|
||||
bool IsDefined() const noexcept {
|
||||
return !start.empty() || !end.empty();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
const char *GetStart() const {
|
||||
const char *GetStart() const noexcept {
|
||||
return start.empty() ? nullptr : start.c_str();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
const char *GetEnd() const {
|
||||
const char *GetEnd() const noexcept {
|
||||
return end.empty() ? nullptr : end.c_str();
|
||||
}
|
||||
|
||||
void SetStart(const char *new_value) {
|
||||
void SetStart(const char *new_value) noexcept {
|
||||
if (new_value == nullptr)
|
||||
start.clear();
|
||||
else
|
||||
start = new_value;
|
||||
}
|
||||
|
||||
void SetStart(std::string &&new_value) {
|
||||
void SetStart(std::string &&new_value) noexcept {
|
||||
start = std::move(new_value);
|
||||
}
|
||||
|
||||
void SetEnd(const char *new_value) {
|
||||
void SetEnd(const char *new_value) noexcept {
|
||||
if (new_value == nullptr)
|
||||
end.clear();
|
||||
else
|
||||
end = new_value;
|
||||
}
|
||||
|
||||
void SetEnd(std::string &&new_value) {
|
||||
void SetEnd(std::string &&new_value) noexcept {
|
||||
end = std::move(new_value);
|
||||
}
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,29 +20,26 @@
|
||||
#include "config.h"
|
||||
#include "MusicBuffer.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
||||
MusicBuffer::MusicBuffer(unsigned num_chunks) noexcept
|
||||
:buffer(num_chunks) {
|
||||
if (buffer.IsOOM())
|
||||
FatalError("Failed to allocate buffer");
|
||||
}
|
||||
|
||||
MusicChunk *
|
||||
MusicBuffer::Allocate()
|
||||
MusicBuffer::Allocate() noexcept
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
return buffer.Allocate();
|
||||
}
|
||||
|
||||
void
|
||||
MusicBuffer::Return(MusicChunk *chunk)
|
||||
MusicBuffer::Return(MusicChunk *chunk) noexcept
|
||||
{
|
||||
assert(chunk != nullptr);
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
if (chunk->other != nullptr) {
|
||||
assert(chunk->other->other == nullptr);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
* @param num_chunks the number of #MusicChunk reserved in
|
||||
* this buffer
|
||||
*/
|
||||
MusicBuffer(unsigned num_chunks);
|
||||
MusicBuffer(unsigned num_chunks) noexcept;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
* music_buffer_new().
|
||||
*/
|
||||
gcc_pure
|
||||
unsigned GetSize() const {
|
||||
unsigned GetSize() const noexcept {
|
||||
return buffer.GetCapacity();
|
||||
}
|
||||
|
||||
@@ -71,13 +71,13 @@ public:
|
||||
* @return an empty chunk or nullptr if there are no chunks
|
||||
* available
|
||||
*/
|
||||
MusicChunk *Allocate();
|
||||
MusicChunk *Allocate() noexcept;
|
||||
|
||||
/**
|
||||
* Returns a chunk to the buffer. It can be reused by
|
||||
* Allocate() then.
|
||||
*/
|
||||
void Return(MusicChunk *chunk);
|
||||
void Return(MusicChunk *chunk) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -31,7 +31,7 @@ MusicChunk::~MusicChunk()
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool
|
||||
MusicChunk::CheckFormat(const AudioFormat other_format) const
|
||||
MusicChunk::CheckFormat(const AudioFormat other_format) const noexcept
|
||||
{
|
||||
assert(other_format.IsValid());
|
||||
|
||||
@@ -41,7 +41,7 @@ MusicChunk::CheckFormat(const AudioFormat other_format) const
|
||||
|
||||
WritableBuffer<void>
|
||||
MusicChunk::Write(const AudioFormat af,
|
||||
SongTime data_time, uint16_t _bit_rate)
|
||||
SongTime data_time, uint16_t _bit_rate) noexcept
|
||||
{
|
||||
assert(CheckFormat(af));
|
||||
assert(length == 0 || audio_format.IsValid());
|
||||
@@ -64,7 +64,7 @@ MusicChunk::Write(const AudioFormat af,
|
||||
}
|
||||
|
||||
bool
|
||||
MusicChunk::Expand(const AudioFormat af, size_t _length)
|
||||
MusicChunk::Expand(const AudioFormat af, size_t _length) noexcept
|
||||
{
|
||||
const size_t frame_size = af.GetFrameSize();
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -48,7 +48,7 @@ struct MusicChunk {
|
||||
* An optional chunk which should be mixed into this chunk.
|
||||
* This is used for cross-fading.
|
||||
*/
|
||||
MusicChunk *other;
|
||||
MusicChunk *other = nullptr;
|
||||
|
||||
/**
|
||||
* The current mix ratio for cross-fading: 1.0 means play 100%
|
||||
@@ -57,7 +57,7 @@ struct MusicChunk {
|
||||
float mix_ratio;
|
||||
|
||||
/** number of bytes stored in this chunk */
|
||||
uint16_t length;
|
||||
uint16_t length = 0;
|
||||
|
||||
/** current bit rate of the source file */
|
||||
uint16_t bit_rate;
|
||||
@@ -71,7 +71,7 @@ struct MusicChunk {
|
||||
* object is owned by this chunk, and must be freed when this
|
||||
* chunk is deinitialized.
|
||||
*/
|
||||
Tag *tag;
|
||||
Tag *tag = nullptr;
|
||||
|
||||
/**
|
||||
* Replay gain information associated with this chunk.
|
||||
@@ -79,6 +79,14 @@ struct MusicChunk {
|
||||
*/
|
||||
ReplayGainInfo replay_gain_info;
|
||||
|
||||
/**
|
||||
* A magic value for #replay_gain_serial which omits updating
|
||||
* the #ReplayGainFilter. This is used by "silence" chunks
|
||||
* (see PlayerThread::SendSilence()) so they don't affect the
|
||||
* replay gain.
|
||||
*/
|
||||
static constexpr unsigned IGNORE_REPLAY_GAIN = ~0u;
|
||||
|
||||
/**
|
||||
* A serial number for checking if replay gain info has
|
||||
* changed since the last chunk. The magic value 0 indicates
|
||||
@@ -93,14 +101,14 @@ struct MusicChunk {
|
||||
AudioFormat audio_format;
|
||||
#endif
|
||||
|
||||
MusicChunk()
|
||||
:other(nullptr),
|
||||
length(0),
|
||||
tag(nullptr),
|
||||
replay_gain_serial(0) {}
|
||||
MusicChunk() = default;
|
||||
|
||||
MusicChunk(const MusicChunk &) = delete;
|
||||
|
||||
~MusicChunk();
|
||||
|
||||
MusicChunk &operator=(const MusicChunk &) = delete;
|
||||
|
||||
bool IsEmpty() const {
|
||||
return length == 0 && tag == nullptr;
|
||||
}
|
||||
@@ -111,7 +119,7 @@ struct MusicChunk {
|
||||
* specified audio_format.
|
||||
*/
|
||||
gcc_pure
|
||||
bool CheckFormat(AudioFormat audio_format) const;
|
||||
bool CheckFormat(AudioFormat audio_format) const noexcept;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -119,30 +127,26 @@ struct MusicChunk {
|
||||
* where you may write into. After you are finished, call
|
||||
* Expand().
|
||||
*
|
||||
* @param chunk the MusicChunk object
|
||||
* @param audio_format the audio format for the appended data;
|
||||
* @param af the audio format for the appended data;
|
||||
* must stay the same for the life cycle of this chunk
|
||||
* @param data_time the time within the song
|
||||
* @param bit_rate the current bit rate of the source file
|
||||
* @param max_length_r the maximum write length is returned
|
||||
* here
|
||||
* @return a writable buffer, or nullptr if the chunk is full
|
||||
*/
|
||||
WritableBuffer<void> Write(AudioFormat af,
|
||||
SongTime data_time,
|
||||
uint16_t bit_rate);
|
||||
uint16_t bit_rate) noexcept;
|
||||
|
||||
/**
|
||||
* Increases the length of the chunk after the caller has written to
|
||||
* the buffer returned by Write().
|
||||
*
|
||||
* @param chunk the MusicChunk object
|
||||
* @param audio_format the audio format for the appended data; must
|
||||
* @param af the audio format for the appended data; must
|
||||
* stay the same for the life cycle of this chunk
|
||||
* @param length the number of bytes which were appended
|
||||
* @return true if the chunk is full
|
||||
*/
|
||||
bool Expand(AudioFormat af, size_t length);
|
||||
bool Expand(AudioFormat af, size_t length) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,9 +25,9 @@
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool
|
||||
MusicPipe::Contains(const MusicChunk *chunk) const
|
||||
MusicPipe::Contains(const MusicChunk *chunk) const noexcept
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
for (const MusicChunk *i = head; i != nullptr; i = i->next)
|
||||
if (i == chunk)
|
||||
@@ -39,9 +39,9 @@ MusicPipe::Contains(const MusicChunk *chunk) const
|
||||
#endif
|
||||
|
||||
MusicChunk *
|
||||
MusicPipe::Shift()
|
||||
MusicPipe::Shift() noexcept
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
MusicChunk *chunk = head;
|
||||
if (chunk != nullptr) {
|
||||
@@ -73,7 +73,7 @@ MusicPipe::Shift()
|
||||
}
|
||||
|
||||
void
|
||||
MusicPipe::Clear(MusicBuffer &buffer)
|
||||
MusicPipe::Clear(MusicBuffer &buffer) noexcept
|
||||
{
|
||||
MusicChunk *chunk;
|
||||
|
||||
@@ -82,12 +82,12 @@ MusicPipe::Clear(MusicBuffer &buffer)
|
||||
}
|
||||
|
||||
void
|
||||
MusicPipe::Push(MusicChunk *chunk)
|
||||
MusicPipe::Push(MusicChunk *chunk) noexcept
|
||||
{
|
||||
assert(!chunk->IsEmpty());
|
||||
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
assert(size > 0 || !audio_format.IsDefined());
|
||||
assert(!audio_format.IsDefined() ||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user