Compare commits
1329 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d7fcaf33b9 | ||
![]() |
6a65b4c305 | ||
![]() |
a163beee69 | ||
![]() |
31268ad7cd | ||
![]() |
a0d43dd87f | ||
![]() |
1db533c8cf | ||
![]() |
78ee663660 | ||
![]() |
c32a809d38 | ||
![]() |
1406144210 | ||
![]() |
bb6ab67175 | ||
![]() |
ed3d8222d6 | ||
![]() |
41c0bbab13 | ||
![]() |
eeb96eb367 | ||
![]() |
ce93e58944 | ||
![]() |
263b0ffdbb | ||
![]() |
22bea5c97e | ||
![]() |
75802ebcc6 | ||
![]() |
27cc7b352d | ||
![]() |
d64729065e | ||
![]() |
ab318200db | ||
![]() |
947856ca8e | ||
![]() |
cd9ff9d9b0 | ||
![]() |
4cd0f661d6 | ||
![]() |
bf270a5663 | ||
![]() |
6e893f40e3 | ||
![]() |
7690905503 | ||
![]() |
6f822a6f19 | ||
![]() |
ca0179b2a9 | ||
![]() |
6682cf749f | ||
![]() |
492607ecbe | ||
![]() |
e0c75da266 | ||
![]() |
34bb53a29f | ||
![]() |
cb4fdac469 | ||
![]() |
ac46a84391 | ||
![]() |
dffd5831f8 | ||
![]() |
8358b34efa | ||
![]() |
4484d7a5c2 | ||
![]() |
b80a135cf3 | ||
![]() |
4ad525d939 | ||
![]() |
4cb5e69811 | ||
![]() |
b0596291a8 | ||
![]() |
8f0a1a5d82 | ||
![]() |
c0775d328c | ||
![]() |
4ca2c33181 | ||
![]() |
362f391b76 | ||
![]() |
980e32f69c | ||
![]() |
dd639e18b8 | ||
![]() |
c883f178b8 | ||
![]() |
65d257675f | ||
![]() |
56fa7368e8 | ||
![]() |
e9df4116fd | ||
![]() |
5492304254 | ||
![]() |
416d4e4433 | ||
![]() |
eae2863286 | ||
![]() |
39bc196f64 | ||
![]() |
157dfa320f | ||
![]() |
9b4f2ac79b | ||
![]() |
c843bce9f5 | ||
![]() |
e3106a019d | ||
![]() |
3e0ceb12d5 | ||
![]() |
050adf6640 | ||
![]() |
60bbc9f626 | ||
![]() |
065926d6a4 | ||
![]() |
85bab67083 | ||
![]() |
4001379663 | ||
![]() |
382273abc5 | ||
![]() |
85af4d6916 | ||
![]() |
6825e1144e | ||
![]() |
45f8449c72 | ||
![]() |
71bf1a8a3d | ||
![]() |
bc47a16943 | ||
![]() |
566787f041 | ||
![]() |
79b2366387 | ||
![]() |
5acea014b0 | ||
![]() |
5130acf3ea | ||
![]() |
a22d1c88d7 | ||
![]() |
85849c9396 | ||
![]() |
d3c257d97d | ||
![]() |
c13fe63f10 | ||
![]() |
07842abcb0 | ||
![]() |
07e524509f | ||
![]() |
2c05752071 | ||
![]() |
7c8427b0f7 | ||
![]() |
b72801abf3 | ||
![]() |
23d5a2b862 | ||
![]() |
7715311117 | ||
![]() |
7552f70c8d | ||
![]() |
0acc398c52 | ||
![]() |
4c1cfca95b | ||
![]() |
e113ce9621 | ||
![]() |
821d08999a | ||
![]() |
e8213220e2 | ||
![]() |
83f9d2a963 | ||
![]() |
bf97ebf89f | ||
![]() |
5b22d27cbb | ||
![]() |
e907ff43ae | ||
![]() |
b18fc3a8d0 | ||
![]() |
a8e23c4140 | ||
![]() |
fc3861b421 | ||
![]() |
e81bb5d8f1 | ||
![]() |
32f4f15831 | ||
![]() |
e29c06b718 | ||
![]() |
d9d511f33e | ||
![]() |
c61a3b8d13 | ||
![]() |
e10b867fe6 | ||
![]() |
43e230f543 | ||
![]() |
e8380cf2aa | ||
![]() |
b2ae5298a7 | ||
![]() |
17dd21ac7f | ||
![]() |
1a5e0ef7c9 | ||
![]() |
979a7a1dcc | ||
![]() |
291be84704 | ||
![]() |
962cf32ba7 | ||
![]() |
ae23682372 | ||
![]() |
540919f256 | ||
![]() |
398281cd76 | ||
![]() |
88446ccde9 | ||
![]() |
6238cc0734 | ||
![]() |
fd4823c507 | ||
![]() |
68bcfd8bf0 | ||
![]() |
1d332746af | ||
![]() |
f3e133c617 | ||
![]() |
1678a6eb59 | ||
![]() |
b4dc2c07d5 | ||
![]() |
d7838950d8 | ||
![]() |
2e93a83dd5 | ||
![]() |
67c7116f05 | ||
![]() |
9aa432c078 | ||
![]() |
db8b419b8c | ||
![]() |
990f631cbc | ||
![]() |
db46d84458 | ||
![]() |
9e6c4f8d80 | ||
![]() |
41b47f95c5 | ||
![]() |
15939fd87c | ||
![]() |
f63c343f68 | ||
![]() |
1a516e7744 | ||
![]() |
5c9d97775f | ||
![]() |
64aadcd13f | ||
![]() |
1f6a7d6462 | ||
![]() |
e44b953d9a | ||
![]() |
6c85020630 | ||
![]() |
9d910320f3 | ||
![]() |
c53074efc9 | ||
![]() |
3b51c53eca | ||
![]() |
0aa0ffb67b | ||
![]() |
33f70931dd | ||
![]() |
8830ea319f | ||
![]() |
38498d3ee2 | ||
![]() |
35d1d0bc6e | ||
![]() |
fefdb7d96d | ||
![]() |
1d39a35b05 | ||
![]() |
902f18fcca | ||
![]() |
8145f34248 | ||
![]() |
ddb524b6b2 | ||
![]() |
cbcdc73f9a | ||
![]() |
4f6c54ecb3 | ||
![]() |
2bdf1b2284 | ||
![]() |
3f0805e7f6 | ||
![]() |
4c93165a67 | ||
![]() |
5f63ffd86c | ||
![]() |
9df2469e51 | ||
![]() |
2e73e605f7 | ||
![]() |
2bcd8516ea | ||
![]() |
5c3301f9a3 | ||
![]() |
f1487c30bf | ||
![]() |
08c70b0702 | ||
![]() |
df1bf28caa | ||
![]() |
8b67ae0460 | ||
![]() |
dbdf782e59 | ||
![]() |
f102cbb613 | ||
![]() |
5522967286 | ||
![]() |
a2f42e6424 | ||
![]() |
bdfe6c2c45 | ||
![]() |
5e1a2e2a93 | ||
![]() |
7376f31c97 | ||
![]() |
155fc8fa5a | ||
![]() |
7daf80a0c0 | ||
![]() |
eb87c28225 | ||
![]() |
c876d6a51c | ||
![]() |
47f54b5650 | ||
![]() |
fbfa1723e7 | ||
![]() |
a74140842c | ||
![]() |
f5a85a816c | ||
![]() |
2a15fafbd7 | ||
![]() |
2fc4802886 | ||
![]() |
bb3f487ee5 | ||
![]() |
7d97d0ae87 | ||
![]() |
f6dc9bcad6 | ||
![]() |
697531a948 | ||
![]() |
3c745b4bc6 | ||
![]() |
3a08a6ad72 | ||
![]() |
448b397cb8 | ||
![]() |
64a1386eb6 | ||
![]() |
77c2efe171 | ||
![]() |
587c0f6232 | ||
![]() |
64e8abf203 | ||
![]() |
6c40d2a656 | ||
![]() |
cf674e9273 | ||
![]() |
9bda0379af | ||
![]() |
b04c6fbd72 | ||
![]() |
b74a91427d | ||
![]() |
c67372f8af | ||
![]() |
00789de7d4 | ||
![]() |
9964a5ffe8 | ||
![]() |
5ece9685c2 | ||
![]() |
e7c5a42821 | ||
![]() |
36e6079c57 | ||
![]() |
e5f23678ca | ||
![]() |
c3cfb5fe16 | ||
![]() |
749ad7cd83 | ||
![]() |
0b59f4eaee | ||
![]() |
402663de74 | ||
![]() |
eaa66c7ee3 | ||
![]() |
996714d6ff | ||
![]() |
fe48e5596f | ||
![]() |
d7744d2b8e | ||
![]() |
33ee35ab92 | ||
![]() |
5b291ff768 | ||
![]() |
39d6816a6d | ||
![]() |
6517b2d2ac | ||
![]() |
bfdf13dca3 | ||
![]() |
86823af685 | ||
![]() |
daefc61aa4 | ||
![]() |
6fed6e50e4 | ||
![]() |
bc9e074822 | ||
![]() |
8047102542 | ||
![]() |
fe5b81e180 | ||
![]() |
f032925c2d | ||
![]() |
8125a5dddb | ||
![]() |
154170e475 | ||
![]() |
fb83936feb | ||
![]() |
db8bf52f7d | ||
![]() |
756f0b8027 | ||
![]() |
b1fba8d3d7 | ||
![]() |
4d88bddfe2 | ||
![]() |
e606044271 | ||
![]() |
bcbb3371ff | ||
![]() |
de632882d1 | ||
![]() |
745e492d15 | ||
![]() |
c5dc615efe | ||
![]() |
a08d4b3d66 | ||
![]() |
beeb02025e | ||
![]() |
cdf7062597 | ||
![]() |
346084da1e | ||
![]() |
bbceb5eb91 | ||
![]() |
90d85319c2 | ||
![]() |
3d03683e7d | ||
![]() |
d8a74802d1 | ||
![]() |
191919d1b1 | ||
![]() |
df38e7565b | ||
![]() |
cb49a03fd7 | ||
![]() |
faee5bbb78 | ||
![]() |
7befab7e83 | ||
![]() |
4244e61214 | ||
![]() |
46eab05045 | ||
![]() |
5ca137c73c | ||
![]() |
760238fe16 | ||
![]() |
a99b4abae8 | ||
![]() |
472881cb95 | ||
![]() |
c4efc37ad8 | ||
![]() |
691b6a236e | ||
![]() |
c72697ea27 | ||
![]() |
5c7243d3ad | ||
![]() |
44cfdff39a | ||
![]() |
5eedda691a | ||
![]() |
a30d5e1b6a | ||
![]() |
8ef09a0a71 | ||
![]() |
e8044663b3 | ||
![]() |
8444c33514 | ||
![]() |
e709d9d15c | ||
![]() |
2b7328b434 | ||
![]() |
e0e5ed62ee | ||
![]() |
3d7147390f | ||
![]() |
ca705e1e37 | ||
![]() |
3c5ef504f8 | ||
![]() |
25b5ca6435 | ||
![]() |
fd217daad4 | ||
![]() |
d9f9b3df10 | ||
![]() |
a43ee97746 | ||
![]() |
43c32372e7 | ||
![]() |
5716cde1fb | ||
![]() |
b7a99b4a4b | ||
![]() |
c6a7f6dabc | ||
![]() |
24741c5d06 | ||
![]() |
6b3a282db4 | ||
![]() |
7583cfe9b7 | ||
![]() |
aafc9ce75b | ||
![]() |
fea326530b | ||
![]() |
8925cc17d8 | ||
![]() |
14412c867f | ||
![]() |
c5cc256bf2 | ||
![]() |
563c7318f9 | ||
![]() |
e92129f449 | ||
![]() |
96a273bf3b | ||
![]() |
66c27d2c13 | ||
![]() |
374cc51f77 | ||
![]() |
c031f9aa5d | ||
![]() |
068006ebd7 | ||
![]() |
d2362b7c31 | ||
![]() |
9a4059ba39 | ||
![]() |
759f4231d2 | ||
![]() |
0cefb61a2e | ||
![]() |
b7ab1a9d79 | ||
![]() |
d181ecce7b | ||
![]() |
d2d53cc9d6 | ||
![]() |
93d87854e9 | ||
![]() |
e5eac71d72 | ||
![]() |
f20b927858 | ||
![]() |
e4dad42ca1 | ||
![]() |
99afe8e6d1 | ||
![]() |
1008d5f67c | ||
![]() |
169810e8f4 | ||
![]() |
8e07ea7ad8 | ||
![]() |
9f5c6d29b2 | ||
![]() |
f6823cc679 | ||
![]() |
69c0f0fe99 | ||
![]() |
28a00472ff | ||
![]() |
8d540737b9 | ||
![]() |
1112d779be | ||
![]() |
ecced0ce13 | ||
![]() |
d751df0a73 | ||
![]() |
2c084781b0 | ||
![]() |
6e1a21a42a | ||
![]() |
80e8338014 | ||
![]() |
bfaa7afcb0 | ||
![]() |
ae7d550a01 | ||
![]() |
7fdbaa6156 | ||
![]() |
aa7dc62f72 | ||
![]() |
6a4992118a | ||
![]() |
f03cc1012d | ||
![]() |
736a696f98 | ||
![]() |
caec384ed0 | ||
![]() |
8fdc6dec44 | ||
![]() |
5e93e882c9 | ||
![]() |
30d97fe8a0 | ||
![]() |
5cb0080052 | ||
![]() |
8e4ca23727 | ||
![]() |
bdc861f058 | ||
![]() |
8925040262 | ||
![]() |
c065950ced | ||
![]() |
257a77fa35 | ||
![]() |
4e5d6e560b | ||
![]() |
d276d8eda2 | ||
![]() |
ebcb5e9368 | ||
![]() |
69f09648a4 | ||
![]() |
9adda30c38 | ||
![]() |
c5f80dc543 | ||
![]() |
d2d4a0251e | ||
![]() |
f7b6431b6f | ||
![]() |
03b9bd3a9e | ||
![]() |
6cc58ccb9b | ||
![]() |
210c270624 | ||
![]() |
be94b4373a | ||
![]() |
eeec0ee804 | ||
![]() |
a24ef280cc | ||
![]() |
d1d6a3871e | ||
![]() |
61aed60f6d | ||
![]() |
2cc323c9fe | ||
![]() |
f24ab120ee | ||
![]() |
68349bc55c | ||
![]() |
60f957ed64 | ||
![]() |
864d26cd1b | ||
![]() |
ba576ffa37 | ||
![]() |
209364adf2 | ||
![]() |
dae8da7066 | ||
![]() |
cdf8ac001c | ||
![]() |
62d0ceabcc | ||
![]() |
935e622915 | ||
![]() |
1efbbfcd6f | ||
![]() |
e0edf0b206 | ||
![]() |
4e9fa36176 | ||
![]() |
8f178401e4 | ||
![]() |
8c1d78873d | ||
![]() |
9815d10137 | ||
![]() |
97f7270aa8 | ||
![]() |
1787aa5e00 | ||
![]() |
e6a77e1297 | ||
![]() |
e251fd0053 | ||
![]() |
24afdee35c | ||
![]() |
7aea285361 | ||
![]() |
47a7707df1 | ||
![]() |
6fdae1139f | ||
![]() |
a485c4856c | ||
![]() |
3c955639a7 | ||
![]() |
bca9678683 | ||
![]() |
814b2a218d | ||
![]() |
6423670eae | ||
![]() |
90a2109fd1 | ||
![]() |
464b90210c | ||
![]() |
fa45a8adfa | ||
![]() |
1532983fb5 | ||
![]() |
ae5b2643da | ||
![]() |
02556ffce9 | ||
![]() |
18ca734819 | ||
![]() |
8a28f7b0a1 | ||
![]() |
cc72ceb368 | ||
![]() |
c021efced1 | ||
![]() |
0b3acc3eec | ||
![]() |
6979be008c | ||
![]() |
71792ffd43 | ||
![]() |
3c145c0f49 | ||
![]() |
55b8f2c533 | ||
![]() |
8437b141a4 | ||
![]() |
1f0881eec0 | ||
![]() |
3c240e2119 | ||
![]() |
57fb153c5d | ||
![]() |
212401d687 | ||
![]() |
dd831d3922 | ||
![]() |
9f8dc31b50 | ||
![]() |
db93bb996c | ||
![]() |
2c02a04566 | ||
![]() |
f13f66487a | ||
![]() |
0a4c5edc3b | ||
![]() |
015cbff93d | ||
![]() |
79e9aff338 | ||
![]() |
3a51fe31df | ||
![]() |
cc3e71d8c7 | ||
![]() |
dd37b4656e | ||
![]() |
e2d2bb8755 | ||
![]() |
a98d627c0b | ||
![]() |
0080eee857 | ||
![]() |
2429cc8778 | ||
![]() |
3a83a6b527 | ||
![]() |
bcf4645263 | ||
![]() |
6c8eb3c7ed | ||
![]() |
870151214d | ||
![]() |
ae4fd576bf | ||
![]() |
747436b17e | ||
![]() |
7a58b8c3e8 | ||
![]() |
56b4b010d6 | ||
![]() |
91c75a133f | ||
![]() |
e620677d7c | ||
![]() |
09d8e44d56 | ||
![]() |
9dc530ab51 | ||
![]() |
2d0798cd4d | ||
![]() |
a269fc988b | ||
![]() |
915c48f748 | ||
![]() |
f04a245769 | ||
![]() |
a8687fb7df | ||
![]() |
3b88bac07c | ||
![]() |
358f231391 | ||
![]() |
f0923231d0 | ||
![]() |
dadf054fbb | ||
![]() |
6593b5998a | ||
![]() |
386235e2d2 | ||
![]() |
ddfd92e547 | ||
![]() |
d5fd309484 | ||
![]() |
6197b29aa0 | ||
![]() |
02294a8236 | ||
![]() |
66bcf04cbd | ||
![]() |
12b97bbe38 | ||
![]() |
7d7bd51bc0 | ||
![]() |
71e551df42 | ||
![]() |
3540cf26b1 | ||
![]() |
cfa4524cb3 | ||
![]() |
4fd0c84f46 | ||
![]() |
e41a52d909 | ||
![]() |
01e00632cc | ||
![]() |
9bad5ee3c5 | ||
![]() |
e87454ae88 | ||
![]() |
f319f88df4 | ||
![]() |
637840264a | ||
![]() |
3888bafc1f | ||
![]() |
adad4c7298 | ||
![]() |
d54acbcffd | ||
![]() |
86613af37e | ||
![]() |
ba3ff10ccd | ||
![]() |
1ec283d213 | ||
![]() |
2261bcb5d3 | ||
![]() |
0e17629445 | ||
![]() |
0da6344726 | ||
![]() |
cade4e71c4 | ||
![]() |
403612c666 | ||
![]() |
7fe49cf24d | ||
![]() |
d2115e908a | ||
![]() |
61b5ab2663 | ||
![]() |
84f71cec2c | ||
![]() |
a5b136c420 | ||
![]() |
c7144ed5c7 | ||
![]() |
00b9f69c90 | ||
![]() |
6d91b5c7b2 | ||
![]() |
fd71514068 | ||
![]() |
256cfc545d | ||
![]() |
77c6c3fabf | ||
![]() |
e25a3d17e7 | ||
![]() |
7f10e7a610 | ||
![]() |
88d56c01e7 | ||
![]() |
97425d56e7 | ||
![]() |
0afb156a5b | ||
![]() |
a192e7b29b | ||
![]() |
591f51f3d3 | ||
![]() |
5e4b7e2fb7 | ||
![]() |
177371a003 | ||
![]() |
a78841d6a9 | ||
![]() |
3ec9fcfc44 | ||
![]() |
b5d1a09010 | ||
![]() |
85b072b3d3 | ||
![]() |
8a1f1fbe06 | ||
![]() |
45b60b3d38 | ||
![]() |
cefc773992 | ||
![]() |
a885bdba4c | ||
![]() |
b6b15afb5a | ||
![]() |
1d560c8f0f | ||
![]() |
189f6eaa6f | ||
![]() |
87f78b9c39 | ||
![]() |
aa722bd8ac | ||
![]() |
58c7ec07a4 | ||
![]() |
3796247d6d | ||
![]() |
332f480ec3 | ||
![]() |
9a164668f2 | ||
![]() |
6876d160cf | ||
![]() |
a63d0ee8fc | ||
![]() |
d4135935e4 | ||
![]() |
569773cc75 | ||
![]() |
a2f5a63bbc | ||
![]() |
2db8bcc353 | ||
![]() |
c846ee0d1b | ||
![]() |
69a51e12c9 | ||
![]() |
4b57b7f5a5 | ||
![]() |
5cd400f578 | ||
![]() |
edc4989d9c | ||
![]() |
2b3d6461e3 | ||
![]() |
ab9f5d2067 | ||
![]() |
a718086ffb | ||
![]() |
8d40e68dec | ||
![]() |
de0affe115 | ||
![]() |
26e718c7c3 | ||
![]() |
f00f8b002a | ||
![]() |
2229e86673 | ||
![]() |
f24c274f5c | ||
![]() |
3824bf66ca | ||
![]() |
d942f874ae | ||
![]() |
01632d37ef | ||
![]() |
c977d646c7 | ||
![]() |
ac50bb5d2b | ||
![]() |
85e33f7d60 | ||
![]() |
7646866a32 | ||
![]() |
d072b3cb17 | ||
![]() |
646fef108a | ||
![]() |
d1cc73775f | ||
![]() |
29d05cdb8e | ||
![]() |
322d6f2a40 | ||
![]() |
7729713924 | ||
![]() |
351a4a80d2 | ||
![]() |
87f7b0f0bb | ||
![]() |
6d3190fe5f | ||
![]() |
5d787806fe | ||
![]() |
dea0cc165d | ||
![]() |
07e0a31d02 | ||
![]() |
36a678276b | ||
![]() |
d4a6d647a0 | ||
![]() |
2d3b51665e | ||
![]() |
7b03f55cb4 | ||
![]() |
b84444b680 | ||
![]() |
1e421cbcb2 | ||
![]() |
a4eed3e330 | ||
![]() |
b9db8ddee6 | ||
![]() |
9cf1385765 | ||
![]() |
a3963de668 | ||
![]() |
7d2c4ec775 | ||
![]() |
1de5bd64d8 | ||
![]() |
1923cf3844 | ||
![]() |
196d5fde65 | ||
![]() |
140d8547c7 | ||
![]() |
6f579ddc95 | ||
![]() |
8e4cb3217e | ||
![]() |
7bcccbedad | ||
![]() |
7c62887df7 | ||
![]() |
3fc859c42d | ||
![]() |
7e41c4de58 | ||
![]() |
452c41b71f | ||
![]() |
4b0444e760 | ||
![]() |
ecad6d936a | ||
![]() |
568deefd68 | ||
![]() |
40d0420648 | ||
![]() |
afb29942b0 | ||
![]() |
15fa780c99 | ||
![]() |
9db3809c7b | ||
![]() |
dfed9546aa | ||
![]() |
469cd9582f | ||
![]() |
bc6eca2115 | ||
![]() |
72ec641f0d | ||
![]() |
4f22f4d357 | ||
![]() |
4c52001a35 | ||
![]() |
faa04966af | ||
![]() |
302eff0a59 | ||
![]() |
bcc4e97c60 | ||
![]() |
4968dd4faa | ||
![]() |
0896f44455 | ||
![]() |
620872390b | ||
![]() |
f7c326dbeb | ||
![]() |
50de3a7886 | ||
![]() |
36cad54ccd | ||
![]() |
b64fdae938 | ||
![]() |
0b2444450f | ||
![]() |
faf149d08e | ||
![]() |
e01bbad7bb | ||
![]() |
7e3eaa5921 | ||
![]() |
6fe4068c8e | ||
![]() |
8472135859 | ||
![]() |
1e07d15428 | ||
![]() |
cc7f66822e | ||
![]() |
9cbfa66886 | ||
![]() |
4df98466df | ||
![]() |
ff2e584bde | ||
![]() |
49309b419f | ||
![]() |
879bafb837 | ||
![]() |
6fcea2d484 | ||
![]() |
5d597a3646 | ||
![]() |
56eaf000a4 | ||
![]() |
77271ebc1f | ||
![]() |
fd2b2cf0bc | ||
![]() |
438a6d7595 | ||
![]() |
00ed836aa9 | ||
![]() |
5afec8256a | ||
![]() |
f249a755e2 | ||
![]() |
4029a79dc2 | ||
![]() |
c16233fa74 | ||
![]() |
ac126ede22 | ||
![]() |
7732db0aee | ||
![]() |
37f984ba74 | ||
![]() |
cd612c4eef | ||
![]() |
914ad261ed | ||
![]() |
7551867249 | ||
![]() |
bdd3167495 | ||
![]() |
526c778162 | ||
![]() |
e01bddbd86 | ||
![]() |
2817bf9e95 | ||
![]() |
a37d22de8a | ||
![]() |
452e1c1a6f | ||
![]() |
8db86e2820 | ||
![]() |
c84bae739a | ||
![]() |
925b5954c3 | ||
![]() |
dca79938d5 | ||
![]() |
235b6980b8 | ||
![]() |
ee46150329 | ||
![]() |
79c585bf03 | ||
![]() |
becd81f771 | ||
![]() |
2073a2c1b0 | ||
![]() |
3f3104348e | ||
![]() |
7e80c62c7c | ||
![]() |
4038d8527f | ||
![]() |
3565f0c8ce | ||
![]() |
9647b2cb01 | ||
![]() |
2d5bf53240 | ||
![]() |
a65f7b1006 | ||
![]() |
bc5b647053 | ||
![]() |
1708ae3e3c | ||
![]() |
6bfbc5d320 | ||
![]() |
e7483bc5bc | ||
![]() |
b911ec1a29 | ||
![]() |
ca2633bf26 | ||
![]() |
e0784cd48b | ||
![]() |
566ac171f5 | ||
![]() |
8aaf39efd6 | ||
![]() |
4d95402e4e | ||
![]() |
4d102c4770 | ||
![]() |
91bc41ea20 | ||
![]() |
e565dcf18c | ||
![]() |
5a87fc7c26 | ||
![]() |
64309abc14 | ||
![]() |
b11c5f8d30 | ||
![]() |
44d7a1d8d2 | ||
![]() |
4937d77cb6 | ||
![]() |
53f8053188 | ||
![]() |
e654c6e005 | ||
![]() |
4b0e288f00 | ||
![]() |
71ace2fbac | ||
![]() |
fb450d2f41 | ||
![]() |
84784badce | ||
![]() |
5990e46de2 | ||
![]() |
7dea5db5df | ||
![]() |
803a48e96d | ||
![]() |
57b8e7f651 | ||
![]() |
83acbe1002 | ||
![]() |
a72878c5b9 | ||
![]() |
bd4df1ae5d | ||
![]() |
a93b7172aa | ||
![]() |
908b6a1939 | ||
![]() |
561ccf600f | ||
![]() |
aee861c009 | ||
![]() |
2cc1dd28cd | ||
![]() |
f8d7bc1c34 | ||
![]() |
a684b4fff1 | ||
![]() |
c82cef3aa6 | ||
![]() |
683d5848f4 | ||
![]() |
b449627265 | ||
![]() |
940206d106 | ||
![]() |
65bbb975d2 | ||
![]() |
c129ca9f63 | ||
![]() |
1e03457746 | ||
![]() |
43ac264f54 | ||
![]() |
cbaa98c1a1 | ||
![]() |
ed327c597a | ||
![]() |
496f43e25d | ||
![]() |
3f4437266b | ||
![]() |
799097c385 | ||
![]() |
4ecd4761c2 | ||
![]() |
e1867a99e9 | ||
![]() |
b2c4a5db14 | ||
![]() |
cadfccfd0c | ||
![]() |
c89c7f71a2 | ||
![]() |
2f3e94f8d0 | ||
![]() |
f616bfe354 | ||
![]() |
f2c3d86612 | ||
![]() |
d7dbf47a3f | ||
![]() |
3db584a3ea | ||
![]() |
409002b1c3 | ||
![]() |
29b542fd36 | ||
![]() |
c9590db188 | ||
![]() |
0643b5abad | ||
![]() |
d63e2c2641 | ||
![]() |
5fdb804a50 | ||
![]() |
91c1274ac6 | ||
![]() |
9caf90f74f | ||
![]() |
71448e645c | ||
![]() |
0509472636 | ||
![]() |
0b956cf968 | ||
![]() |
2c3eb5b8ad | ||
![]() |
58363cf4dd | ||
![]() |
2574615fa3 | ||
![]() |
15fbd2b4ab | ||
![]() |
ee36a48dbb | ||
![]() |
07f212c98c | ||
![]() |
a1e2602c3d | ||
![]() |
b03e4ae692 | ||
![]() |
57808d1a1b | ||
![]() |
7775691965 | ||
![]() |
a727150c8d | ||
![]() |
949916cba1 | ||
![]() |
497d090814 | ||
![]() |
6a13847287 | ||
![]() |
cbe7d052e8 | ||
![]() |
f4d0bd8205 | ||
![]() |
1bfede120a | ||
![]() |
e96856032f | ||
![]() |
05a29e8458 | ||
![]() |
7f9a8b8748 | ||
![]() |
af3f637d3f | ||
![]() |
97a9adcbec | ||
![]() |
177d3b0178 | ||
![]() |
12beb22c1d | ||
![]() |
29fd3172ee | ||
![]() |
a873137702 | ||
![]() |
e08298a66f | ||
![]() |
fd1826cb91 | ||
![]() |
d5681b678c | ||
![]() |
0fd6235a66 | ||
![]() |
4d11745156 | ||
![]() |
2038620bc4 | ||
![]() |
5dc7cb87bb | ||
![]() |
f885e068c8 | ||
![]() |
0d16772dea | ||
![]() |
2376527d1f | ||
![]() |
7f043367ed | ||
![]() |
45403b44de | ||
![]() |
32f865f146 | ||
![]() |
9f92b59376 | ||
![]() |
2bb5030f70 | ||
![]() |
366de8773c | ||
![]() |
d3cc54d4eb | ||
![]() |
71ef0faa2c | ||
![]() |
328a6de86e | ||
![]() |
f750c8012a | ||
![]() |
b0a04b3da8 | ||
![]() |
9617bd6c85 | ||
![]() |
4c7154bd23 | ||
![]() |
4f5c3b349d | ||
![]() |
4fabfdabde | ||
![]() |
2e9b5e4e78 | ||
![]() |
115dd2b5ce | ||
![]() |
b18003ddfd | ||
![]() |
6ec335dcd5 | ||
![]() |
d5d6746ddf | ||
![]() |
00d7759cee | ||
![]() |
2ecc4e3eed | ||
![]() |
7d98145ea8 | ||
![]() |
e7c5a59e39 | ||
![]() |
71c45d8ebe | ||
![]() |
c9081a206a | ||
![]() |
f2cdbeace6 | ||
![]() |
e6600b8562 | ||
![]() |
04e2d08417 | ||
![]() |
af4ffa91fd | ||
![]() |
f3ed2c0a82 | ||
![]() |
2c35ea92bd | ||
![]() |
26e0e1d25a | ||
![]() |
6412efb6e4 | ||
![]() |
995783bb2f | ||
![]() |
1a08bdf16f | ||
![]() |
48b122f2ed | ||
![]() |
06dac4783f | ||
![]() |
fdaadc19cb | ||
![]() |
2e53e9248a | ||
![]() |
b7abd5691c | ||
![]() |
7a0957d713 | ||
![]() |
2934fc2507 | ||
![]() |
0c8ff56a15 | ||
![]() |
07be44a50a | ||
![]() |
7a473729af | ||
![]() |
402f429b17 | ||
![]() |
4c46ca6b59 | ||
![]() |
76a0bf68c7 | ||
![]() |
9f02beaba9 | ||
![]() |
a478af6759 | ||
![]() |
4c2434788f | ||
![]() |
ca9daf5e19 | ||
![]() |
e98ce710b8 | ||
![]() |
79d1004544 | ||
![]() |
bb7f7bd3e5 | ||
![]() |
ad2b858933 | ||
![]() |
d7aa4fa7d3 | ||
![]() |
57c5603122 | ||
![]() |
1550113506 | ||
![]() |
a82d61a5e4 | ||
![]() |
0c4a7c8004 | ||
![]() |
674ee9d19a | ||
![]() |
3344953db8 | ||
![]() |
f909615b14 | ||
![]() |
92c89f0c86 | ||
![]() |
34246eb7fd | ||
![]() |
5894514ccb | ||
![]() |
dcb07e6ed4 | ||
![]() |
ccffff9870 | ||
![]() |
e34672c9d8 | ||
![]() |
a8f314190f | ||
![]() |
545af857ba | ||
![]() |
01f86e1c25 | ||
![]() |
7a89b1656c | ||
![]() |
07fcf091a2 | ||
![]() |
74a883dbf8 | ||
![]() |
5c550e8b33 | ||
![]() |
433e18b247 | ||
![]() |
2b837277c1 | ||
![]() |
d515a8e99a | ||
![]() |
2c2efaa91f | ||
![]() |
9ae9b2c18f | ||
![]() |
8e0d810968 | ||
![]() |
0f1e13d9ff | ||
![]() |
21b81dfb1d | ||
![]() |
6b51429203 | ||
![]() |
e2da13b0d3 | ||
![]() |
54daa85ac2 | ||
![]() |
575ba51931 | ||
![]() |
96a1c69c29 | ||
![]() |
3895d35a52 | ||
![]() |
b717ab0383 | ||
![]() |
4f61cd0b93 | ||
![]() |
989790e7f1 | ||
![]() |
831bc711ca | ||
![]() |
d640961420 | ||
![]() |
828c614d57 | ||
![]() |
4964ad7800 | ||
![]() |
a7976cd0f2 | ||
![]() |
bed8a0e040 | ||
![]() |
b8a64771c0 | ||
![]() |
f357f743a3 | ||
![]() |
91e565d92e | ||
![]() |
a189a9e478 | ||
![]() |
9654a33218 | ||
![]() |
9bcd02d178 | ||
![]() |
cf9ee33928 | ||
![]() |
4a47bbd816 | ||
![]() |
7654038d65 | ||
![]() |
e4612ecb66 | ||
![]() |
9c6850210d | ||
![]() |
40a2880857 | ||
![]() |
ade712d711 | ||
![]() |
175e13099c | ||
![]() |
349a2ea7eb | ||
![]() |
192ad91010 | ||
![]() |
91fb91d89c | ||
![]() |
8b399b7133 | ||
![]() |
9d24f68f51 | ||
![]() |
44652fdb13 | ||
![]() |
2892a6f5e2 | ||
![]() |
2fc40e5575 | ||
![]() |
7363fe90bb | ||
![]() |
d146bef740 | ||
![]() |
1f4c4be1f1 | ||
![]() |
90067d16c0 | ||
![]() |
cde6c46d2f | ||
![]() |
d305f187d5 | ||
![]() |
4f6a713b32 | ||
![]() |
8f981845dc | ||
![]() |
c764b70b3a | ||
![]() |
52bb03e136 | ||
![]() |
a90685d6cf | ||
![]() |
fe2f8c088a | ||
![]() |
af99f9fc90 | ||
![]() |
a784c8b1ae | ||
![]() |
991bbea875 | ||
![]() |
a2d2210713 | ||
![]() |
426891ab31 | ||
![]() |
b94de51ac4 | ||
![]() |
db024c27d5 | ||
![]() |
326c6ae615 | ||
![]() |
5fa7610264 | ||
![]() |
1c757f8c1c | ||
![]() |
06fbbe2d7b | ||
![]() |
21d91cb1d1 | ||
![]() |
9d3d4fc734 | ||
![]() |
d6660bad03 | ||
![]() |
9d74b1a212 | ||
![]() |
54c7dc029e | ||
![]() |
d8bcdca7ff | ||
![]() |
d663f81420 | ||
![]() |
9cdebc90a0 | ||
![]() |
0a267056d3 | ||
![]() |
4650a903b4 | ||
![]() |
94c9fafe16 | ||
![]() |
8480b834b3 | ||
![]() |
07080574a2 | ||
![]() |
6c22c34300 | ||
![]() |
f54710b100 | ||
![]() |
196db1a8c8 | ||
![]() |
d66ef7eac1 | ||
![]() |
0a32634d8f | ||
![]() |
b12fc3c60d | ||
![]() |
6d013b092f | ||
![]() |
ccb182865c | ||
![]() |
412b04be58 | ||
![]() |
510e6841a0 | ||
![]() |
2089c99348 | ||
![]() |
77b5b4158c | ||
![]() |
08552f3938 | ||
![]() |
2700265769 | ||
![]() |
557098644b | ||
![]() |
44aaf51345 | ||
![]() |
4e2a551f30 | ||
![]() |
5b01373356 | ||
![]() |
a92aa0bedc | ||
![]() |
d66f5a8590 | ||
![]() |
30ca6b8881 | ||
![]() |
cf631fca50 | ||
![]() |
f0ac63d5af | ||
![]() |
c1eb0583c4 | ||
![]() |
549faa8a9c | ||
![]() |
8f6c750064 | ||
![]() |
9fc1668de3 | ||
![]() |
e9190f4249 | ||
![]() |
127b464c59 | ||
![]() |
048990cd2f | ||
![]() |
01fd6e5e82 | ||
![]() |
beed004b10 | ||
![]() |
730e67d766 | ||
![]() |
34c6337887 | ||
![]() |
2093e53641 | ||
![]() |
2f243f2295 | ||
![]() |
e69fd0300a | ||
![]() |
f43cafbf7d | ||
![]() |
53faf77d20 | ||
![]() |
bf574dcb0a | ||
![]() |
72b8f33272 | ||
![]() |
a17f420d6b | ||
![]() |
f97a9ce765 | ||
![]() |
bf26adf555 | ||
![]() |
0cc94fe30c | ||
![]() |
d5d5705213 | ||
![]() |
96d74e77eb | ||
![]() |
ca8451cdbc | ||
![]() |
28e07e900f | ||
![]() |
c75dc4a647 | ||
![]() |
32380d1db0 | ||
![]() |
c9f1354e4d | ||
![]() |
e3f9e96eef | ||
![]() |
8f9b3cbf0e | ||
![]() |
458a1beed9 | ||
![]() |
47bb1cd8b5 | ||
![]() |
ccc96e25d3 | ||
![]() |
33f5e03e80 | ||
![]() |
fd7caab872 | ||
![]() |
e87f0ca771 | ||
![]() |
a139279575 | ||
![]() |
9fcd33cc8d | ||
![]() |
96ff6b9b8b | ||
![]() |
fd5e74dbd0 | ||
![]() |
b64571f4a5 | ||
![]() |
22a9e866bc | ||
![]() |
97e6ea57c4 | ||
![]() |
527642a90b | ||
![]() |
aebb1baad8 | ||
![]() |
bd6b7aa88e | ||
![]() |
fcf6415963 | ||
![]() |
be79b44dc8 | ||
![]() |
17f207ffd1 | ||
![]() |
476647bfa0 | ||
![]() |
9f246fc0dc | ||
![]() |
7de6e4dbac | ||
![]() |
15dbb8082e | ||
![]() |
1a7e3bb358 | ||
![]() |
74380d2ae4 | ||
![]() |
d43ce8413a | ||
![]() |
3055c1266d | ||
![]() |
931c3a1de0 | ||
![]() |
a7b30fcb9e | ||
![]() |
e153407b51 | ||
![]() |
5675431eaf | ||
![]() |
8a136b79e5 | ||
![]() |
dffa25c55e | ||
![]() |
72a0aeb265 | ||
![]() |
e556cd20f7 | ||
![]() |
80ec6f976c | ||
![]() |
589639f80f | ||
![]() |
548aa00111 | ||
![]() |
76eb550011 | ||
![]() |
c1719a5200 | ||
![]() |
b07bbb928a | ||
![]() |
3b5a128097 | ||
![]() |
fad60f977e | ||
![]() |
71f9332bd3 | ||
![]() |
3eae3a2826 | ||
![]() |
3c1f7c77f0 | ||
![]() |
3e40b1d9d2 | ||
![]() |
adffbba2a5 | ||
![]() |
120e570da7 | ||
![]() |
0019231a37 | ||
![]() |
9ae1256ae7 | ||
![]() |
e1ac377812 | ||
![]() |
7866d1a005 | ||
![]() |
3e3ee581a8 | ||
![]() |
0e8ca44968 | ||
![]() |
12e75a523a | ||
![]() |
508ba22789 | ||
![]() |
fa13648f2c | ||
![]() |
2f83ed90d0 | ||
![]() |
5d74b5cee1 | ||
![]() |
e8a0ce643a | ||
![]() |
9ed4fac341 | ||
![]() |
81b2b4a85c | ||
![]() |
7739b3960c | ||
![]() |
11ec7117ab | ||
![]() |
c3ccbfd407 | ||
![]() |
de3cd96c76 | ||
![]() |
d8cf7d1ef0 | ||
![]() |
57de2470f1 | ||
![]() |
8fef4af7b2 | ||
![]() |
cfb678d618 | ||
![]() |
4eb101f046 | ||
![]() |
af7970337b | ||
![]() |
96a37da03d | ||
![]() |
ece35552fe | ||
![]() |
7d599c1afc | ||
![]() |
7c565bce1d | ||
![]() |
d17ff18ec0 | ||
![]() |
efc6b1b77a | ||
![]() |
fdbec694c6 | ||
![]() |
b86d8d0cd8 | ||
![]() |
0b4e7b3317 | ||
![]() |
472e4bfd41 | ||
![]() |
d3d70a7eed | ||
![]() |
39046bed85 | ||
![]() |
71a5c8b819 | ||
![]() |
620a39afb4 | ||
![]() |
14cee01ba1 | ||
![]() |
c782fdb698 | ||
![]() |
49ba76167e | ||
![]() |
93ab957800 | ||
![]() |
155c915733 | ||
![]() |
971450f0d4 | ||
![]() |
40a48cfba0 | ||
![]() |
9d1906da8a | ||
![]() |
3d2b180cf8 | ||
![]() |
f987947730 | ||
![]() |
e0d5d88104 | ||
![]() |
585a745484 | ||
![]() |
43fe513de8 | ||
![]() |
c1b853ca7c | ||
![]() |
4b78038b41 | ||
![]() |
d651d1abfd | ||
![]() |
5a8b734cfd | ||
![]() |
31b59a0db6 | ||
![]() |
92f7421715 | ||
![]() |
6f1d5105ee | ||
![]() |
9a78371b5c | ||
![]() |
3fc4da382e | ||
![]() |
6ee7d88af0 | ||
![]() |
bbdf2dcf1e | ||
![]() |
02bb47dd08 | ||
![]() |
0c48b8d084 | ||
![]() |
8462559b2f | ||
![]() |
319c9699fb | ||
![]() |
06a0a4a838 | ||
![]() |
8942be858b | ||
![]() |
45a091c00c | ||
![]() |
219546cb81 | ||
![]() |
555a4d738c | ||
![]() |
813567bf5c | ||
![]() |
16a07bc201 | ||
![]() |
1153715608 | ||
![]() |
b5c7c16fb4 | ||
![]() |
302c0515b7 | ||
![]() |
19e4672a54 | ||
![]() |
c2dd6808e1 | ||
![]() |
2cf6b77627 | ||
![]() |
a5c09f4ddb | ||
![]() |
1acb9bcedb | ||
![]() |
0626e3d21e | ||
![]() |
869d215058 | ||
![]() |
0cf922b2da | ||
![]() |
5e266cd8e4 | ||
![]() |
a199f58db5 | ||
![]() |
5277297336 | ||
![]() |
604d08b2c6 | ||
![]() |
a48604d2e3 | ||
![]() |
98e6a861ca | ||
![]() |
2c6dd04d19 | ||
![]() |
82ca3aa281 | ||
![]() |
b45f5c7bf6 | ||
![]() |
f54877d128 | ||
![]() |
af3ea97a42 | ||
![]() |
8beac03dc4 | ||
![]() |
4a49a5587d | ||
![]() |
d0cfa44c8f | ||
![]() |
5bae6946c6 | ||
![]() |
a8fc805594 | ||
![]() |
a265738528 | ||
![]() |
5641c4baa6 | ||
![]() |
96f889276f | ||
![]() |
214ddee2f5 | ||
![]() |
973c87b351 | ||
![]() |
72fc117393 | ||
![]() |
230ca2e968 | ||
![]() |
9095167039 | ||
![]() |
ad4ca0c449 | ||
![]() |
0a0cc66e8f | ||
![]() |
1b5c1f75a4 | ||
![]() |
040573c636 | ||
![]() |
bc5d4f9494 | ||
![]() |
dedc4b4b10 | ||
![]() |
cf348f9fae | ||
![]() |
23d56cb6a1 | ||
![]() |
4473816384 | ||
![]() |
2c8d004f78 | ||
![]() |
684bd9153e | ||
![]() |
ec456fc57c | ||
![]() |
7c92eb4360 | ||
![]() |
2c6ebe28e9 | ||
![]() |
401f06f367 | ||
![]() |
2b4e9cc635 | ||
![]() |
afdaaba045 | ||
![]() |
1cfc0cb874 | ||
![]() |
3882c97545 | ||
![]() |
bf9f690c70 | ||
![]() |
392b783c9e | ||
![]() |
6d86902a02 | ||
![]() |
376f4a2b16 | ||
![]() |
b42f19f514 | ||
![]() |
92022658f9 | ||
![]() |
b51bae5500 | ||
![]() |
5bc8cd0ecb | ||
![]() |
d38a079ba1 | ||
![]() |
c75a0f7c75 | ||
![]() |
e740f8d969 | ||
![]() |
9da7509944 | ||
![]() |
36aa204575 | ||
![]() |
2c0a968735 | ||
![]() |
84c406d5f5 | ||
![]() |
0e48747607 | ||
![]() |
f764925edc | ||
![]() |
692c8025a2 | ||
![]() |
a6dc1ab0a9 | ||
![]() |
77c9081f78 | ||
![]() |
c88d5616f7 | ||
![]() |
34d483a34a | ||
![]() |
5a3828ed4a | ||
![]() |
3fe7f27345 | ||
![]() |
0dccadff89 | ||
![]() |
5a915eb0e6 | ||
![]() |
7b48ae4f85 | ||
![]() |
92dc4a0ca7 | ||
![]() |
c7c303eec3 | ||
![]() |
1b62adc894 | ||
![]() |
0641ce79fe | ||
![]() |
b985835d8b | ||
![]() |
e413dcf8c6 | ||
![]() |
ea61e6dde1 | ||
![]() |
f7f858cb07 | ||
![]() |
4d1546cb38 | ||
![]() |
a4bc972aad | ||
![]() |
1415bac1d6 | ||
![]() |
7a98a784b2 | ||
![]() |
162845cc6d | ||
![]() |
a8ee7269bc | ||
![]() |
7c1843ee2e | ||
![]() |
bc8bb41aef | ||
![]() |
a8b94a4507 | ||
![]() |
f1b6deb768 | ||
![]() |
72ebd5ebdd | ||
![]() |
61b2ae0f7c | ||
![]() |
0d2ec5ead2 | ||
![]() |
5b74ed6b3b | ||
![]() |
ccc58f2a32 | ||
![]() |
d28307e082 | ||
![]() |
aa5c5bf14f | ||
![]() |
2e80477218 | ||
![]() |
8b9df85daa | ||
![]() |
38d0f02e83 | ||
![]() |
edafe4cad6 | ||
![]() |
3cbadf42a5 | ||
![]() |
1d49f1108f | ||
![]() |
791245dec2 | ||
![]() |
8e5e97bfed | ||
![]() |
17dd334b82 | ||
![]() |
ab5eb4f9ce | ||
![]() |
a30af2ba42 | ||
![]() |
9f1c23e217 | ||
![]() |
28fc1d555f | ||
![]() |
ac74f284aa | ||
![]() |
77af999b46 | ||
![]() |
4926763f00 | ||
![]() |
a19eee78c6 | ||
![]() |
6be3c99876 | ||
![]() |
8006911a1f | ||
![]() |
61e5828790 | ||
![]() |
6addc9d6e0 | ||
![]() |
e78d825059 | ||
![]() |
00b04468dc | ||
![]() |
8a07724b23 | ||
![]() |
5256929b17 | ||
![]() |
093bf5d859 | ||
![]() |
4f6144dc71 | ||
![]() |
2d1493ed7a | ||
![]() |
43677d5740 | ||
![]() |
693815bb32 | ||
![]() |
58d7804d66 | ||
![]() |
ea5e6d8f33 | ||
![]() |
c1272c72b0 | ||
![]() |
7d1db5c19f | ||
![]() |
2142d070a3 | ||
![]() |
9711cee26d | ||
![]() |
39baa4e364 | ||
![]() |
f339a53e3c | ||
![]() |
d9117a272b | ||
![]() |
b8a8bdeaec | ||
![]() |
8f20edac9d | ||
![]() |
8499a662ea | ||
![]() |
3f05b7d8b4 | ||
![]() |
1d563700a4 | ||
![]() |
def6b936c8 | ||
![]() |
3610f55479 | ||
![]() |
6db84852ae | ||
![]() |
41dc36ba92 | ||
![]() |
fe32db17d7 | ||
![]() |
772aa4f165 | ||
![]() |
38298e0cd8 | ||
![]() |
1213d979f8 | ||
![]() |
a9cb12b745 | ||
![]() |
380f73c112 | ||
![]() |
9f79d034b3 | ||
![]() |
4a745a399f | ||
![]() |
c340485dd5 | ||
![]() |
f8570dd79f | ||
![]() |
4a49f3cce8 | ||
![]() |
a1ae455c69 | ||
![]() |
7a1b56fe96 | ||
![]() |
508e522188 | ||
![]() |
b1b630a4cc | ||
![]() |
c60d374fc8 | ||
![]() |
de4fd4c059 | ||
![]() |
95d8b30864 | ||
![]() |
eb94f409d5 | ||
![]() |
93d91936b5 | ||
![]() |
2220383d83 | ||
![]() |
3231706628 | ||
![]() |
ca4e53859d | ||
![]() |
61120d2059 | ||
![]() |
cc1822810f | ||
![]() |
a21c6884f2 | ||
![]() |
2700eed08d | ||
![]() |
ec2badbedd | ||
![]() |
054a7557fa | ||
![]() |
977a4570d9 | ||
![]() |
6c2077eb7c | ||
![]() |
1d436b3c86 | ||
![]() |
f86b14bfc5 | ||
![]() |
ec5be91ff6 | ||
![]() |
a7a9490a0c | ||
![]() |
c0d6008781 | ||
![]() |
9f62824e98 | ||
![]() |
b824ba3299 | ||
![]() |
59c4f9a089 | ||
![]() |
c673528cff | ||
![]() |
321f01b95c | ||
![]() |
e88667e01c | ||
![]() |
fb96907b52 | ||
![]() |
09ece26200 | ||
![]() |
0c6d22fe47 | ||
![]() |
c563eb81a3 | ||
![]() |
e864a0dd05 | ||
![]() |
42a05bc904 | ||
![]() |
4722175049 | ||
![]() |
3a901098e9 | ||
![]() |
a66097129d | ||
![]() |
eed4e40ec6 | ||
![]() |
6de57b36c7 | ||
![]() |
1a0865da7a | ||
![]() |
a6ecf6c992 | ||
![]() |
cb100f2e5c | ||
![]() |
bfb7b0117f | ||
![]() |
f6a705c769 | ||
![]() |
0c01840a7e | ||
![]() |
b0b75c54de | ||
![]() |
3fc201d985 | ||
![]() |
5aa453ada3 | ||
![]() |
0009d53b3f | ||
![]() |
05f7a6d1ff | ||
![]() |
0256bbbbaf | ||
![]() |
bce608cdbc | ||
![]() |
38a0844cdf | ||
![]() |
9acc6617d2 | ||
![]() |
4f72f49216 | ||
![]() |
af9840daf7 | ||
![]() |
a67a9c9980 | ||
![]() |
732b2acf35 | ||
![]() |
16906cdcbe | ||
![]() |
96e70659f0 | ||
![]() |
f2cacaf6b6 | ||
![]() |
24cde31328 | ||
![]() |
f6c0688684 | ||
![]() |
c176d94598 | ||
![]() |
f300ea62dc | ||
![]() |
c5df879cf9 | ||
![]() |
0762e5c289 | ||
![]() |
5d18559c1c | ||
![]() |
62c9751ac8 | ||
![]() |
7db9c7f24e | ||
![]() |
c834eb4590 | ||
![]() |
945ea51bd4 |
.clang-format
.github
.gitignore.travis.ymlAUTHORSNEWSandroid
doc
conf.pydeveloper.rstmeson.buildmpd.1mpd.1.rstmpd.conf.5mpd.conf.5.rstmpdconf.exampleplugins.rstprotocol.rstuser.rst
meson.buildmeson_options.txtpython/build
src
BulkEdit.hxxChrono.hxxCommandLine.cxxCommandLine.hxxGitVersion.cxxGitVersion.hxxIcyMetaDataParser.cxxIcyMetaDataParser.hxxIdle.cxxIdle.hxxIdleFlags.cxxIdleFlags.hxxInstance.cxxInstance.hxxListen.cxxListen.hxxLocateUri.cxxLocateUri.hxxLog.cxxLog.hxxLogBackend.cxxLogBackend.hxxLogInit.cxxLogInit.hxxLogLevel.hxxLogV.hxxMain.cxxMain.hxxMapper.cxxMapper.hxxMixRampInfo.hxxMusicBuffer.cxxMusicBuffer.hxxMusicChunk.cxxMusicChunk.hxxMusicChunkPtr.cxxMusicChunkPtr.hxxMusicPipe.cxxMusicPipe.hxxPartition.cxxPartition.hxxPermission.cxxPermission.hxxPlaylistDatabase.cxxPlaylistDatabase.hxxPlaylistError.cxxPlaylistError.hxxPlaylistFile.cxxPlaylistFile.hxxPlaylistPrint.cxxPlaylistPrint.hxxPlaylistSave.cxxPlaylistSave.hxxPluginUnavailable.hxxRemoteTagCache.cxxRemoteTagCache.hxxRemoteTagCacheHandler.hxxReplayGainConfig.hxxReplayGainGlobal.cxxReplayGainGlobal.hxxReplayGainInfo.cxxReplayGainInfo.hxxReplayGainMode.cxxReplayGainMode.hxxSingleMode.cxxSingleMode.hxxSongLoader.cxxSongLoader.hxxSongPrint.cxxSongPrint.hxxSongSave.cxxSongSave.hxxSongUpdate.cxxStateFile.cxxStateFile.hxxStateFileConfig.cxxStateFileConfig.hxxStats.cxxStats.hxxTagAny.cxxTagAny.hxxTagArchive.cxxTagArchive.hxxTagFile.cxxTagFile.hxxTagPrint.cxxTagPrint.hxxTagSave.cxxTagSave.hxxTagStream.cxxTagStream.hxxTimePrint.cxxTimePrint.hxxls.cxxls.hxx
android
apple
archive
ArchiveFile.hxxArchiveList.cxxArchiveList.hxxArchiveLookup.cxxArchivePlugin.cxxArchivePlugin.hxxArchiveVisitor.hxxmeson.build
plugins
client
BackgroundCommand.hxxClient.cxxClient.hxxConfig.cxxConfig.hxxDomain.cxxDomain.hxxEvent.cxxExpire.cxxFile.cxxIdle.cxxList.cxxList.hxxListener.cxxListener.hxxMessage.cxxMessage.hxxNew.cxxProcess.cxxRead.cxxResponse.cxxResponse.hxxSubscribe.cxxThreadBackgroundCommand.cxxThreadBackgroundCommand.hxxWrite.cxx
command
AllCommands.cxxAllCommands.hxxClientCommands.cxxClientCommands.hxxCommandError.cxxCommandError.hxxCommandListBuilder.cxxCommandListBuilder.hxxCommandResult.hxxDatabaseCommands.cxxDatabaseCommands.hxxFileCommands.cxxFileCommands.hxxFingerprintCommands.cxxFingerprintCommands.hxxMessageCommands.cxxMessageCommands.hxxNeighborCommands.cxxNeighborCommands.hxxOtherCommands.cxxOtherCommands.hxxOutputCommands.cxxOutputCommands.hxxPartitionCommands.cxxPartitionCommands.hxxPlayerCommands.cxxPlayerCommands.hxxPlaylistCommands.cxxPlaylistCommands.hxxQueueCommands.cxxQueueCommands.hxxRequest.hxxStickerCommands.cxxStickerCommands.hxxStorageCommands.cxxStorageCommands.hxxTagCommands.cxxTagCommands.hxx
config
Block.cxxBlock.hxxCheck.cxxCheck.hxxData.cxxData.hxxDefaults.hxxDomain.cxxDomain.hxxFile.cxxFile.hxxMigrate.cxxMigrate.hxxNet.cxxNet.hxxOption.hxxParam.cxxParam.hxxParser.cxxParser.hxxPath.cxxPath.hxxTemplates.cxxTemplates.hxxmeson.build
db
Configured.cxxConfigured.hxxCount.cxxCount.hxxDatabaseError.hxxDatabaseGlue.cxxDatabaseGlue.hxxDatabaseListener.hxxDatabaseLock.cxxDatabaseLock.hxxDatabasePlaylist.cxxDatabasePlaylist.hxxDatabasePlugin.hxxDatabasePrint.cxxDatabasePrint.hxxDatabaseQueue.cxxDatabaseQueue.hxxDatabaseSong.cxxDatabaseSong.hxxHelpers.cxxHelpers.hxxInterface.hxxLightDirectory.hxxPlaylistInfo.hxxPlaylistVector.cxxPlaylistVector.hxxPtr.hxxRegistry.cxxRegistry.hxxSelection.cxxSelection.hxxStats.hxxUniqueTags.cxxUniqueTags.hxxUri.hxxVHelper.cxxVHelper.hxxVisitor.hxxmeson.build
plugins
ProxyDatabasePlugin.cxxProxyDatabasePlugin.hxx
simple
DatabaseSave.cxxDatabaseSave.hxxDirectory.cxxDirectory.hxxDirectorySave.cxxDirectorySave.hxxMount.cxxMount.hxxPrefixedLightSong.hxxPtr.hxxSimpleDatabasePlugin.cxxSimpleDatabasePlugin.hxxSong.cxxSong.hxxSongSort.cxxSongSort.hxx
upnp
update
Archive.cxxConfig.cxxConfig.hxxContainer.cxxEditor.cxxEditor.hxxExcludeList.cxxExcludeList.hxxInotifyDomain.cxxInotifyDomain.hxxInotifyQueue.cxxInotifyQueue.hxxInotifySource.cxxInotifySource.hxxInotifyUpdate.cxxInotifyUpdate.hxxPlaylist.cxxQueue.cxxQueue.hxxRemove.cxxRemove.hxxService.cxxService.hxxUpdateDomain.cxxUpdateDomain.hxxUpdateIO.cxxUpdateIO.hxxUpdateSong.cxxVirtualDirectory.cxxWalk.cxxWalk.hxx
decoder
Bridge.cxxBridge.hxxClient.hxxCommand.hxxControl.cxxControl.hxxDecoderAPI.cxxDecoderAPI.hxxDecoderBuffer.cxxDecoderBuffer.hxxDecoderList.cxxDecoderList.hxxDecoderPlugin.cxxDecoderPlugin.hxxDecoderPrint.cxxDecoderPrint.hxxDomain.cxxDomain.hxxReader.cxxReader.hxxThread.cxxmeson.build
plugins
AdPlugDecoderPlugin.cxxAdPlugDecoderPlugin.hAudiofileDecoderPlugin.cxxAudiofileDecoderPlugin.hxxDsdLib.cxxDsdLib.hxxDsdiffDecoderPlugin.cxxDsdiffDecoderPlugin.hxxDsfDecoderPlugin.cxxDsfDecoderPlugin.hxxFaadDecoderPlugin.cxxFaadDecoderPlugin.hxxFfmpegDecoderPlugin.cxxFfmpegDecoderPlugin.hxxFfmpegIo.cxxFfmpegIo.hxxFfmpegMetaData.cxxFfmpegMetaData.hxxFlacCommon.cxxFlacCommon.hxxFlacDecoderPlugin.cxxFlacDecoderPlugin.hFlacDomain.cxxFlacDomain.hxxFlacInput.cxxFlacInput.hxxFlacPcm.cxxFlacPcm.hxxFlacStreamDecoder.hxxFluidsynthDecoderPlugin.cxxFluidsynthDecoderPlugin.hxxGmeDecoderPlugin.cxxGmeDecoderPlugin.hxxHybridDsdDecoderPlugin.cxxHybridDsdDecoderPlugin.hxxMadDecoderPlugin.cxxMadDecoderPlugin.hxxMikmodDecoderPlugin.cxxMikmodDecoderPlugin.hxxModplugDecoderPlugin.cxxModplugDecoderPlugin.hxxMpcdecDecoderPlugin.cxxMpcdecDecoderPlugin.hxxMpg123DecoderPlugin.cxxMpg123DecoderPlugin.hxxOggCodec.cxxOggCodec.hxxOggDecoder.cxxOggDecoder.hxxOpusDecoderPlugin.cxxOpusDecoderPlugin.hOpusDomain.cxxOpusDomain.hxxOpusHead.cxxOpusHead.hxxOpusReader.hxxOpusTags.cxxOpusTags.hxxPcmDecoderPlugin.cxxPcmDecoderPlugin.hxxSidplayDecoderPlugin.cxxSidplayDecoderPlugin.hxxSndfileDecoderPlugin.cxxSndfileDecoderPlugin.hxxVorbisDecoderPlugin.cxxVorbisDecoderPlugin.hVorbisDomain.cxxVorbisDomain.hxxWavpackDecoderPlugin.cxxWavpackDecoderPlugin.hxxWildmidiDecoderPlugin.cxxWildmidiDecoderPlugin.hxxmeson.build
encoder
Configured.cxxConfigured.hxxEncoderAPI.hxxEncoderInterface.hxxEncoderList.cxxEncoderList.hxxEncoderPlugin.hxxToOutputStream.cxxToOutputStream.hxxmeson.build
plugins
FlacEncoderPlugin.cxxFlacEncoderPlugin.hxxLameEncoderPlugin.cxxLameEncoderPlugin.hxxNullEncoderPlugin.cxxNullEncoderPlugin.hxxOggEncoder.hxxOpusEncoderPlugin.cxxOpusEncoderPlugin.hxxShineEncoderPlugin.cxxShineEncoderPlugin.hxxTwolameEncoderPlugin.cxxTwolameEncoderPlugin.hxxVorbisEncoderPlugin.cxxVorbisEncoderPlugin.hxxWaveEncoderPlugin.cxxWaveEncoderPlugin.hxxmeson.build
event
BufferedSocket.cxxBufferedSocket.hxxCall.cxxCall.hxxChrono.hxxDeferEvent.cxxDeferEvent.hxxFullyBufferedSocket.cxxFullyBufferedSocket.hxxIdleMonitor.cxxIdleMonitor.hxxLoop.cxxLoop.hxxMaskMonitor.cxxMaskMonitor.hxxMultiSocketMonitor.cxxMultiSocketMonitor.hxxPollGroup.hxxPollGroupEpoll.hxxPollGroupPoll.cxxPollGroupPoll.hxxPollGroupWinSelect.cxxPollGroupWinSelect.hxxPollResultGeneric.hxxServerSocket.cxxServerSocket.hxxSignalMonitor.cxxSignalMonitor.hxxSocketMonitor.cxxSocketMonitor.hxxThread.cxxThread.hxxTimerEvent.cxxTimerEvent.hxxUringManager.cxxUringManager.hxxWakeFD.hxxmeson.build
filter
Factory.cxxFactory.hxxFilter.cxxFilter.hxxFilterPlugin.hxxLoadChain.cxxLoadChain.hxxLoadOne.cxxLoadOne.hxxNullFilter.hxxObserver.cxxObserver.hxxPrepared.hxxRegistry.cxxRegistry.hxxmeson.build
plugins
AutoConvertFilterPlugin.cxxAutoConvertFilterPlugin.hxxChainFilterPlugin.cxxChainFilterPlugin.hxxConvertFilterPlugin.cxxConvertFilterPlugin.hxxFfmpegFilter.cxxFfmpegFilter.hxxFfmpegFilterPlugin.cxxFfmpegFilterPlugin.hxxHdcdFilterPlugin.cxxHdcdFilterPlugin.hxxNormalizeFilterPlugin.cxxNormalizeFilterPlugin.hxxNullFilterPlugin.cxxNullFilterPlugin.hxxReplayGainFilterPlugin.cxxReplayGainFilterPlugin.hxxRouteFilterPlugin.cxxRouteFilterPlugin.hxxVolumeFilterPlugin.cxxVolumeFilterPlugin.hxxmeson.build
fs
AllocatedPath.cxxAllocatedPath.hxxCharset.cxxCharset.hxxCheckFile.cxxCheckFile.hxxConfig.cxxConfig.hxxDirectoryReader.cxxDirectoryReader.hxxDomain.cxxDomain.hxxFeatures.hxxFileInfo.hxxFileSystem.cxxFileSystem.hxxGlob.hxxLimits.hxxList.cxxList.hxxLookupFile.cxxLookupFile.hxxNarrowPath.cxxNarrowPath.hxxPath.cxxPath.hxxPath2.cxxStandardDirectory.cxxStandardDirectory.hxxTraits.cxxTraits.hxxXDG.hxx
io
AutoGunzipReader.cxxAutoGunzipReader.hxxBufferedOutputStream.cxxBufferedOutputStream.hxxBufferedReader.cxxBufferedReader.hxxFileOutputStream.cxxFileOutputStream.hxxFileReader.cxxFileReader.hxxGunzipReader.cxxGunzipReader.hxxGzipOutputStream.hxxOutputStream.hxxPeekReader.cxxPeekReader.hxxReader.hxxTextFile.cxxTextFile.hxx
meson.buildinput
AsyncInputStream.cxxAsyncInputStream.hxxBufferedInputStream.cxxBufferedInputStream.hxxBufferingInputStream.cxxBufferingInputStream.hxxCondHandler.hxxError.cxxError.hxxFailingInputStream.hxxHandler.hxxIcyInputStream.cxxIcyInputStream.hxxInit.cxxInit.hxxInputPlugin.cxxInputPlugin.hxxInputStream.cxxInputStream.hxxLocalOpen.cxxLocalOpen.hxxMaybeBufferedInputStream.cxxMaybeBufferedInputStream.hxxOffset.hxxOpen.cxxProxyInputStream.cxxProxyInputStream.hxxPtr.hxxReader.cxxReader.hxxRegistry.cxxRegistry.hxxRemoteTagScanner.hxxRewindInputStream.cxxRewindInputStream.hxxScanTags.cxxScanTags.hxxTextInputStream.cxxTextInputStream.hxxThreadInputStream.cxxThreadInputStream.hxx
cache
meson.buildplugins
AlsaInputPlugin.cxxAlsaInputPlugin.hxxArchiveInputPlugin.cxxArchiveInputPlugin.hxxCdioParanoiaInputPlugin.cxxCdioParanoiaInputPlugin.hxxCurlInputPlugin.cxxCurlInputPlugin.hxxFfmpegInputPlugin.cxxFfmpegInputPlugin.hxxFileInputPlugin.cxxFileInputPlugin.hxxMmsInputPlugin.cxxMmsInputPlugin.hxxNfsInputPlugin.cxxNfsInputPlugin.hxxQobuzClient.cxxQobuzClient.hxxQobuzErrorParser.cxxQobuzErrorParser.hxxQobuzInputPlugin.cxxQobuzInputPlugin.hxxQobuzLoginRequest.cxxQobuzLoginRequest.hxxQobuzSession.hxxQobuzTagScanner.cxxQobuzTagScanner.hxxQobuzTrackRequest.cxxQobuzTrackRequest.hxxSmbclientInputPlugin.cxxSmbclientInputPlugin.hxxTidalError.hxxTidalErrorParser.cxxTidalErrorParser.hxxTidalInputPlugin.cxxTidalInputPlugin.hxxTidalLoginRequest.cxxTidalLoginRequest.hxxTidalSessionManager.cxxTidalSessionManager.hxxTidalTagScanner.cxxTidalTagScanner.hxxTidalTrackRequest.cxxTidalTrackRequest.hxxUringInputPlugin.cxxUringInputPlugin.hxxmeson.build
io
java
Class.hxxException.cxxException.hxxFile.cxxObject.cxxObject.hxxRef.hxxString.cxxString.hxxmeson.build
lib
alsa
AllowedFormat.cxxAllowedFormat.hxxFormat.hxxHwSetup.cxxHwSetup.hxxNonBlock.cxxNonBlock.hxxPeriodBuffer.hxxVersion.cxxVersion.hxx
chromaprint
crypto
curl
dbus
AppendIter.hxxAsyncRequest.hxxConnection.hxxError.hxxGlue.cxxGlue.hxxMessage.cxxMessage.hxxObjectManager.hxxTypes.hxxUDisks2.cxxUDisks2.hxxValues.hxxWatch.cxxWatch.hxx
expat
ffmpeg
Buffer.hxxCodec.hxxDomain.cxxDomain.hxxError.cxxError.hxxFilter.cxxFilter.hxxFormat.hxxFrame.hxxIOContext.hxxInit.cxxInit.hxxLogCallback.cxxLogCallback.hxxLogError.cxxLogError.hxxSampleFormat.hxxTime.hxxmeson.build
gcrypt
icu
CaseFold.cxxCaseFold.hxxCollate.cxxCollate.hxxCompare.cxxCompare.hxxConverter.cxxConverter.hxxInit.cxxInit.hxxUtil.cxxUtil.hxxWin32.cxxWin32.hxxmeson.build
nfs
Base.cxxBase.hxxBlocking.cxxBlocking.hxxCallback.hxxCancellable.hxxConnection.cxxConnection.hxxError.cxxFileReader.cxxFileReader.hxxGlue.cxxGlue.hxxLease.hxxManager.cxxManager.hxx
patches
pcre
pulse
smbclient
sqlite
systemd
upnp
Action.hxxCallback.hxxClientInit.cxxClientInit.hxxCompat.hxxContentDirectoryService.cxxContentDirectoryService.hxxDevice.cxxDevice.hxxDiscovery.cxxDiscovery.hxxInit.cxxInit.hxxUniqueIxml.hxxUtil.cxxUtil.hxxixmlwrap.cxxixmlwrap.hxxmeson.build
xiph
FlacAudioFormat.hxxFlacIOHandle.cxxFlacIOHandle.hxxFlacMetadataChain.cxxFlacMetadataChain.hxxFlacMetadataIterator.hxxFlacStreamMetadata.cxxFlacStreamMetadata.hxxOggFind.cxxOggFind.hxxOggPacket.cxxOggPacket.hxxOggPage.hxxOggSerial.cxxOggSerial.hxxOggStreamState.hxxOggSyncState.cxxOggSyncState.hxxOggVisitor.cxxOggVisitor.hxxScanVorbisComment.cxxScanVorbisComment.hxxVorbisComment.hxxVorbisComments.cxxVorbisComments.hxxVorbisPicture.cxxVorbisPicture.hxxXiphTags.cxxXiphTags.hxxmeson.build
yajl
mixer
Listener.hxxMixerAll.cxxMixerControl.cxxMixerControl.hxxMixerInternal.hxxMixerList.hxxMixerPlugin.hxxMixerType.cxxMixerType.hxxVolume.cxxVolume.hxx
plugins
neighbor
net
AddressInfo.cxxAddressInfo.hxxAllocatedSocketAddress.cxxAllocatedSocketAddress.hxxFeatures.hxxHostParser.cxxHostParser.hxxIPv4Address.cxxIPv4Address.hxxIPv6Address.cxxIPv6Address.hxxInit.hxxResolver.cxxResolver.hxxSocketAddress.cxxSocketAddress.hxxSocketDescriptor.cxxSocketDescriptor.hxxSocketError.cxxSocketError.hxxSocketUtil.cxxSocketUtil.hxxStaticSocketAddress.cxxStaticSocketAddress.hxxToString.cxxToString.hxxUniqueSocketDescriptor.hxx
open.houtput
Client.hxxControl.cxxControl.hxxDefaults.cxxDefaults.hxxDomain.cxxDomain.hxxError.hxxFiltered.cxxFiltered.hxxFinish.cxxInit.cxxInterface.cxxInterface.hxxMultipleOutputs.cxxMultipleOutputs.hxxOutputAPI.hxxOutputCommand.cxxOutputCommand.hxxOutputPlugin.cxxOutputPlugin.hxxPrint.cxxPrint.hxxRegistry.cxxRegistry.hxxSharedPipeConsumer.cxxSharedPipeConsumer.hxxSource.cxxSource.hxxState.cxxState.hxxThread.cxxTimer.cxxTimer.hxxmeson.build
plugins
AlsaOutputPlugin.cxxAlsaOutputPlugin.hxxAoOutputPlugin.cxxAoOutputPlugin.hxxFifoOutputPlugin.cxxFifoOutputPlugin.hxxHaikuOutputPlugin.cxxHaikuOutputPlugin.hxxJackOutputPlugin.cxxJackOutputPlugin.hxxNullOutputPlugin.cxxNullOutputPlugin.hxxOSXOutputPlugin.cxxOSXOutputPlugin.hxxOpenALOutputPlugin.cxxOpenALOutputPlugin.hxxOssOutputPlugin.cxxOssOutputPlugin.hxxPipeOutputPlugin.cxxPipeOutputPlugin.hxxPulseOutputPlugin.cxxPulseOutputPlugin.hxxRecorderOutputPlugin.cxxRecorderOutputPlugin.hxxShoutOutputPlugin.cxxShoutOutputPlugin.hxxSndioOutputPlugin.cxxSndioOutputPlugin.hxxSolarisOutputPlugin.cxxSolarisOutputPlugin.hxxWasapiOutputPlugin.cxxWasapiOutputPlugin.hxxWinmmOutputPlugin.cxxWinmmOutputPlugin.hxx
httpd
HttpdClient.cxxHttpdClient.hxxHttpdInternal.hxxHttpdOutputPlugin.cxxHttpdOutputPlugin.hxxIcyMetaDataServer.cxxIcyMetaDataServer.hxxPage.cxxPage.hxx
meson.buildsles
pcm
AudioFormat.cxxAudioFormat.hxxAudioParser.cxxAudioParser.hxxBuffer.cxxBuffer.hxxChannelDefs.hxxChannelsConverter.cxxChannelsConverter.hxxCheckAudioFormat.cxxCheckAudioFormat.hxxClamp.hxxConfiguredResampler.cxxConfiguredResampler.hxxConvert.cxxConvert.hxxDither.cxxDither.hxxDop.cxxDop.hxxDsd16.cxxDsd16.hxxDsd2Pcm.cxxDsd2Pcm.hxxDsd32.cxxDsd32.hxxExport.cxxExport.hxxFallbackResampler.cxxFallbackResampler.hxxFloatConvert.hxxFormatConverter.cxxFormatConverter.hxxGlueResampler.cxxGlueResampler.hxxInterleave.cxxInterleave.hxxLibsamplerateResampler.cxxLibsamplerateResampler.hxxMix.cxxMix.hxxNeon.hxxOrder.cxxOrder.hxxPack.cxxPack.hxxPcmChannels.cxxPcmChannels.hxxPcmDsd.cxxPcmDsd.hxxPcmFormat.cxxPcmFormat.hxxPrng.hxxResampler.hxxRestBuffer.hxxSampleFormat.cxxSampleFormat.hxxShiftConvert.hxxSilence.cxxSilence.hxxSoxrResampler.cxxSoxrResampler.hxxTraits.hxxVolume.cxxVolume.hxx
dsd2pcm
meson.buildplayer
playlist
MemorySongEnumerator.cxxMemorySongEnumerator.hxxPlaylistAny.cxxPlaylistAny.hxxPlaylistMapper.cxxPlaylistMapper.hxxPlaylistPlugin.cxxPlaylistPlugin.hxxPlaylistQueue.cxxPlaylistQueue.hxxPlaylistRegistry.cxxPlaylistRegistry.hxxPlaylistSong.cxxPlaylistSong.hxxPlaylistStream.cxxPlaylistStream.hxxPrint.cxxPrint.hxxSongEnumerator.hxx
cue
meson.buildplugins
AsxPlaylistPlugin.cxxAsxPlaylistPlugin.hxxCuePlaylistPlugin.cxxCuePlaylistPlugin.hxxEmbeddedCuePlaylistPlugin.cxxEmbeddedCuePlaylistPlugin.hxxExtM3uPlaylistPlugin.cxxExtM3uPlaylistPlugin.hxxFlacPlaylistPlugin.cxxFlacPlaylistPlugin.hxxM3uPlaylistPlugin.cxxM3uPlaylistPlugin.hxxPlsPlaylistPlugin.cxxPlsPlaylistPlugin.hxxRssPlaylistPlugin.cxxRssPlaylistPlugin.hxxSoundCloudPlaylistPlugin.cxxSoundCloudPlaylistPlugin.hxxXspfPlaylistPlugin.cxxXspfPlaylistPlugin.hxxmeson.build
protocol
queue
IdTable.hxxListener.hxxPlaylist.cxxPlaylist.hxxPlaylistControl.cxxPlaylistEdit.cxxPlaylistState.cxxPlaylistState.hxxPlaylistTag.cxxPlaylistUpdate.cxxQueue.cxxQueue.hxxQueuePrint.cxxQueuePrint.hxxQueueSave.cxxQueueSave.hxx
song
AndSongFilter.cxxAndSongFilter.hxxAudioFormatSongFilter.cxxAudioFormatSongFilter.hxxBaseSongFilter.cxxBaseSongFilter.hxxDetachedSong.cxxDetachedSong.hxxEscape.cxxEscape.hxxFilter.cxxFilter.hxxISongFilter.hxxLightSong.cxxLightSong.hxxModifiedSinceSongFilter.cxxModifiedSinceSongFilter.hxxNotSongFilter.hxxOptimizeFilter.cxxOptimizeFilter.hxxStringFilter.cxxStringFilter.hxxTagSongFilter.cxxTagSongFilter.hxxUriSongFilter.cxxUriSongFilter.hxx
sticker
Database.cxxDatabase.hxxMatch.hxxPrint.cxxPrint.hxxSongSticker.cxxSongSticker.hxxSticker.hxxStickerDatabase.cxxStickerDatabase.hxx
storage
CompositeStorage.cxxCompositeStorage.hxxConfigured.cxxConfigured.hxxFileInfo.hxxMemoryDirectoryReader.cxxMemoryDirectoryReader.hxxRegistry.cxxRegistry.hxxStorageInterface.cxxStorageInterface.hxxStoragePlugin.hxxStorageState.cxxStorageState.hxx
plugins
system
Clock.cxxClock.hxxEpollFD.hxxError.hxxEventFD.cxxEventFD.hxxEventPipe.cxxEventPipe.hxxFatalError.cxxFatalError.hxxKernelVersion.cxxKernelVersion.hxxPeriodClock.hxxSignalFD.cxxSignalFD.hxxmeson.build
tag
Aiff.cxxAiff.hxxApeLoader.cxxApeLoader.hxxApeReplayGain.cxxApeReplayGain.hxxApeTag.cxxApeTag.hxxBuilder.cxxBuilder.hxxChromaprint.hxxConfig.cxxConfig.hxxFallback.hxxFixString.cxxFixString.hxxFormat.cxxFormat.hxxGenParseName.cxxGeneric.cxxGeneric.hxxHandler.cxxHandler.hxxId3Load.cxxId3Load.hxxId3MusicBrainz.cxxId3MusicBrainz.hxxId3Picture.cxxId3Picture.hxxId3ReplayGain.cxxId3ReplayGain.hxxId3Scan.cxxId3Scan.hxxId3Unique.hxxItem.hxxMask.hxxMixRamp.cxxMixRamp.hxxNames.cParseName.cxxParseName.hxxPool.cxxPool.hxxReplayGain.cxxReplayGain.hxxRiff.cxxRiff.hxxRva2.cxxRva2.hxxSettings.cxxSettings.hxxTable.cxxTable.hxxTag.cxxTag.hxxType.hVisitFallback.hxxVorbisComment.cxxVorbisComment.hxxmeson.build
thread
Cond.hxxCriticalSection.hxxId.hxxMutex.hxxName.hxxPosixCond.hxxSafeSingleton.hxxSlack.hxxThread.cxxThread.hxxUtil.cxxWindowsCond.hxx
time
unix
util
ASCII.hxxAlloc.cxxAlloc.hxxAllocatedArray.hxxAllocatedString.hxxBindMethod.hxxBitReverse.cxxBitReverse.hxxByteOrder.hxxByteReverse.cxxByteReverse.hxxCast.hxxCharUtil.hxxCircularBuffer.hxxClamp.hxxCompiler.hConstBuffer.hxxDereferenceIterator.hxxDivideString.cxxDivideString.hxxDomain.hxxDynamicFifoBuffer.hxxException.cxxException.hxxForeignFifoBuffer.hxxFormatString.cxxFormatString.hxxGenerateArray.hxxHexFormat.hxxHugeAllocator.cxxHugeAllocator.hxxLazyRandomEngine.cxxLazyRandomEngine.hxxManual.hxxMath.hxxMimeType.cxxMimeType.hxxNumberParser.cxxNumberParser.hxxOffsetPointer.hxxOptionDef.hxxOptionParser.cxxOptionParser.hxxPeakBuffer.cxxPeakBuffer.hxxPrintException.hxxReusableArray.hxxRuntimeError.hxxSliceBuffer.hxxSparseBuffer.hxxSplitString.cxxSplitString.hxxStaticFifoBuffer.hxxStringAPI.hxxStringBuffer.hxxStringCompare.cxxStringCompare.hxxStringFormat.hxxStringPointer.hxxStringStrip.hxxStringUtil.cxxStringUtil.hxxStringView.hxxTemplateString.hxxTextFile.hxxTransformN.hxxTruncateString.hxxUTF8.cxxUTF8.hxxUriExtract.cxxUriExtract.hxxUriQueryParser.cxxUriQueryParser.hxxUriRelative.cxxUriRelative.hxxUriUtil.cxxUriUtil.hxxWCharUtil.hxxWStringAPI.hxxWStringCompare.cxxWStringCompare.hxxWritableBuffer.hxxbit_reverse.cformat.cformat.hmeson.build
win32
zeroconf
subprojects
systemd
test
ConfigGlue.hxxContainerScan.cxxDumpDatabase.cxxDumpDecoderClient.cxxDumpDecoderClient.hxxMakeTag.hxxNullMixerListener.hxxParseSongFilter.cxxReadApeTags.cxxRunChromaprint.cxxRunCurl.cxxShutdownHandler.cxxShutdownHandler.hxxTestAudioFormat.cxxTestCircularBuffer.cxxTestIcu.cxxTestLookupFile.cxxTestRewindInputStream.cxxTestSplitString.cxxTestTagSongFilter.cxxTestUriExtract.cxxTestUriQueryParser.cxxTestUriRelative.cxxTestUriUtil.cxxWriteFile.cxxdump_playlist.cxxdump_rva2.cxxdump_text_file.cxx
fuzzer
meson.buildread_conf.cxxread_mixer.cxxread_tags.cxxrun_avahi.cxxrun_convert.cxxrun_decoder.cxxrun_encoder.cxxrun_filter.cxxrun_gunzip.cxxrun_gzip.cxxrun_inotify.cxxrun_input.cxxrun_neighbor_explorer.cxxrun_normalize.cxxrun_output.cxxrun_resolver.cxxrun_storage.cxxsoftware_volume.cxxtest_archive.cxxtest_archive_iso9660.shtest_byte_reverse.cxxtest_icy_parser.cxxtest_pcm_channels.cxxtest_pcm_dither.cxxtest_pcm_export.cxxtest_pcm_format.cxxtest_pcm_interleave.cxxtest_pcm_mix.cxxtest_pcm_pack.cxxtest_pcm_util.hxxtest_pcm_volume.cxxtest_protocol.cxxtest_queue_priority.cxxtest_translate_song.cxxtest_vorbis_encoder.cxxvisit_archive.cxxwin32
17
.clang-format
Normal file
17
.clang-format
Normal file
@@ -0,0 +1,17 @@
|
||||
BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -8
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BraceWrapping:
|
||||
AfterFunction: true
|
||||
SplitEmptyFunction: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
ColumnLimit: 90
|
||||
ConstructorInitializerIndentWidth: 0
|
||||
ContinuationIndentWidth: 8
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 8
|
||||
Standard: c++17
|
||||
TabWidth: 8
|
||||
UseTab: Always
|
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: MaxK
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
22
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a bug report
|
||||
---
|
||||
|
||||
<!-- See https://www.musicpd.org/help/ -->
|
||||
## Bug report
|
||||
### Describe the bug
|
||||
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
|
||||
## Actual Behavior
|
||||
|
||||
|
||||
## Version
|
||||
<!-- Paste the output of "mpd --version" here -->
|
||||
|
||||
|
||||
## Log
|
||||
<!-- Paste relevant portions of the log file here (--verbose) -->
|
6
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
6
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Create a feature request
|
||||
---
|
||||
|
||||
## Feature request
|
9
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
9
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask a question about MPD
|
||||
---
|
||||
|
||||
<!-- Before you ask a question on GitHub, please read MPD's
|
||||
documentation. A copy is available at
|
||||
https://www.musicpd.org/doc/html/ -->
|
||||
## Question
|
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,3 +6,6 @@
|
||||
/output/
|
||||
|
||||
__pycache__/
|
||||
|
||||
/.clangd/
|
||||
/compile_commands.json
|
||||
|
31
.travis.yml
31
.travis.yml
@@ -67,32 +67,6 @@ jobs:
|
||||
env:
|
||||
- MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH"
|
||||
|
||||
# Ubuntu Trusty (16.04) with GCC 6
|
||||
- os: linux
|
||||
dist: trusty
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'ppa:mhier/libboost-latest'
|
||||
- sourceline: 'ppa:mstipicevic/ninja-build-1-7-2'
|
||||
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
||||
packages:
|
||||
- g++-6
|
||||
- libgtest-dev
|
||||
- boost1.67
|
||||
- python3.6
|
||||
- python3-urllib3
|
||||
- ninja-build
|
||||
before_install:
|
||||
- wget https://bootstrap.pypa.io/get-pip.py
|
||||
- /usr/bin/python3.6 get-pip.py --user --no-cache-dir
|
||||
install:
|
||||
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir
|
||||
env:
|
||||
# use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068
|
||||
- MATRIX_EVAL="export CC='ccache gcc-6' CXX='ccache g++-6' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
|
||||
|
||||
# Ubuntu Trusty (16.04) with GCC 8
|
||||
- os: linux
|
||||
dist: trusty
|
||||
@@ -120,7 +94,7 @@ jobs:
|
||||
- MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
|
||||
|
||||
- os: osx
|
||||
osx_image: xcode9.4
|
||||
osx_image: xcode10.3
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
@@ -135,7 +109,8 @@ jobs:
|
||||
- chromaprint
|
||||
- libsamplerate
|
||||
- libsoxr
|
||||
- libzzip
|
||||
# libzzip appears to be broken on Homebrew: "ld: library not found for -lzzip"
|
||||
#- libzzip
|
||||
- flac
|
||||
- opus
|
||||
- libvorbis
|
||||
|
2
AUTHORS
2
AUTHORS
@@ -1,5 +1,5 @@
|
||||
Music Player Daemon - http://www.musicpd.org
|
||||
Copyright 2003-2018 The Music Player Daemon Project
|
||||
Copyright 2003-2020 The Music Player Daemon Project
|
||||
|
||||
The following people have contributed code to MPD:
|
||||
|
||||
|
118
NEWS
118
NEWS
@@ -1,3 +1,121 @@
|
||||
ver 0.22.1 (2020/10/17)
|
||||
* decoder
|
||||
- opus: apply the OpusHead output gain even if there is no EBU R128 tag
|
||||
- opus: fix track/album ReplayGain fallback
|
||||
* output
|
||||
- alsa: don't deadlock when the ALSA driver is buggy
|
||||
- jack, pulse: reduce the delay when stopping or pausing playback
|
||||
* playlist
|
||||
- cue: fix two crash bugs
|
||||
* state_file: fix the state_file_interval setting
|
||||
|
||||
ver 0.22 (2020/09/23)
|
||||
* protocol
|
||||
- "findadd"/"searchadd"/"searchaddpl" support the "sort" and
|
||||
"window" parameters
|
||||
- add command "readpicture" to download embedded pictures
|
||||
- command "moveoutput" moves an output between partitions
|
||||
- command "delpartition" deletes a partition
|
||||
- show partition name in "status" response
|
||||
* tags
|
||||
- new tags "Grouping" (for ID3 "TIT1"), "Work" and "Conductor"
|
||||
* input
|
||||
- curl: support "charset" parameter in URI fragment
|
||||
- ffmpeg: allow partial reads
|
||||
- io_uring: new plugin for local files on Linux (using liburing)
|
||||
- smbclient: close unused SMB/CIFS connections
|
||||
* database
|
||||
- upnp: drop support for libupnp versions older than 1.8
|
||||
* playlist
|
||||
- cue: integrate contents in database
|
||||
* decoder
|
||||
- ffmpeg: support RTSP
|
||||
- mad: remove option "gapless", always do gapless
|
||||
- sidplay: add option "default_genre"
|
||||
- sidplay: map SID name field to "Album" tag
|
||||
- sidplay: add support for new song length format with libsidplayfp 2.0
|
||||
- vorbis, opus: improve seeking accuracy
|
||||
* playlist
|
||||
- flac: support reading CUE sheets from remote FLAC files
|
||||
* filter
|
||||
- ffmpeg: new plugin based on FFmpeg's libavfilter library
|
||||
- hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback
|
||||
- volume: convert S16 to S24 to preserve quality and reduce dithering noise
|
||||
- dsd: add integer-only DSD to PCM converter
|
||||
* output
|
||||
- jack: add option "auto_destination_ports"
|
||||
- jack: report error details
|
||||
- pulse: add option "media_role"
|
||||
- solaris: support S8 and S32
|
||||
* lower the real-time priority from 50 to 40
|
||||
* switch to C++17
|
||||
- GCC 8 or clang 5 (or newer) recommended
|
||||
|
||||
ver 0.21.26 (2020/09/21)
|
||||
* database
|
||||
- inotify: obey ".mpdignore" files
|
||||
* output
|
||||
- osx: fix crash bug
|
||||
- sles: support floating point samples
|
||||
* archive
|
||||
- bzip2: fix crash on corrupt bzip2 file
|
||||
- bzip2: flush output at end of input file
|
||||
- iso9660: fix unaligned reads
|
||||
- iso9660: support seeking
|
||||
- zzip: fix crash on corrupt ZIP file
|
||||
* decoder
|
||||
- ffmpeg: remove "rtsp://" from the list of supported protocols
|
||||
- ffmpeg: add "hls+http://" to the list of supported protocols
|
||||
- opus: support the gain value from the Opus header
|
||||
- sndfile: fix lost samples at end of file
|
||||
* fix "single" mode bug after resuming playback
|
||||
* the default log_level is "default", not "info"
|
||||
|
||||
ver 0.21.25 (2020/07/06)
|
||||
* protocol:
|
||||
- fix crash when using "rangeid" while playing
|
||||
* database
|
||||
- simple: automatically scan new mounts
|
||||
- upnp: fix compatibility with Plex DLNA
|
||||
* storage
|
||||
- fix disappearing mounts after mounting twice
|
||||
- udisks: fix reading ".mpdignore"
|
||||
* input
|
||||
- file: detect premature end of file
|
||||
- smbclient: don't send credentials to MPD clients
|
||||
* decoder
|
||||
- opus: apply pre-skip and end trimming
|
||||
- opus: fix memory leak
|
||||
- opus: fix crash bug
|
||||
- vorbis: fix crash bug
|
||||
* output
|
||||
- osx: improve sample rate selection
|
||||
- osx: fix noise while stopping
|
||||
* neighbor
|
||||
- upnp: fix crash during shutdown
|
||||
* Windows/Android:
|
||||
- fix Boost detection after breaking change in Meson 0.54
|
||||
|
||||
ver 0.21.24 (2020/06/10)
|
||||
* protocol
|
||||
- "tagtypes" requires no permissions
|
||||
* database
|
||||
- simple: fix crash when mounting twice
|
||||
* decoder
|
||||
- modplug: fix Windows build failure
|
||||
- wildmidi: attempt to detect WildMidi using pkg-config
|
||||
- wildmidi: fix Windows build failure
|
||||
* player
|
||||
- don't restart current song if seeking beyond end
|
||||
* Android
|
||||
- enable the decoder plugins GME, ModPlug and WildMidi
|
||||
- fix build failure with Android NDK r21
|
||||
* Windows
|
||||
- fix stream playback
|
||||
- enable the decoder plugins GME, ModPlug and WildMidi
|
||||
- work around Meson bug breaking the Windows build with GCC 10
|
||||
* fix unit test failure
|
||||
|
||||
ver 0.21.23 (2020/04/23)
|
||||
* protocol
|
||||
- add tag fallback for AlbumSort
|
||||
|
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="46"
|
||||
android:versionName="0.21.23">
|
||||
android:versionCode="51"
|
||||
android:versionName="0.22.1">
|
||||
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
||||
|
||||
|
@@ -26,7 +26,7 @@ android_abis = {
|
||||
'ndk_arch': 'arm',
|
||||
'toolchain_arch': 'arm-linux-androideabi',
|
||||
'llvm_triple': 'armv7-linux-androideabi',
|
||||
'cflags': '-march=armv7-a -mfpu=vfp -mfloat-abi=softfp',
|
||||
'cflags': '-fpic -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=softfp',
|
||||
},
|
||||
|
||||
'arm64-v8a': {
|
||||
@@ -34,7 +34,7 @@ android_abis = {
|
||||
'ndk_arch': 'arm64',
|
||||
'toolchain_arch': 'aarch64-linux-android',
|
||||
'llvm_triple': 'aarch64-linux-android',
|
||||
'cflags': '',
|
||||
'cflags': '-fpic',
|
||||
},
|
||||
|
||||
'x86': {
|
||||
@@ -42,7 +42,7 @@ android_abis = {
|
||||
'ndk_arch': 'x86',
|
||||
'toolchain_arch': 'x86',
|
||||
'llvm_triple': 'i686-linux-android',
|
||||
'cflags': '-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
|
||||
'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
|
||||
},
|
||||
|
||||
'x86_64': {
|
||||
@@ -50,7 +50,7 @@ android_abis = {
|
||||
'ndk_arch': 'x86_64',
|
||||
'toolchain_arch': 'x86_64',
|
||||
'llvm_triple': 'x86_64-linux-android',
|
||||
'cflags': '-m64',
|
||||
'cflags': '-fPIC -m64',
|
||||
},
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ class AndroidNdkToolchain:
|
||||
llvm_triple = abi_info['llvm_triple'] + android_api_level
|
||||
|
||||
common_flags = '-Os -g'
|
||||
common_flags += ' -fPIC'
|
||||
common_flags += ' ' + abi_info['cflags']
|
||||
|
||||
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||
@@ -169,6 +168,9 @@ thirdparty_libs = [
|
||||
opus,
|
||||
flac,
|
||||
libid3tag,
|
||||
libmodplug,
|
||||
wildmidi,
|
||||
gme,
|
||||
ffmpeg,
|
||||
curl,
|
||||
libexpat,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -30,7 +30,7 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Music Player Daemon'
|
||||
copyright = '2003-2018 The Music Player Daemon Project'
|
||||
copyright = '2003-2020 The Music Player Daemon Project'
|
||||
author = 'Max Kellermann'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -38,7 +38,7 @@ author = 'Max Kellermann'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.21.23'
|
||||
version = '0.22.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version
|
||||
|
||||
@@ -212,3 +212,7 @@ html_static_path = ['_static']
|
||||
# implements a search results scorer. If empty, the default will be used.
|
||||
#
|
||||
# html_search_scorer = 'scorer.js'
|
||||
man_pages = [
|
||||
('mpd.1', 'mpd', 'MPD documentation', [author], 1),
|
||||
('mpd.conf.5', 'mpd.conf', 'mpd.conf documentation', [author], 5)
|
||||
]
|
||||
|
@@ -12,8 +12,7 @@ Code Style
|
||||
* indent with tabs (width 8)
|
||||
* don't write CPP when you can write C++: use inline functions and constexpr instead of macros
|
||||
* comment your code, document your APIs
|
||||
* the code should be C++14 compliant, and must compile with :program:`GCC` 6.0 and :program:`clang` 3.4
|
||||
* report error conditions with C++ exceptions, preferable derived from :envvar:`std::runtime_error`
|
||||
* the code should be C++17 compliant, and must compile with :program:`GCC` 8 and :program:`clang` 5
|
||||
* all code must be exception-safe
|
||||
* classes and functions names use CamelCase; variables are lower-case with words separated by underscore
|
||||
|
||||
@@ -31,6 +30,56 @@ Some example code:
|
||||
return xyz;
|
||||
}
|
||||
|
||||
|
||||
Error handling
|
||||
==============
|
||||
|
||||
If an error occurs, throw a C++ exception, preferably derived from
|
||||
:code:`std::runtime_error`. The function's API documentation should
|
||||
mention that. If a function cannot throw exceptions, add
|
||||
:code:`noexcept` to its prototype.
|
||||
|
||||
Some parts of MPD use callbacks to report completion; the handler
|
||||
classes usually have an "error" callback which receives a
|
||||
:code:`std::exception_ptr`
|
||||
(e.g. :code:`BufferedSocket::OnSocketError()`). Wrapping errors in
|
||||
:code:`std::exception_ptr` allows propagating details about the error
|
||||
across thread boundaries to the entity which is interested in handling
|
||||
it (e.g. giving the MPD client details about an I/O error caught by
|
||||
the decoder thread).
|
||||
|
||||
Out-of-memory errors (i.e. :code:`std::bad_alloc`) do not need to be
|
||||
handled. Some operating systems such as Linux do not report
|
||||
out-of-memory to userspace, and instead kill a process to recover.
|
||||
Even if we know we are out of memory, there is little we can do except
|
||||
for aborting the process quickly. Any other attempts to give back
|
||||
memory may cause page faults on the way which make the situation
|
||||
worse.
|
||||
|
||||
Error conditions which are caused by a bug do not need to be handled
|
||||
at runtime; instead, use :code:`assert()` to detect them in debug
|
||||
builds.
|
||||
|
||||
|
||||
git Branches
|
||||
************
|
||||
|
||||
There are two active branches in the git repository:
|
||||
|
||||
- the "unstable" branch called ``master`` where new features are
|
||||
merged. This will become the next major release eventually.
|
||||
- the "stable" branch (currently called ``v0.21.x``) where only bug
|
||||
fixes are merged.
|
||||
|
||||
Once :program:`MPD` 0.22 is released, a new branch called ``v0.22.x``
|
||||
will be created for 0.22 bug-fix releases; after that, ``v0.21.x``
|
||||
will eventually cease to be maintained.
|
||||
|
||||
After bug fixes have been added to the "stable" branch, it will be
|
||||
merged into ``master``. This ensures that all known bugs are fixed in
|
||||
all active branches.
|
||||
|
||||
|
||||
Hacking The Source
|
||||
******************
|
||||
|
||||
|
@@ -1,33 +1,51 @@
|
||||
install_man(['mpd.1', 'mpd.conf.5'])
|
||||
if not get_option('html_manual') and not get_option('manpages')
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
sphinx = find_program('sphinx-build')
|
||||
sphinx_output = custom_target(
|
||||
'HTML documentation',
|
||||
output: 'html',
|
||||
input: [
|
||||
'index.rst', 'user.rst', 'developer.rst',
|
||||
'plugins.rst',
|
||||
'protocol.rst',
|
||||
'conf.py',
|
||||
],
|
||||
command: [sphinx, '-q', '-b', 'html', '-d', '@OUTDIR@/doctrees', meson.current_source_dir(), '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()),
|
||||
)
|
||||
sphinx = find_program('sphinx-build', required: get_option('documentation'))
|
||||
if not sphinx.found()
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
custom_target(
|
||||
'upload',
|
||||
input: sphinx_output,
|
||||
output: 'upload',
|
||||
build_always_stale: true,
|
||||
command: [
|
||||
'rsync', '-vpruz', '--delete', meson.current_build_dir() + '/',
|
||||
'www.musicpd.org:/var/www/mpd/doc/',
|
||||
'--chmod=Dug+rwx,Do+rx,Fug+rw,Fo+r',
|
||||
'--include=html', '--include=html/**',
|
||||
'--exclude=*',
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
if get_option('html_manual')
|
||||
sphinx_output = custom_target(
|
||||
'HTML documentation',
|
||||
output: 'html',
|
||||
input: [
|
||||
'index.rst', 'user.rst', 'developer.rst',
|
||||
'plugins.rst',
|
||||
'protocol.rst',
|
||||
'conf.py',
|
||||
],
|
||||
command: [sphinx, '-q', '-b', 'html', '-d', '@OUTDIR@/doctrees', meson.current_source_dir(), '@OUTPUT@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()),
|
||||
)
|
||||
|
||||
custom_target(
|
||||
'upload',
|
||||
input: sphinx_output,
|
||||
output: 'upload',
|
||||
build_always_stale: true,
|
||||
command: [
|
||||
'rsync', '-vpruz', '--delete', meson.current_build_dir() + '/',
|
||||
'www.musicpd.org:/var/www/mpd/doc/',
|
||||
'--chmod=Dug+rwx,Do+rx,Fug+rw,Fo+r',
|
||||
'--include=html', '--include=html/**',
|
||||
'--exclude=*',
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('manpages')
|
||||
custom_target(
|
||||
'Manpage documentation',
|
||||
output: ['mpd.1', 'mpd.conf.5'],
|
||||
input: ['mpd.1.rst', 'conf.py'],
|
||||
command: [sphinx, '-q', '-b', 'man', '-d', '@OUTDIR@/man_doctrees', meson.current_source_dir(), '@OUTDIR@'],
|
||||
build_by_default: true,
|
||||
install: true,
|
||||
install_dir: [join_paths(get_option('mandir'), 'man1'), join_paths(get_option('mandir'), 'man5')],
|
||||
)
|
||||
endif
|
||||
|
55
doc/mpd.1
55
doc/mpd.1
@@ -1,55 +0,0 @@
|
||||
.TH "Music Player Daemon" 1
|
||||
.SH NAME
|
||||
MPD \- A daemon for playing music
|
||||
.SH SYNOPSIS
|
||||
.B mpd
|
||||
.RI [ options ]
|
||||
.RI [ CONF_FILE ]
|
||||
.SH DESCRIPTION
|
||||
MPD is a daemon for playing music. Music is played through the configured
|
||||
audio output(s) (which are generally local, but can be remote). 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.
|
||||
|
||||
MPD searches for a config file in \fB$XDG_CONFIG_HOME/mpd/mpd.conf\fP then
|
||||
\fB~/.mpdconf\fP then \fB/etc/mpd.conf\fP or uses CONF_FILE.
|
||||
|
||||
Read more about MPD at <\fBhttp://www.musicpd.org/\fP>.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BI \-\-help
|
||||
Output a brief help message.
|
||||
.TP
|
||||
.BI \-\-kill
|
||||
Kill the currently running mpd session. The pid_file parameter must be
|
||||
specified in the config file for this to work.
|
||||
.TP
|
||||
.BI \-\-no\-daemon
|
||||
Don't detach from console.
|
||||
.TP
|
||||
.BI \-\-stderr
|
||||
Print messages stderr.
|
||||
.TP
|
||||
.BI \-\-verbose
|
||||
Verbose logging.
|
||||
.TP
|
||||
.BI \-\-version
|
||||
Print version information.
|
||||
.SH FILES
|
||||
.TP
|
||||
.BI ~/.mpdconf
|
||||
User configuration file.
|
||||
.TP
|
||||
.BI /etc/mpd.conf
|
||||
Global configuration file.
|
||||
.SH SEE ALSO
|
||||
mpd.conf(5), mpc(1)
|
||||
.SH BUGS
|
||||
If you find a bug, please report it at
|
||||
.br
|
||||
<\fBhttps://github.com/MusicPlayerDaemon/MPD/issues/\fP>.
|
||||
.SH AUTHORS
|
||||
Max Kellermann <max.kellermann@gmail.com>
|
||||
|
||||
Special thanks to all the people that provided feedback and patches.
|
69
doc/mpd.1.rst
Normal file
69
doc/mpd.1.rst
Normal file
@@ -0,0 +1,69 @@
|
||||
===
|
||||
mpd
|
||||
===
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
||||
``mpd`` [options] [CONF_FILE]
|
||||
|
||||
DESCRIPTION
|
||||
------------
|
||||
|
||||
MPD is a daemon for playing music. Music is played through the configured audio output(s) (which are generally local, but can be remote). 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.
|
||||
|
||||
MPD searches for a config file in ``$XDG_CONFIG_HOME/mpd/mpd.conf``
|
||||
then ``~/.mpdconf`` then ``/etc/mpd.conf`` or uses ``CONF_FILE``.
|
||||
|
||||
Read more about MPD at http://www.musicpd.org/
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
|
||||
.. program:: mpd
|
||||
|
||||
.. option:: --help
|
||||
|
||||
Output a brief help message.
|
||||
|
||||
.. option:: --kill
|
||||
|
||||
Kill the currently running mpd session. The pid_file parameter must be specified in the config file for this to work.
|
||||
|
||||
.. option:: --no-config
|
||||
|
||||
Don't read from the configuration file.
|
||||
|
||||
.. option:: --no-daemon
|
||||
|
||||
Don't detach from console.
|
||||
|
||||
.. option:: --stderr
|
||||
|
||||
Print messages to stderr.
|
||||
|
||||
.. option:: --verbose
|
||||
|
||||
Verbose logging.
|
||||
|
||||
.. option:: --version
|
||||
|
||||
Print version information.
|
||||
|
||||
FILES
|
||||
-----
|
||||
|
||||
:file:`~/.mpdconf`
|
||||
User configuration file.
|
||||
|
||||
:file:`/etc/mpd.conf`
|
||||
Global configuration file.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
:manpage:`mpd.conf(5)`, :manpage:`mpc(1)`
|
||||
|
||||
BUGS
|
||||
----
|
||||
If you find a bug, please report it at https://github.com/MusicPlayerDaemon/MPD/issues/
|
180
doc/mpd.conf.5
180
doc/mpd.conf.5
@@ -1,180 +0,0 @@
|
||||
.TH mpd.conf 5
|
||||
.SH NAME
|
||||
mpd.conf \- Music Player Daemon configuration file
|
||||
.SH DESCRIPTION
|
||||
\fBmpd.conf\fP is the configuration file for mpd(1). If not specified on the
|
||||
command line, MPD first searches for it at \fB$XDG_CONFIG_HOME/mpd/mpd.conf\fP
|
||||
then at \fB~/.mpdconf\fP then at \fB~/.mpd/mpd.conf\fP and then in
|
||||
\fB/etc/mpd.conf\fP.
|
||||
|
||||
Lines beginning with a "#" character are comments. All other non-empty lines
|
||||
specify parameters and their values. These lines contain the parameter name
|
||||
and parameter value (surrounded by double quotes) separated by whitespace
|
||||
(either tabs or spaces). For example:
|
||||
|
||||
parameter "value"
|
||||
|
||||
The exception to this rule is the audio_output parameter, which is of the form:
|
||||
|
||||
audio_output {
|
||||
.br
|
||||
parameter1 "value"
|
||||
parameter2 "value"
|
||||
.br
|
||||
}
|
||||
|
||||
Parameters that take a file or directory as an argument should use absolute
|
||||
paths.
|
||||
|
||||
See \fBdocs/mpdconf.example\fP in the source tarball for an example
|
||||
configuration file.
|
||||
|
||||
This manual is not complete, it lists only the most important options.
|
||||
Please read the MPD user manual for a complete configuration guide:
|
||||
<\fBhttp://www.musicpd.org/doc/user/\fP>
|
||||
.SH REQUIRED PARAMETERS
|
||||
.TP
|
||||
.B db_file <file>
|
||||
This specifies where the db file will be stored.
|
||||
.TP
|
||||
.B log_file <file>
|
||||
This specifies where the log file should be located.
|
||||
The special value "syslog" makes MPD use the local syslog daemon.
|
||||
.SH OPTIONAL PARAMETERS
|
||||
.TP
|
||||
.B sticker_file <file>
|
||||
The location of the sticker database. This is a database which
|
||||
manages dynamic information attached to songs.
|
||||
.TP
|
||||
.B pid_file <file>
|
||||
This specifies the file to save mpd's process ID in.
|
||||
.TP
|
||||
.B music_directory <directory>
|
||||
This specifies the directory where music is located.
|
||||
If you do not configure this, you can only play streams.
|
||||
.TP
|
||||
.B playlist_directory <directory>
|
||||
This specifies the directory where saved playlists are stored.
|
||||
If you do not configure this, you cannot save playlists.
|
||||
.TP
|
||||
.B state_file <file>
|
||||
This specifies if a state file is used and where it is located. The state of
|
||||
mpd will be saved to this file when mpd is terminated by a TERM signal or by
|
||||
the "kill" command. When mpd is restarted, it will read the state file and
|
||||
restore the state of mpd (including the playlist).
|
||||
.TP
|
||||
.B restore_paused <yes or no>
|
||||
Put MPD into pause mode instead of starting playback after startup.
|
||||
.TP
|
||||
.B user <username>
|
||||
This specifies the user that MPD will run as, if set. MPD should
|
||||
never run as root, and you may use this option to make MPD change its
|
||||
user id after initialization. Do not use this option if you start MPD
|
||||
as an unprivileged user.
|
||||
.TP
|
||||
.B port <port>
|
||||
This specifies the port that mpd listens on. The default is 6600.
|
||||
.TP
|
||||
.B log_level <default, secure, or verbose>
|
||||
This specifies how verbose logs are. "default" is minimal logging, "secure"
|
||||
reports from what address a connection is opened, and when it is closed, and
|
||||
"verbose" records excessive amounts of information for debugging purposes. The
|
||||
default is "default".
|
||||
.TP
|
||||
.B follow_outside_symlinks <yes or no>
|
||||
Control if MPD will follow symbolic links pointing outside the music dir.
|
||||
You must recreate the database after changing this option.
|
||||
The default is "yes".
|
||||
.TP
|
||||
.B follow_inside_symlinks <yes or no>
|
||||
Control if MPD will follow symbolic links pointing inside the music dir,
|
||||
potentially adding duplicates to the database.
|
||||
You must recreate the database after changing this option.
|
||||
The default is "yes".
|
||||
.TP
|
||||
.B zeroconf_enabled <yes or no>
|
||||
If yes, and MPD has been compiled with support for Avahi or Bonjour, service
|
||||
information will be published with Zeroconf. The default is yes.
|
||||
.TP
|
||||
.B zeroconf_name <name>
|
||||
If Zeroconf is enabled, this is the service name to publish. This name should
|
||||
be unique to your local network, but name collisions will be properly dealt
|
||||
with. The default is "Music Player @ %h", where %h will be replaced with the
|
||||
hostname of the machine running MPD.
|
||||
.TP
|
||||
.B audio_output
|
||||
See \fBDESCRIPTION\fP and the various \fBAUDIO OUTPUT PARAMETERS\fP sections
|
||||
for the format of this parameter. Multiple audio_output sections may be
|
||||
specified. If no audio_output section is specified, then MPD will scan for a
|
||||
usable audio output.
|
||||
.TP
|
||||
.B replaygain <off or album or track or auto>
|
||||
If specified, mpd will adjust the volume of songs played using ReplayGain tags
|
||||
(see <\fBhttp://www.replaygain.org/\fP>). Setting this to "album" will adjust
|
||||
volume using the album's ReplayGain tags, while setting it to "track" will
|
||||
adjust it using the track ReplayGain tags. "auto" uses the track ReplayGain
|
||||
tags if random play is activated otherwise the album ReplayGain tags. Currently
|
||||
only FLAC, Ogg Vorbis, Musepack, and MP3 (through ID3v2 ReplayGain tags, not
|
||||
APEv2) are supported.
|
||||
.TP
|
||||
.B replaygain_preamp <\-15 to 15>
|
||||
This is the gain (in dB) applied to songs with ReplayGain tags.
|
||||
.TP
|
||||
.B volume_normalization <yes or no>
|
||||
If yes, mpd will normalize the volume of songs as they play. The default is no.
|
||||
.TP
|
||||
.B filesystem_charset <charset>
|
||||
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 save_absolute_paths_in_playlists <yes or no>
|
||||
This specifies whether relative or absolute paths for song filenames are used
|
||||
when saving playlists. The default is "no".
|
||||
.TP
|
||||
.B auto_update <yes or no>
|
||||
This specifies the whether to support automatic update of music database when
|
||||
files are changed in music_directory. The default is to disable autoupdate
|
||||
of database.
|
||||
.TP
|
||||
.B auto_update_depth <N>
|
||||
Limit the depth of the directories being watched, 0 means only watch
|
||||
the music directory itself. There is no limit by default.
|
||||
.SH REQUIRED AUDIO OUTPUT PARAMETERS
|
||||
.TP
|
||||
.B type <type>
|
||||
This specifies the audio output type. See the list of supported outputs in mpd
|
||||
\-\-version for possible values.
|
||||
.TP
|
||||
.B name <name>
|
||||
This specifies a unique name for the audio output.
|
||||
.SH OPTIONAL AUDIO OUTPUT PARAMETERS
|
||||
.TP
|
||||
.B format <sample_rate:bits:channels>
|
||||
This specifies the sample rate, bits per sample, and number of channels of
|
||||
audio that is sent to the audio output device. See documentation for the
|
||||
\fBaudio_output_format\fP parameter for more details. The default is to use
|
||||
whatever audio format is passed to the audio output.
|
||||
Any of the three attributes may be an asterisk to specify that this
|
||||
attribute should not be enforced
|
||||
.TP
|
||||
.B replay_gain_handler <software, mixer or none>
|
||||
Specifies how replay gain is applied. The default is "software",
|
||||
which uses an internal software volume control. "mixer" uses the
|
||||
configured (hardware) mixer control. "none" disables replay gain on
|
||||
this audio output.
|
||||
.TP
|
||||
.B mixer_type <hardware, software or none>
|
||||
Specifies which mixer should be used for this audio output: the
|
||||
hardware mixer (available for ALSA, OSS and PulseAudio), the software
|
||||
mixer or no mixer ("none"). By default, the hardware mixer is used
|
||||
for devices which support it, and none for the others.
|
||||
.SH FILES
|
||||
.TP
|
||||
.BI ~/.mpdconf
|
||||
User configuration file.
|
||||
.TP
|
||||
.BI /etc/mpd.conf
|
||||
Global configuration file.
|
||||
.SH SEE ALSO
|
||||
mpd(1), mpc(1)
|
202
doc/mpd.conf.5.rst
Normal file
202
doc/mpd.conf.5.rst
Normal file
@@ -0,0 +1,202 @@
|
||||
========
|
||||
mpd.conf
|
||||
========
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
------------
|
||||
|
||||
:file:`mpd.conf` is the configuration file for :manpage:`mpd(1)`. If
|
||||
not specified on the command line, MPD first searches for it at
|
||||
:file:`$XDG_CONFIG_HOME/mpd/mpd.conf` then at :file:`~/.mpdconf` then
|
||||
at :file:`~/.mpd/mpd.conf` and then in :file:`/etc/mpd.conf`.
|
||||
|
||||
Lines beginning with a :samp:`#` character are comments. All other
|
||||
non-empty lines specify parameters and their values. These lines
|
||||
contain the parameter name and parameter value (surrounded by double
|
||||
quotes) separated by whitespace (either tabs or spaces). For
|
||||
example::
|
||||
|
||||
parameter "value"
|
||||
|
||||
The exception to this rule is the audio_output parameter, which is of
|
||||
the form::
|
||||
|
||||
audio_output {
|
||||
parameter1 "value"
|
||||
parameter2 "value"
|
||||
}
|
||||
|
||||
|
||||
Parameters that take a file or directory as an argument should use absolute paths.
|
||||
|
||||
See :file:`docs/mpdconf.example` in the source tarball for an example
|
||||
configuration file.
|
||||
|
||||
This manual is not complete, it lists only the most important options.
|
||||
Please read the MPD user manual for a complete configuration guide:
|
||||
http://www.musicpd.org/doc/user/
|
||||
|
||||
|
||||
REQUIRED PARAMETERS
|
||||
-------------------
|
||||
|
||||
db_file <file>
|
||||
This specifies where the db file will be stored.
|
||||
|
||||
log_file <file>
|
||||
This specifies where the log file should be located. The special value "syslog" makes MPD use the local syslog daemon.
|
||||
|
||||
OPTIONAL PARAMETERS
|
||||
-------------------
|
||||
|
||||
sticker_file <file>
|
||||
The location of the sticker database. This is a database which manages
|
||||
dynamic information attached to songs.
|
||||
|
||||
pid_file <file>
|
||||
This specifies the file to save mpd's process ID in.
|
||||
|
||||
music_directory <directory>
|
||||
This specifies the directory where music is located. If you do not configure
|
||||
this, you can only play streams.
|
||||
|
||||
playlist_directory <directory>
|
||||
This specifies the directory where saved playlists are stored. If
|
||||
you do not configure this, you cannot save playlists.
|
||||
|
||||
state_file <file>
|
||||
This specifies if a state file is used and where it is located. The state of
|
||||
mpd will be saved to this file when mpd is terminated by a TERM signal or by
|
||||
the :program:`kill` command. When mpd is restarted, it will read the state file and
|
||||
restore the state of mpd (including the playlist).
|
||||
|
||||
restore_paused <yes or no>
|
||||
Put MPD into pause mode instead of starting playback after startup.
|
||||
|
||||
user <username>
|
||||
This specifies the user that MPD will run as, if set. MPD should never run
|
||||
as root, and you may use this option to make MPD change its user id after
|
||||
initialization. Do not use this option if you start MPD as an unprivileged
|
||||
user.
|
||||
|
||||
port <port>
|
||||
This specifies the port that mpd listens on. The default is 6600.
|
||||
|
||||
log_level <default, secure, or verbose>
|
||||
Suppress all messages below the given threshold. The following
|
||||
log levels are available:
|
||||
|
||||
- :samp:`error`: errors
|
||||
- :samp:`warning`: warnings
|
||||
- :samp:`notice`: interesting informational messages
|
||||
- :samp:`info`: unimportant informational messages
|
||||
- :samp:`verbose`: debug messages (for developers and for
|
||||
troubleshooting)
|
||||
|
||||
The default is :samp:`notice`.
|
||||
|
||||
follow_outside_symlinks <yes or no>
|
||||
Control if MPD will follow symbolic links pointing outside the music dir. You
|
||||
must recreate the database after changing this option. The default is "yes".
|
||||
|
||||
follow_inside_symlinks <yes or no>
|
||||
Control if MPD will follow symbolic links pointing inside the music dir,
|
||||
potentially adding duplicates to the database. You must recreate the
|
||||
database after changing this option. The default is "yes".
|
||||
|
||||
zeroconf_enabled <yes or no>
|
||||
If yes, and MPD has been compiled with support for Avahi or Bonjour, service
|
||||
information will be published with Zeroconf. The default is yes.
|
||||
|
||||
zeroconf_name <name>
|
||||
If Zeroconf is enabled, this is the service name to publish. This name should
|
||||
be unique to your local network, but name collisions will be properly dealt
|
||||
with. The default is "Music Player @ %h", where %h will be replaced with the
|
||||
hostname of the machine running MPD.
|
||||
|
||||
audio_output
|
||||
See DESCRIPTION and the various ``AUDIO OUTPUT PARAMETERS`` sections for the
|
||||
format of this parameter. Multiple audio_output sections may be specified. If
|
||||
no audio_output section is specified, then MPD will scan for a usable audio
|
||||
output.
|
||||
|
||||
replaygain <off or album or track or auto>
|
||||
If specified, mpd will adjust the volume of songs played using ReplayGain
|
||||
tags (see http://www.replaygain.org/). Setting this to "album" will
|
||||
adjust volume using the album's ReplayGain tags, while setting it to "track"
|
||||
will adjust it using the track ReplayGain tags. "auto" uses the track
|
||||
ReplayGain tags if random play is activated otherwise the album ReplayGain
|
||||
tags. Currently only FLAC, Ogg Vorbis, Musepack, and MP3 (through ID3v2
|
||||
ReplayGain tags, not APEv2) are supported.
|
||||
|
||||
replaygain_preamp <-15 to 15>
|
||||
This is the gain (in dB) applied to songs with ReplayGain tags.
|
||||
|
||||
volume_normalization <yes or no>
|
||||
If yes, mpd will normalize the volume of songs as they play. The default is
|
||||
no.
|
||||
|
||||
filesystem_charset <charset>
|
||||
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.
|
||||
|
||||
save_absolute_paths_in_playlists <yes or no>
|
||||
This specifies whether relative or absolute paths for song filenames are used
|
||||
when saving playlists. The default is "no".
|
||||
|
||||
auto_update <yes or no>
|
||||
This specifies the whether to support automatic update of music database
|
||||
when files are changed in music_directory. The default is to disable
|
||||
autoupdate of database.
|
||||
|
||||
auto_update_depth <N>
|
||||
Limit the depth of the directories being watched, 0 means only watch the
|
||||
music directory itself. There is no limit by default.
|
||||
|
||||
REQUIRED AUDIO OUTPUT PARAMETERS
|
||||
--------------------------------
|
||||
|
||||
type <type>
|
||||
This specifies the audio output type. See the list of supported outputs in
|
||||
``mpd --version`` for possible values.
|
||||
|
||||
name <name>
|
||||
This specifies a unique name for the audio output.
|
||||
|
||||
OPTIONAL AUDIO OUTPUT PARAMETERS
|
||||
--------------------------------
|
||||
|
||||
format <sample_rate:bits:channels>
|
||||
This specifies the sample rate, bits per sample, and number of channels of
|
||||
audio that is sent to the audio output device. See documentation for the
|
||||
``audio_output_format`` parameter for more details. The default is to use
|
||||
whatever audio format is passed to the audio output. Any of the three
|
||||
attributes may be an asterisk to specify that this attribute should not be
|
||||
enforced
|
||||
|
||||
replay_gain_handler <software, mixer or none>
|
||||
Specifies how replay gain is applied. The default is "software", which uses
|
||||
an internal software volume control. "mixer" uses the configured (hardware)
|
||||
mixer control. "none" disables replay gain on this audio output.
|
||||
|
||||
mixer_type <hardware, software or none>
|
||||
Specifies which mixer should be used for this audio output: the hardware
|
||||
mixer (available for ALSA, OSS and PulseAudio), the software mixer or no
|
||||
mixer ("none"). By default, the hardware mixer is used for devices which
|
||||
support it, and none for the others.
|
||||
|
||||
FILES
|
||||
-----
|
||||
|
||||
:file:`~/.mpdconf`
|
||||
User configuration file.
|
||||
|
||||
:file:`/etc/mpd.conf`
|
||||
Global configuration file.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
:manpage:`mpd(1)`, :manpage:`mpc(1)`
|
@@ -89,12 +89,10 @@
|
||||
#
|
||||
#port "6600"
|
||||
#
|
||||
# This setting controls the type of information which is logged. Available
|
||||
# setting arguments are "default", "secure" or "verbose". The "verbose" setting
|
||||
# argument is recommended for troubleshooting, though can quickly stretch
|
||||
# available resources on limited hardware storage.
|
||||
# Suppress all messages below the given threshold. Use "verbose" for
|
||||
# troubleshooting.
|
||||
#
|
||||
#log_level "default"
|
||||
#log_level "notice"
|
||||
#
|
||||
# Setting "restore_paused" to "yes" puts MPD into pause mode instead
|
||||
# of starting playback after startup.
|
||||
@@ -280,6 +278,7 @@ input {
|
||||
# name "My Pulse Output"
|
||||
## server "remote_server" # optional
|
||||
## sink "remote_server_sink" # optional
|
||||
## media_role "media_role" #optional
|
||||
#}
|
||||
#
|
||||
# An example of a winmm output (Windows multimedia API).
|
||||
@@ -293,6 +292,20 @@ input {
|
||||
## mixer_type "hardware" # optional
|
||||
#}
|
||||
#
|
||||
# An example of a wasapi output (Windows multimedia API).
|
||||
#
|
||||
#audio_output {
|
||||
# type "wasapi"
|
||||
# name "My WASAPI output"
|
||||
## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
|
||||
# or
|
||||
## device "0" # optional
|
||||
## Exclusive mode blocks all other audio source, and get best audio quality without resampling.
|
||||
## exclusive "no" # optional
|
||||
## Enumerate all devices in log.
|
||||
## enumerate "no" # optional
|
||||
#}
|
||||
#
|
||||
# An example of an openal output.
|
||||
#
|
||||
#audio_output {
|
||||
|
215
doc/plugins.rst
215
doc/plugins.rst
@@ -27,7 +27,7 @@ The default plugin. Stores a copy of the database in memory. A file is used for
|
||||
proxy
|
||||
-----
|
||||
|
||||
Provides access to the database of another :program:`MPD` instance using libmpdclient. This is useful when you run mount the music directory via NFS/SMB, and the file server already runs a :program:`MPD` instance. Only the file server needs to update the database.
|
||||
Provides access to the database of another :program:`MPD` instance using libmpdclient. This is useful when you mount the music directory via NFS/SMB, and the file server already runs a :program:`MPD` instance. Only the file server needs to update the database.
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
@@ -60,25 +60,25 @@ The default plugin which gives :program:`MPD` access to local files. It is used
|
||||
curl
|
||||
----
|
||||
|
||||
A WebDAV client using libcurl. It is used when :code:`music_directory` contains a http:// or https:// URI, for example :samp:`https://the.server/dav/`.
|
||||
A WebDAV client using libcurl. It is used when :code:`music_directory`
|
||||
contains a ``http://`` or ``https://`` URI, for example
|
||||
:samp:`https://the.server/dav/`.
|
||||
|
||||
smbclient
|
||||
---------
|
||||
|
||||
Load music files from a SMB/CIFS server. It is used when :code:`music_directory` contains a smb:// URI, for example :samp:`smb://myfileserver/Music`.
|
||||
Load music files from a SMB/CIFS server. It is used when
|
||||
:code:`music_directory` contains a ``smb://`` URI, for example
|
||||
:samp:`smb://myfileserver/Music`.
|
||||
|
||||
nfs
|
||||
---
|
||||
|
||||
Load music files from a NFS server. It is used when :code:`music_directory` contains a nfs:// URI according to RFC2224, for example :samp:`nfs://servername/path`.
|
||||
Load music files from a NFS server. It is used when
|
||||
:code:`music_directory` contains a ``nfs://`` URI according to
|
||||
RFC2224, for example :samp:`nfs://servername/path`.
|
||||
|
||||
This plugin uses libnfs, which supports only NFS version 3. Since :program:`MPD` is not allowed to bind to "privileged ports", the NFS server needs to enable the "insecure" setting; example :file:`/etc/exports`:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
/srv/mp3 192.168.1.55(ro,insecure)
|
||||
|
||||
Don't fear: "insecure" does not mean that your NFS server is insecure. A few decades ago, people thought the concept of "privileged ports" would make network services "secure", which was a fallacy. The absence of this obsolete "security" measure means little.
|
||||
See :ref:`input_nfs` for more information.
|
||||
|
||||
udisks
|
||||
------
|
||||
@@ -116,7 +116,7 @@ Provides a list of SMB/CIFS servers on the local network.
|
||||
udisks
|
||||
------
|
||||
|
||||
Queries the udisks2 daemon via D-Bus and obtain a list of file systems (e.g. USB sticks or other removable media).
|
||||
Queries the udisks2 daemon via D-Bus and obtains a list of file systems (e.g. USB sticks or other removable media).
|
||||
|
||||
upnp
|
||||
----
|
||||
@@ -131,15 +131,39 @@ Input plugins
|
||||
alsa
|
||||
----
|
||||
|
||||
Allows :program:`MPD` on Linux to play audio directly from a soundcard using the scheme alsa://. Audio is formatted as 44.1 kHz 16-bit stereo (CD format). Examples:
|
||||
Allows :program:`MPD` on Linux to play audio directly from a soundcard using the scheme alsa://. Audio is by default formatted as 48 kHz 16-bit stereo, but this default can be overidden by a config file setting or by the URI. Examples:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpc add alsa:// plays audio from device hw:0,0
|
||||
mpc add alsa:// plays audio from device default
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpc add alsa://hw:1,0 plays audio from device hw:1,0 cdio_paranoia
|
||||
mpc add alsa://hw:1,0 plays audio from device hw:1,0
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpc add alsa://hw:1,0?format=44100:16:2 plays audio from device hw:1,0 sampling 16-bit stereo at 44.1kHz.
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
:header-rows: 1
|
||||
|
||||
* - Setting
|
||||
- Description
|
||||
* - **default_device NAME**
|
||||
- The alsa device id to use when none is specified in the URI.
|
||||
* - **default_format F**
|
||||
- The sampling rate, size and channels to use. Wildcards are not allowed.
|
||||
|
||||
Example - "44100:16:2"
|
||||
|
||||
* - **auto_resample yes|no**
|
||||
- If set to no, then libasound will not attempt to resample. In this case, the user is responsible for ensuring that the requested sample rate can be produced natively by the device, otherwise an error will occur.
|
||||
* - **auto_channels yes|no**
|
||||
- If set to no, then libasound will not attempt to convert between different channel numbers. The user must ensure that the device supports the requested channels when sampling.
|
||||
* - **auto_format yes|no**
|
||||
- If set to no, then libasound will not attempt to convert between different sample formats (16 bit, 24 bit, floating point, ...). Again the user must ensure that the requested format is available natively from the device.
|
||||
|
||||
cdio_paranoia
|
||||
-------------
|
||||
@@ -162,7 +186,10 @@ curl
|
||||
|
||||
Opens remote files or streams over HTTP using libcurl.
|
||||
|
||||
Note that unless overridden by the below settings (e.g. by setting them to a blank value), general curl configuration from environment variables such as http_proxy or specified in :file:`~/.curlrc` will be in effect.
|
||||
Note that unless overridden by the below settings (e.g. by setting
|
||||
them to a blank value), general curl configuration from environment
|
||||
variables such as ``http_proxy`` or specified in :file:`~/.curlrc`
|
||||
will be in effect.
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
@@ -182,7 +209,9 @@ Note that unless overridden by the below settings (e.g. by setting them to a bla
|
||||
ffmpeg
|
||||
------
|
||||
|
||||
Access to various network protocols implemented by the FFmpeg library: gopher://, rtp://, rtsp://, rtmp://, rtmpt://, rtmps://
|
||||
Access to various network protocols implemented by the FFmpeg library:
|
||||
``gopher://``, ``rtp://``, ``rtsp://``, ``rtmp://``, ``rtmpt://``,
|
||||
``rtmps://``
|
||||
|
||||
file
|
||||
----
|
||||
@@ -194,30 +223,51 @@ mms
|
||||
|
||||
Plays streams with the MMS protocol using `libmms <https://launchpad.net/libmms>`_.
|
||||
|
||||
.. _input_nfs:
|
||||
|
||||
nfs
|
||||
---
|
||||
|
||||
Allows :program:`MPD` to access files on NFSv3 servers without actually mounting them (i.e. in userspace, without help from the kernel's VFS layer). All URIs with the nfs:// scheme are used according to RFC2224. Example:
|
||||
Allows :program:`MPD` to access files on NFS servers without actually
|
||||
mounting them (i.e. with :program:`libnfs` in userspace, without help
|
||||
from the kernel's VFS layer). All URIs with the ``nfs://`` scheme are
|
||||
used according to RFC2224. Example:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpc add nfs://servername/path/filename.ogg
|
||||
|
||||
Note that this usually requires enabling the "insecure" flag in the server's /etc/exports file, because :program:`MPD` cannot bind to so-called "privileged" ports. Don't fear: this will not make your file server insecure; the flag was named in a time long ago when privileged ports were thought to be meaningful for security. By today's standards, NFSv3 is not secure at all, and if you believe it is, you're already doomed.
|
||||
This plugin uses :program:`libnfs`, which supports only NFS version 3.
|
||||
Since :program:`MPD` is not allowed to bind to so-called "privileged
|
||||
ports", the NFS server needs to enable the ``insecure`` setting;
|
||||
example :file:`/etc/exports`:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
/srv/mp3 192.168.1.55(ro,insecure)
|
||||
|
||||
Don't fear: this will not make your file server insecure; the flag was
|
||||
named a time long ago when privileged ports were thought to be
|
||||
meaningful for security. By today's standards, NFSv3 is not secure at
|
||||
all, and if you believe it is, you're already doomed.
|
||||
|
||||
smbclient
|
||||
---------
|
||||
|
||||
Allows :program:`MPD` to access files on SMB/CIFS servers (e.g. Samba or Microsoft Windows). All URIs with the smb:// scheme are used. Example:
|
||||
Allows :program:`MPD` to access files on SMB/CIFS servers (e.g. Samba
|
||||
or Microsoft Windows). All URIs with the ``smb://`` scheme are
|
||||
used. Example:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpc add smb://servername/sharename/filename.ogg
|
||||
mpc add smb://username:password@servername/sharename/filename.ogg
|
||||
|
||||
qobuz
|
||||
-----
|
||||
|
||||
Play songs from the commercial streaming service Qobuz. It plays URLs in the form qobuz://track/ID, e.g.:
|
||||
Play songs from the commercial streaming service Qobuz. It plays URLs
|
||||
in the form ``qobuz://track/ID``, e.g.:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@@ -243,7 +293,9 @@ Play songs from the commercial streaming service Qobuz. It plays URLs in the for
|
||||
tidal
|
||||
-----
|
||||
|
||||
Play songs from the commercial streaming service `Tidal <http://tidal.com/>`_. It plays URLs in the form tidal://track/ID, e.g.:
|
||||
Play songs from the commercial streaming service `Tidal
|
||||
<http://tidal.com/>`_. It plays URLs in the form ``tidal://track/ID``,
|
||||
e.g.:
|
||||
|
||||
.. warning::
|
||||
|
||||
@@ -298,6 +350,8 @@ faad
|
||||
|
||||
Decodes AAC files using libfaad.
|
||||
|
||||
.. _decoder_ffmpeg:
|
||||
|
||||
ffmpeg
|
||||
------
|
||||
|
||||
@@ -367,30 +421,22 @@ Video game music file emulator based on `game-music-emu <https://bitbucket.org/m
|
||||
- Description
|
||||
* - **accuracy yes|no**
|
||||
- Enable more accurate sound emulation.
|
||||
* - **default_fade**
|
||||
- The default fade-out time, in seconds. Used by songs that don't specify their own fade-out time.
|
||||
|
||||
hybrid_dsd
|
||||
----------
|
||||
|
||||
`Hybrid-DSD
|
||||
<http://dsdmaster.blogspot.de/p/bitperfect-introduces-hybrid-dsd-file.html>`_
|
||||
is a MP4 container file (:file:`*.m4a`) which contains both ALAC and
|
||||
is an MP4 container file (:file:`*.m4a`) which contains both ALAC and
|
||||
DSD data. It is disabled by default, and works only if you explicitly
|
||||
enable it. Without this plugin, the ALAC parts gets handled by the
|
||||
`FFmpeg decoder plugin
|
||||
<https://www.musicpd.org/doc/user/decoder_plugins.html#ffmpeg_decoder>`_. This
|
||||
:ref:`FFmpeg decoder plugin <decoder_ffmpeg>`. This
|
||||
plugin should be enabled only if you have a bit-perfect playback path
|
||||
to a DSD-capable DAC; for everybody else, playing back the ALAC copy
|
||||
of the file is better.
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
:header-rows: 1
|
||||
|
||||
* - Setting
|
||||
- Description
|
||||
* - **gapless yes|no**
|
||||
- This specifies whether to support gapless playback of MP3s which have the necessary headers. Useful if your MP3s have headers with incorrect information. If you have such MP3s, it is highly recommended that you fix them using `vbrfix <http://www.willwap.co.uk/Programs/vbrfix.php>`_ instead of disabling gapless MP3 playback. The default is to support gapless MP3 playback.
|
||||
|
||||
mad
|
||||
---
|
||||
|
||||
@@ -434,7 +480,9 @@ Decodes Musepack files using `libmpcdec <http://www.musepack.net/>`_.
|
||||
mpg123
|
||||
------
|
||||
|
||||
Decodes MP3 files using `libmpg123 <http://www.mpg123.de/>`_.
|
||||
Decodes MP3 files using `libmpg123 <http://www.mpg123.de/>`_. Currently, this
|
||||
decoder does not support streams (e.g. archived files, remote files over HTTP,
|
||||
...), only regular local files.
|
||||
|
||||
opus
|
||||
----
|
||||
@@ -444,7 +492,7 @@ Decodes Opus files using `libopus <http://www.opus-codec.org/>`_.
|
||||
pcm
|
||||
---
|
||||
|
||||
Read raw PCM samples. It understands the "audio/L16" MIME type with parameters "rate" and "channels" according to RFC 2586. It also understands the MPD-specific MIME type "audio/x-mpd-float".
|
||||
Reads raw PCM samples. It understands the "audio/L16" MIME type with parameters "rate" and "channels" according to RFC 2586. It also understands the MPD-specific MIME type "audio/x-mpd-float".
|
||||
|
||||
sidplay
|
||||
-------
|
||||
@@ -458,9 +506,11 @@ C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay
|
||||
* - Setting
|
||||
- Description
|
||||
* - **songlength_database PATH**
|
||||
- Location of your songlengths file, as distributed with the HVSC. The sidplay plugin checks this for matching MD5 fingerprints. See http://www.hvsc.c64.org/download/C64Music/DOCUMENTS/Songlengths.faq.
|
||||
- Location of your songlengths file, as distributed with the HVSC. The sidplay plugin checks this for matching MD5 fingerprints. See http://www.hvsc.c64.org/download/C64Music/DOCUMENTS/Songlengths.faq. New songlength format support requires libsidplayfp 2.0 or later.
|
||||
* - **default_songlength SECONDS**
|
||||
- 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.
|
||||
* - **default_genre GENRE**
|
||||
- Optional default genre for SID songs.
|
||||
* - **filter yes|no**
|
||||
- Turns the SID filter emulation on or off.
|
||||
* - **kernal**
|
||||
@@ -696,6 +746,25 @@ Valid quality values for libsoxr:
|
||||
* "medium"
|
||||
* "low"
|
||||
* "quick"
|
||||
* "custom"
|
||||
|
||||
If the quality is set to custom also the following settings are available:
|
||||
|
||||
* - Name
|
||||
- Description
|
||||
* - **precision**
|
||||
- The precision in bits. Valid values 16,20,24,28 and 32 bits.
|
||||
* - **phase_response**
|
||||
- Between the 0-100, Where 0=MINIMUM_PHASE and 50=LINEAR_PHASE.
|
||||
* - **passband_end**
|
||||
- The % of source bandwidth where to start filtering. Typical between the 90-99.7.
|
||||
* - **stopband_begin**
|
||||
- The % of the source bandwidth Where the anti aliasing filter start. Value 100+.
|
||||
* - **attenuation**
|
||||
- Reduction in dB's to prevent clipping from the resampling process.
|
||||
* - **flags**
|
||||
- Bitmask with additional option see soxr documentation for specific flags.
|
||||
|
||||
|
||||
.. _output_plugins:
|
||||
|
||||
@@ -840,6 +909,10 @@ The jack plugin connects to a `JACK server <http://jackaudio.org/>`_.
|
||||
- The names of the JACK source ports to be created. By default, the ports "left" and "right" are created. To use more ports, you have to tweak this option.
|
||||
* - **destination_ports A,B**
|
||||
- The names of the JACK destination ports to connect to.
|
||||
* - **auto_destination_ports yes|no**
|
||||
- If set to *yes*, then MPD will automatically create connections between the send ports of
|
||||
MPD and receive ports of the first sound card; if set to *no*, then MPD will only create
|
||||
connections to the contents of *destination_ports* if it is set. Enabled by default.
|
||||
* - **ringbuffer_size NBYTES**
|
||||
- Sets the size of the ring buffer for each channel. Do not configure this value unless you know what you're doing.
|
||||
|
||||
@@ -974,6 +1047,8 @@ The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Soft
|
||||
- Sets the host name of the PulseAudio server. By default, :program:`MPD` connects to the local PulseAudio server.
|
||||
* - **sink NAME**
|
||||
- Specifies the name of the PulseAudio sink :program:`MPD` should play on.
|
||||
* - **media_role ROLE**
|
||||
- Specifies a custom media role that :program:`MPD` reports to PulseAudio. Default is "music". (optional).
|
||||
* - **scale_volume FACTOR**
|
||||
- Specifies a linear scaling coefficient (ranging from 0.5 to 5.0) to apply when adjusting volume through :program:`MPD`. For example, chosing a factor equal to ``"0.7"`` means that setting the volume to 100 in :program:`MPD` will set the PulseAudio volume to 70%, and a factor equal to ``"3.5"`` means that volume 100 in :program:`MPD` corresponds to a 350% PulseAudio volume.
|
||||
|
||||
@@ -1044,7 +1119,8 @@ sles
|
||||
|
||||
Plugin using the `OpenSL ES <https://www.khronos.org/opensles/>`__
|
||||
audio API. Its primary use is local playback on Android, where
|
||||
:ref:`ALSA <alsa_plugin>` is not available.
|
||||
:ref:`ALSA <alsa_plugin>` is not available. It supports 16 bit and
|
||||
floating point samples.
|
||||
|
||||
|
||||
solaris
|
||||
@@ -1061,11 +1137,58 @@ The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
|
||||
- Sets the path of the audio device, defaults to /dev/audio.
|
||||
|
||||
|
||||
wasapi
|
||||
------
|
||||
|
||||
The `Windows Audio Session API <https://docs.microsoft.com/en-us/windows/win32/coreaudio/wasapi>`_ plugin uses WASAPI, which is supported started from Windows Vista. It is recommended if you are using Windows.
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
:header-rows: 1
|
||||
|
||||
* - Setting
|
||||
- Description
|
||||
* - **device NAME**
|
||||
- Sets the device which should be used. This can be any valid audio device name, or index number. The default value is "", which makes WASAPI choose the default output device.
|
||||
* - **enumerate yes|no**
|
||||
- Enumerate all devices in log while playing started. Useful for device configuration. The default value is "no".
|
||||
* - **exclusive yes|no**
|
||||
- Exclusive mode blocks all other audio source, and get best audio quality without resampling. Stopping playing release the exclusive control of the output device. The default value is "no".
|
||||
|
||||
|
||||
.. _filter_plugins:
|
||||
|
||||
Filter plugins
|
||||
==============
|
||||
|
||||
ffmpeg
|
||||
------
|
||||
|
||||
Configures a FFmpeg filter graph.
|
||||
|
||||
This plugin requires building with ``libavfilter`` (FFmpeg).
|
||||
|
||||
.. list-table::
|
||||
:widths: 20 80
|
||||
:header-rows: 1
|
||||
|
||||
* - Setting
|
||||
- Description
|
||||
* - **graph "..."**
|
||||
- Specifies the ``libavfilter`` graph; read the `FFmpeg
|
||||
documentation
|
||||
<https://libav.org/documentation/libavfilter.html#Filtergraph-syntax-1>`_
|
||||
for details
|
||||
|
||||
|
||||
hdcd
|
||||
----
|
||||
|
||||
Decode `HDCD
|
||||
<https://en.wikipedia.org/wiki/High_Definition_Compatible_Digital>`_.
|
||||
|
||||
This plugin requires building with ``libavfilter`` (FFmpeg).
|
||||
|
||||
normalize
|
||||
---------
|
||||
|
||||
@@ -1148,3 +1271,19 @@ Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
|
||||
xspf
|
||||
----
|
||||
Reads XSPF playlist files.
|
||||
|
||||
|
||||
Archive plugins
|
||||
===============
|
||||
|
||||
bz2
|
||||
---
|
||||
Allows to load single bzip2 compressed files using `libbz2 <https://www.sourceware.org/bzip2/>`_. Does not support seeking.
|
||||
|
||||
zzip
|
||||
----
|
||||
Allows to load music files from ZIP archives using `zziplib <http://zziplib.sourceforge.net/>`_.
|
||||
|
||||
iso
|
||||
---
|
||||
Allows to load music files from ISO 9660 images using `libcdio <https://www.gnu.org/software/libcdio/>`_.
|
||||
|
120
doc/protocol.rst
120
doc/protocol.rst
@@ -66,7 +66,16 @@ Binary Responses
|
||||
Some commands can return binary data. This is initiated by a line
|
||||
containing ``binary: 1234`` (followed as usual by a newline). After
|
||||
that, the specified number of bytes of binary data follows, then a
|
||||
newline, and finally the ``OK`` line. Example::
|
||||
newline, and finally the ``OK`` line.
|
||||
|
||||
If the object to be transmitted is large, the server may choose a
|
||||
reasonable chunk size and transmit only a portion. Usually, the
|
||||
response also contains a ``size`` line which specifies the total
|
||||
(uncropped) size, and the command usually has a way to specify an
|
||||
offset into the object; this way, the client can copy the whole file
|
||||
without blocking the connection for too long.
|
||||
|
||||
Example::
|
||||
|
||||
foo: bar
|
||||
binary: 42
|
||||
@@ -163,7 +172,7 @@ syntax::
|
||||
|
||||
find EXPRESSION
|
||||
|
||||
``EXPRESSION`` is a string enclosed in parantheses which can be one
|
||||
``EXPRESSION`` is a string enclosed in parentheses which can be one
|
||||
of:
|
||||
|
||||
- ``(TAG == 'VALUE')``: match a tag value; if there are multiple
|
||||
@@ -209,15 +218,15 @@ of:
|
||||
or more attributes may be ``*``).
|
||||
|
||||
- ``(!EXPRESSION)``: negate an expression. Note that each expression
|
||||
must be enclosed in parantheses, e.g. :code:`(!(artist == 'VALUE'))`
|
||||
must be enclosed in parentheses, e.g. :code:`(!(artist == 'VALUE'))`
|
||||
(which is equivalent to :code:`(artist != 'VALUE')`)
|
||||
|
||||
- ``(EXPRESSION1 AND EXPRESSION2 ...)``: combine two or
|
||||
more expressions with logical "and". Note that each expression must
|
||||
be enclosed in parantheses, e.g. :code:`((artist == 'FOO') AND
|
||||
be enclosed in parentheses, e.g. :code:`((artist == 'FOO') AND
|
||||
(album == 'BAR'))`
|
||||
|
||||
The :command:`find` commands are case sensitive, which
|
||||
The :command:`find` commands are case sensitive, while
|
||||
:command:`search` and related commands ignore case.
|
||||
|
||||
Prior to MPD 0.21, the syntax looked like this::
|
||||
@@ -274,6 +283,12 @@ The following tags are supported by :program:`MPD`:
|
||||
* **date**: the song's release date. This is usually a 4-digit year.
|
||||
* **composer**: the artist who composed the song.
|
||||
* **performer**: the artist who performed the song.
|
||||
* **conductor**: the conductor who conducted the song.
|
||||
* **work**: `"a work is a distinct intellectual or artistic creation,
|
||||
which can be expressed in the form of one or more audio recordings" <https://musicbrainz.org/doc/Work>`_
|
||||
* **grouping**: "used if the sound belongs to a larger category of
|
||||
sounds/music" (`from the IDv2.4.0 TIT1 description
|
||||
<http://id3.org/id3v2.4.0-frames>`_).
|
||||
* **comment**: a human-readable comment about this song. The exact meaning of this tag is not well-defined.
|
||||
* **disc**: the decimal disc number in a multi-disc album.
|
||||
* **label**: the name of the label or publisher.
|
||||
@@ -374,7 +389,9 @@ Querying :program:`MPD`'s status
|
||||
|
||||
:command:`currentsong`
|
||||
Displays the song info of the current song (same song that
|
||||
is identified in status).
|
||||
is identified in status). Information about the current song
|
||||
is represented by key-value pairs, one on each line. The first
|
||||
pair must be the `file` key-value pair.
|
||||
|
||||
.. _command_idle:
|
||||
|
||||
@@ -398,9 +415,11 @@ Querying :program:`MPD`'s status
|
||||
- ``sticker``: the sticker database has been modified.
|
||||
- ``subscription``: a client has subscribed or unsubscribed to a channel
|
||||
- ``message``: a message was received on a channel this client is subscribed to; this event is only emitted when the queue is empty
|
||||
- ``neighbor``: a neighbor was found or lost
|
||||
- ``mount``: the mount list has changed
|
||||
|
||||
Change events accumulate, even while the connection is not in
|
||||
"idle" mode; no events gets lost while the client is doing
|
||||
"idle" mode; no events get lost while the client is doing
|
||||
something else with the connection. If an event had already
|
||||
occurred since the last call, the new :ref:`idle <command_idle>`
|
||||
command will return immediately.
|
||||
@@ -424,6 +443,8 @@ Querying :program:`MPD`'s status
|
||||
Reports the current status of the player and the volume
|
||||
level.
|
||||
|
||||
- ``partition``: the name of the current partition (see
|
||||
:ref:`partition_commands`)
|
||||
- ``volume``: ``0-100`` (deprecated: ``-1`` if the volume cannot
|
||||
be determined)
|
||||
- ``repeat``: ``0`` or ``1``
|
||||
@@ -464,7 +485,8 @@ Querying :program:`MPD`'s status
|
||||
- ``songs``: number of songs
|
||||
- ``uptime``: daemon uptime in seconds
|
||||
- ``db_playtime``: sum of all song times in the database in seconds
|
||||
- ``db_update``: last db update in UNIX time
|
||||
- ``db_update``: last db update in UNIX time (seconds since
|
||||
1970-01-01 UTC)
|
||||
- ``playtime``: time length of music played
|
||||
|
||||
Playback options
|
||||
@@ -514,7 +536,7 @@ Playback options
|
||||
``auto``
|
||||
.
|
||||
Changing the mode during playback may take several
|
||||
seconds, because the new settings does not affect the
|
||||
seconds, because the new settings do not affect the
|
||||
buffered data.
|
||||
This command triggers the
|
||||
``options`` idle event.
|
||||
@@ -534,10 +556,10 @@ Controlling playback
|
||||
:command:`next`
|
||||
Plays next song in the playlist.
|
||||
|
||||
:command:`pause {PAUSE}`
|
||||
Toggles pause/resumes playing, ``PAUSE`` is 0 or 1.
|
||||
|
||||
The use of pause command without the PAUSE argument is deprecated.
|
||||
:command:`pause {STATE}`
|
||||
Pause or resume playback. Pass :samp:`1` to pause playback or
|
||||
:samp:`0` to resume playback. Without the parameter, the pause
|
||||
state is toggled.
|
||||
|
||||
:command:`play [SONGPOS]`
|
||||
Begins playing the playlist at song number
|
||||
@@ -808,11 +830,12 @@ The music database
|
||||
==================
|
||||
|
||||
:command:`albumart {URI} {OFFSET}`
|
||||
Searches the directory the file ``URI``
|
||||
resides in and attempts to return a chunk of an album
|
||||
Locate album art for the given song and return a chunk of an album
|
||||
art image file at offset ``OFFSET``.
|
||||
Uses the filename "cover" with any of ".png, .jpg,
|
||||
.tiff, .bmp".
|
||||
|
||||
This is currently implemented by searching the directory the file
|
||||
resides in for a file called :file:`cover.png`, :file:`cover.jpg`,
|
||||
:file:`cover.tiff` or :file:`cover.bmp`.
|
||||
|
||||
Returns the file size and actual number
|
||||
of bytes read at the requested offset, followed
|
||||
@@ -821,7 +844,7 @@ The music database
|
||||
|
||||
Example::
|
||||
|
||||
albumart
|
||||
albumart foo/bar.ogg 0
|
||||
size: 1024768
|
||||
binary: 8192
|
||||
<8192 bytes>
|
||||
@@ -845,10 +868,21 @@ The music database
|
||||
count group artist
|
||||
count title Echoes group artist
|
||||
|
||||
A group with an empty value contains counts of matching song which
|
||||
don't this group tag. It exists only if at least one such song is
|
||||
A group with an empty value contains counts of matching songs which
|
||||
don't have this group tag. It exists only if at least one such song is
|
||||
found.
|
||||
|
||||
:command:`getfingerprint {URI}`
|
||||
|
||||
Calculate the song's audio fingerprint. Example (abbreviated fingerprint)::
|
||||
|
||||
getfingerprint "foo/bar.ogg"
|
||||
chromaprint: AQACcEmSREmWJJmkIT_6CCf64...
|
||||
OK
|
||||
|
||||
This command is only available if MPD was built with
|
||||
:file:`libchromaprint` (``-Dchromaprint=enabled``).
|
||||
|
||||
.. _command_find:
|
||||
|
||||
:command:`find {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||
@@ -875,7 +909,7 @@ The music database
|
||||
|
||||
.. _command_findadd:
|
||||
|
||||
:command:`findadd {FILTER}`
|
||||
:command:`findadd {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||
Search the database for songs matching
|
||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||
the queue. Parameters have the same meaning as for
|
||||
@@ -980,6 +1014,30 @@ The music database
|
||||
decoder plugins support it. For example, on Ogg files,
|
||||
this lists the Vorbis comments.
|
||||
|
||||
:command:`readpicture {URI} {OFFSET}`
|
||||
Locate a picture for the given song and return a chunk of the
|
||||
image file at offset ``OFFSET``. This is usually implemented by
|
||||
reading embedded pictures from binary tags (e.g. ID3v2's ``APIC``
|
||||
tag).
|
||||
|
||||
Returns the following values:
|
||||
|
||||
- ``size``: the total file size
|
||||
- ``type``: the file's MIME type (optional)
|
||||
- ``binary``: see :ref:`binary`
|
||||
|
||||
If the song file was recognized, but there is no picture, the
|
||||
response is successful, but is otherwise empty.
|
||||
|
||||
Example::
|
||||
|
||||
readpicture foo/bar.ogg 0
|
||||
size: 1024768
|
||||
type: image/jpeg
|
||||
binary: 8192
|
||||
<8192 bytes>
|
||||
OK
|
||||
|
||||
.. _command_search:
|
||||
|
||||
:command:`search {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||
@@ -990,14 +1048,14 @@ The music database
|
||||
|
||||
.. _command_searchadd:
|
||||
|
||||
:command:`searchadd {FILTER}`
|
||||
:command:`searchadd {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||
Search the database for songs matching
|
||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||
the queue.
|
||||
|
||||
Parameters have the same meaning as for :ref:`search <command_search>`.
|
||||
|
||||
:command:`searchaddpl {NAME} {FILTER}`
|
||||
:command:`searchaddpl {NAME} {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||
Search the database for songs matching
|
||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||
the playlist named ``NAME``.
|
||||
@@ -1037,8 +1095,8 @@ access NFS and SMB servers.
|
||||
Multiple storages can be "mounted" together, similar to the
|
||||
`mount` command on many operating
|
||||
systems, but without cooperation from the kernel. No
|
||||
superuser privileges are necessary, beause this mapping exists
|
||||
only inside the :program:`MPD` process
|
||||
superuser privileges are necessary, because this mapping exists
|
||||
only inside the :program:`MPD` process.
|
||||
|
||||
.. _command_mount:
|
||||
|
||||
@@ -1187,6 +1245,8 @@ Connection settings
|
||||
Announce that this client is interested in all tag
|
||||
types. This is the default setting for new clients.
|
||||
|
||||
.. _partition_commands:
|
||||
|
||||
Partition commands
|
||||
==================
|
||||
|
||||
@@ -1207,6 +1267,13 @@ client is assigned to one partition at a time.
|
||||
:command:`newpartition {NAME}`
|
||||
Create a new partition.
|
||||
|
||||
:command:`delpartition {NAME}`
|
||||
Delete a partition. The partition must be empty (no connected
|
||||
clients and no outputs).
|
||||
|
||||
:command:`moveoutput {OUTPUTNAME}`
|
||||
Move an output to the current partition.
|
||||
|
||||
Audio output devices
|
||||
====================
|
||||
|
||||
@@ -1296,6 +1363,9 @@ additional services.
|
||||
New messages are indicated by the ``message``
|
||||
idle event.
|
||||
|
||||
If your MPD instance has multiple partitions, note that
|
||||
client-to-client messages are local to the current partition.
|
||||
|
||||
:command:`subscribe {NAME}`
|
||||
Subscribe to a channel. The channel is created if it
|
||||
does not exist already. The name may consist of
|
||||
|
270
doc/user.rst
270
doc/user.rst
@@ -44,7 +44,9 @@ ALSA is not available on Android; only the :ref:`OpenSL ES
|
||||
Compiling from source
|
||||
---------------------
|
||||
|
||||
Download the source tarball from the `MPD home page <https://musicpd.org>`_ and unpack it:
|
||||
`Download the source tarball <https://www.musicpd.org/download.html>`_
|
||||
and unpack it (or `clone the git repository
|
||||
<https://github.com/MusicPlayerDaemon/MPD>`_):
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
@@ -53,7 +55,7 @@ Download the source tarball from the `MPD home page <https://musicpd.org>`_ and
|
||||
|
||||
In any case, you need:
|
||||
|
||||
* a C++14 compiler (e.g. gcc 6.0 or clang 3.9)
|
||||
* a C++17 compiler (e.g. GCC 8 or clang 5)
|
||||
* `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
|
||||
<https://ninja-build.org/>`__
|
||||
* Boost 1.58
|
||||
@@ -185,47 +187,6 @@ ABI is the Android ABI to be built, e.g. ":code:`arm64-v8a`".
|
||||
|
||||
This downloads various library sources, and then configures and builds :program:`MPD`.
|
||||
|
||||
systemd socket activation
|
||||
-------------------------
|
||||
|
||||
Using systemd, you can launch :program:`MPD` on demand when the first client attempts to connect.
|
||||
|
||||
:program:`MPD` comes with two systemd unit files: a "service" unit and
|
||||
a "socket" unit. These will be installed to the directory specified
|
||||
with :code:`-Dsystemd_system_unit_dir=...`,
|
||||
e.g. :file:`/lib/systemd/system`.
|
||||
|
||||
To enable socket activation, type:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl enable mpd.socket
|
||||
systemctl start mpd.socket
|
||||
|
||||
In this configuration, :program:`MPD` will ignore the :ref:`listener
|
||||
settings <listeners>` (``bind_to_address`` and ``port``).
|
||||
|
||||
systemd user unit
|
||||
-----------------
|
||||
|
||||
You can launch :program:`MPD` as a systemd user unit. These will be
|
||||
installed to the directory specified with
|
||||
:code:`-Dsystemd_user_unit_dir=...`,
|
||||
e.g. :file:`/usr/lib/systemd/user` or
|
||||
:file:`$HOME/.local/share/systemd/user`.
|
||||
|
||||
Once the user unit is installed, you can start and stop :program:`MPD` like any other service:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl --user start mpd
|
||||
|
||||
To auto-start :program:`MPD` upon login, type:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl --user enable mpd
|
||||
|
||||
Configuration
|
||||
*************
|
||||
|
||||
@@ -260,6 +221,13 @@ another file; the given file name is relative to the current file:
|
||||
|
||||
include "other.conf"
|
||||
|
||||
You can use :code:`include_optional` instead if you want the included file
|
||||
to be optional; the directive will be ignored if the file does not exist:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
include_optional "may_not_exist.conf"
|
||||
|
||||
Configuring the music directory
|
||||
-------------------------------
|
||||
|
||||
@@ -336,6 +304,44 @@ The following table lists the input options valid for all plugins:
|
||||
|
||||
More information can be found in the :ref:`input_plugins` reference.
|
||||
|
||||
.. _input_cache:
|
||||
|
||||
Configuring the Input Cache
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The input cache prefetches queued song files before they are going to
|
||||
be played. This has several advantages:
|
||||
|
||||
- risk of buffer underruns during playback is reduced because this
|
||||
decouples playback from disk (or network) I/O
|
||||
- bulk transfers may be faster and more energy efficient than loading
|
||||
small chunks on-the-fly
|
||||
- by prefetching several songs at a time, the hard disk can spin down
|
||||
for longer periods of time
|
||||
|
||||
This comes at a cost:
|
||||
|
||||
- memory usage
|
||||
- bulk transfers may reduce the performance of other applications
|
||||
which also want to access the disk (if the kernel's I/O scheduler
|
||||
isn't doing its job properly)
|
||||
|
||||
To enable the input cache, add an ``input_cache`` block to the
|
||||
configuration file:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
input_cache {
|
||||
size "1 GB"
|
||||
}
|
||||
|
||||
This allocates a cache of 1 GB. If the cache grows larger than that,
|
||||
older files will be evicted.
|
||||
|
||||
You can flush the cache at any time by sending ``SIGHUP`` to the
|
||||
:program:`MPD` process, see :ref:`signals`.
|
||||
|
||||
|
||||
Configuring decoder plugins
|
||||
---------------------------
|
||||
|
||||
@@ -419,7 +425,7 @@ The following table lists the audio_output options valid for all plugins:
|
||||
:ref:`oss_plugin` and PulseAudio :ref:`pulse_plugin`), the
|
||||
software mixer, the ":samp:`null`" mixer (allows setting the
|
||||
volume, but with no effect; this can be used as a trick to
|
||||
implement an external mixer :ref:`external_mixer`) or no mixer
|
||||
implement an external mixer, see :ref:`external_mixer`) or no mixer
|
||||
(:samp:`none`). By default, the hardware mixer is used for
|
||||
devices which support it, and none for the others.
|
||||
* - **filters "name,...**"
|
||||
@@ -714,8 +720,9 @@ Do not change these unless you know what you are doing.
|
||||
|
||||
* - Setting
|
||||
- Description
|
||||
* - **audio_buffer_size KBYTES**
|
||||
- Adjust the size of the internal audio buffer. Default is 4096 (4 MiB).
|
||||
* - **audio_buffer_size SIZE**
|
||||
- Adjust the size of the internal audio buffer. Default is
|
||||
:samp:`4 MB` (4 MiB).
|
||||
|
||||
Zeroconf
|
||||
^^^^^^^^
|
||||
@@ -763,22 +770,24 @@ The :code:`music_directory` setting tells :program:`MPD` to read files from the
|
||||
|
||||
The database setting tells :program:`MPD` to pass all database queries on to the :program:`MPD` instance running on the file server (using the proxy plugin).
|
||||
|
||||
.. _realtime:
|
||||
|
||||
Real-Time Scheduling
|
||||
--------------------
|
||||
|
||||
On Linux, :program:`MPD` attempts to configure real-time scheduling for some threads that benefit from it.
|
||||
|
||||
This is only possible you allow :program:`MPD` to do it. This privilege is controlled by :envvar:`RLIMIT_RTPRIO` :envvar:`RLIMIT_RTTIME`. You can configure this privilege with :command:`ulimit` before launching :program:`MPD`:
|
||||
This is only possible if you allow :program:`MPD` to do it. This privilege is controlled by :envvar:`RLIMIT_RTPRIO` :envvar:`RLIMIT_RTTIME`. You can configure this privilege with :command:`ulimit` before launching :program:`MPD`:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
ulimit -HS -r 50; mpd
|
||||
ulimit -HS -r 40; mpd
|
||||
|
||||
Or you can use the :command:`prlimit` program from the util-linux package:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
prlimit --rtprio=50 --rttime=unlimited mpd
|
||||
prlimit --rtprio=40 --rttime=unlimited mpd
|
||||
|
||||
The systemd service file shipped with :program:`MPD` comes with this setting.
|
||||
|
||||
@@ -796,10 +805,10 @@ You can verify whether the real-time scheduler is active with the ps command:
|
||||
PID TID CLS RTPRIO COMMAND
|
||||
16257 16257 TS - mpd
|
||||
16257 16258 TS - io
|
||||
16257 16259 FF 50 rtio
|
||||
16257 16259 FF 40 rtio
|
||||
16257 16260 TS - player
|
||||
16257 16261 TS - decoder
|
||||
16257 16262 FF 50 output:ALSA
|
||||
16257 16262 FF 40 output:ALSA
|
||||
16257 16263 IDL 0 update
|
||||
|
||||
The CLS column shows the CPU scheduler; TS is the normal scheduler; FF and RR are real-time schedulers. In this example, two threads use the real-time scheduler: the output thread and the rtio (real-time I/O) thread; these two are the important ones. The database update thread uses the idle scheduler ("IDL in ps), which only gets CPU when no other process needs it.
|
||||
@@ -814,6 +823,89 @@ The CLS column shows the CPU scheduler; TS is the normal scheduler; FF and RR ar
|
||||
Using MPD
|
||||
*********
|
||||
|
||||
Starting and Stopping MPD
|
||||
-------------------------
|
||||
|
||||
The simplest (but not the best) way to start :program:`MPD` is to
|
||||
simply type::
|
||||
|
||||
mpd
|
||||
|
||||
This will start :program:`MPD` as a daemon process (which means it
|
||||
detaches from your terminal and continues to run in background). To
|
||||
stop it, send ``SIGTERM`` to the process; if you have configured a
|
||||
``pid_file``, you can use the ``--kill`` option::
|
||||
|
||||
mpd --kill
|
||||
|
||||
The best way to manage :program:`MPD` processes is to use a service
|
||||
manager such as :program:`systemd`.
|
||||
|
||||
systemd
|
||||
^^^^^^^
|
||||
|
||||
:program:`MPD` ships with :program:`systemd` service units.
|
||||
|
||||
If you have installed :program:`MPD` with your operating system's
|
||||
package manager, these are probably preinstalled, so you can start and
|
||||
stop :program:`MPD` this way (like any other service)::
|
||||
|
||||
systemctl start mpd
|
||||
systemctl stop mpd
|
||||
|
||||
systemd socket activation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Using systemd, you can launch :program:`MPD` on demand when the first client attempts to connect.
|
||||
|
||||
:program:`MPD` comes with two systemd unit files: a "service" unit and
|
||||
a "socket" unit. These will be installed to the directory specified
|
||||
with :code:`-Dsystemd_system_unit_dir=...`,
|
||||
e.g. :file:`/lib/systemd/system`.
|
||||
|
||||
To enable socket activation, type:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl enable mpd.socket
|
||||
systemctl start mpd.socket
|
||||
|
||||
In this configuration, :program:`MPD` will ignore the :ref:`listener
|
||||
settings <listeners>` (``bind_to_address`` and ``port``).
|
||||
|
||||
systemd user unit
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can launch :program:`MPD` as a systemd user unit. These will be
|
||||
installed to the directory specified with
|
||||
:code:`-Dsystemd_user_unit_dir=...`,
|
||||
e.g. :file:`/usr/lib/systemd/user` or
|
||||
:file:`$HOME/.local/share/systemd/user`.
|
||||
|
||||
Once the user unit is installed, you can start and stop :program:`MPD` like any other service:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl --user start mpd
|
||||
|
||||
To auto-start :program:`MPD` upon login, type:
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
systemctl --user enable mpd
|
||||
|
||||
.. _signals:
|
||||
|
||||
Signals
|
||||
-------
|
||||
|
||||
:program:`MPD` understands the following UNIX signals:
|
||||
|
||||
- ``SIGTERM``, ``SIGINT``: shut down MPD
|
||||
- ``SIGHUP``: reopen log files (send this after log rotation) and
|
||||
flush caches (see :ref:`input_cache`)
|
||||
|
||||
|
||||
The client
|
||||
----------
|
||||
|
||||
@@ -953,6 +1045,22 @@ is no way for :program:`MPD` to find out whether the DAC supports
|
||||
it. DSD to PCM conversion is the fallback if DSD cannot be used
|
||||
directly.
|
||||
|
||||
ICY-MetaData
|
||||
------------
|
||||
|
||||
Some MP3 streams send information about the current song with a
|
||||
protocol named `"ICY-MetaData"
|
||||
<http://www.smackfu.com/stuff/programming/shoutcast.html>`_.
|
||||
:program:`MPD` makes its ``StreamTitle`` value available as ``Title``
|
||||
tag.
|
||||
|
||||
By default, :program:`MPD` assumes this tag is UTF-8-encoded. To tell
|
||||
:program:`MPD` to assume a different character set, specify it in the
|
||||
``charset`` URL fragment parameter, e.g.::
|
||||
|
||||
mpc add 'http://radio.example.com/stream#charset=cp1251'
|
||||
|
||||
|
||||
Client Hacks
|
||||
************
|
||||
|
||||
@@ -977,7 +1085,7 @@ Sometimes, it is helpful to run :program:`MPD` in a terminal and follow what hap
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
mpd --stdout --no-daemon --verbose
|
||||
mpd --stderr --no-daemon --verbose
|
||||
|
||||
Support
|
||||
-------
|
||||
@@ -990,34 +1098,66 @@ The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an I
|
||||
Common Problems
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
1. Database
|
||||
"""""""""""
|
||||
Startup
|
||||
"""""""
|
||||
|
||||
Question: I can't see my music in the MPD database!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Error "could not get realtime scheduling"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
See :ref:`realtime`. You can safely ignore this, but you won't
|
||||
benefit from real-time scheduling. This only makes a difference if
|
||||
your computer runs programs other than MPD.
|
||||
|
||||
Error "Failed to initialize io_uring"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Linux specific: the io_uring subsystem could not be initialized. This
|
||||
is not a critical error - MPD will fall back to "classic" blocking
|
||||
disk I/O. You can safely ignore this error, but you won't benefit
|
||||
from io_uring's advantages.
|
||||
|
||||
* "Cannot allocate memory" usually means that your memlock limit
|
||||
(``ulimit -l`` in bash or ``LimitMEMLOCK`` in systemd) is too low.
|
||||
64 MB is a reasonable value for this limit.
|
||||
* Your Linux kernel might be too old and does not support io_uring.
|
||||
|
||||
Error "bind to '0.0.0.0:6600' failed (continuing anyway, because binding to '[::]:6600' succeeded)"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This happens on Linux when :file:`/proc/sys/net/ipv6/bindv6only` is
|
||||
disabled. MPD first binds to IPv6, and this automatically binds to
|
||||
IPv4 as well; after that, MPD binds to IPv4, but that fails. You can
|
||||
safely ignore this, because MPD works on both IPv4 and IPv6.
|
||||
|
||||
|
||||
Database
|
||||
""""""""
|
||||
|
||||
I can't see my music in the MPD database
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Check your :code:`music_directory` setting.
|
||||
* Does the MPD user have read permission on all music files, and read+execute permission on all music directories (and all of their parent directories)?
|
||||
* Did you update the database? (mpc update)
|
||||
* Did you enable all relevant decoder plugins at compile time? :command:`mpd --version` will tell you.
|
||||
|
||||
Question: MPD doesn't read ID3 tags!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
MPD doesn't read ID3 tags!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* You probably compiled :program:`MPD` without libid3tag. :command:`mpd --version` will tell you.
|
||||
|
||||
2. Playback
|
||||
"""""""""""
|
||||
Playback
|
||||
""""""""
|
||||
|
||||
Question: I can't hear music on my client!
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
I can't hear music on my client
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* That problem usually follows a misunderstanding of the nature of :program:`MPD`. :program:`MPD` is a remote-controlled music player, not a music distribution system. Usually, the speakers are connected to the box where :program:`MPD` runs, and the :program:`MPD` client only sends control commands, but the client does not actually play your music.
|
||||
|
||||
:program:`MPD` has output plugins which allow hearing music on a remote host (such as httpd), but that is not :program:`MPD`'s primary design goal.
|
||||
|
||||
Question: "Device or resource busy"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Error "Device or resource busy"
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* This ALSA error means that another program uses your sound hardware exclusively. You can stop that program to allow :program:`MPD` to use it.
|
||||
|
||||
@@ -1057,7 +1197,7 @@ You can extract the backtrace from a core dump, or by running :program:`MPD` in
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
gdb --args mpd --stdout --no-daemon --verbose
|
||||
gdb --args mpd --stderr --no-daemon --verbose
|
||||
run
|
||||
|
||||
As soon as you have reproduced the crash, type ":command:`bt`" on the
|
||||
|
132
meson.build
132
meson.build
@@ -1,11 +1,18 @@
|
||||
project(
|
||||
'mpd',
|
||||
['c', 'cpp'],
|
||||
version: '0.21.23',
|
||||
version: '0.22.1',
|
||||
meson_version: '>= 0.49.0',
|
||||
default_options: [
|
||||
'c_std=c99',
|
||||
'cpp_std=c++14'
|
||||
'build.c_std=c99',
|
||||
'cpp_std=c++17',
|
||||
'build.cpp_std=c++17',
|
||||
'warning_level=3',
|
||||
|
||||
# This is only here to build subprojects as static libraries; MPD
|
||||
# itself doesn't ship any libraries.
|
||||
'default_library=static',
|
||||
],
|
||||
license: 'GPLv2+',
|
||||
)
|
||||
@@ -15,18 +22,20 @@ version_cxx = vcs_tag(input: 'src/GitVersion.cxx', output: 'GitVersion.cxx')
|
||||
compiler = meson.get_compiler('cpp')
|
||||
c_compiler = meson.get_compiler('c')
|
||||
|
||||
if compiler.get_id() == 'gcc' and compiler.version().version_compare('<6')
|
||||
warning('Your GCC version is too old. You need at least version 6.')
|
||||
elif compiler.get_id() == 'clang' and compiler.version().version_compare('<3')
|
||||
warning('Your clang version is too old. You need at least version 3.')
|
||||
if compiler.get_id() == 'gcc' and compiler.version().version_compare('<8')
|
||||
warning('Your GCC version is too old. You need at least version 8.')
|
||||
elif compiler.get_id() == 'clang' and compiler.version().version_compare('<5')
|
||||
warning('Your clang version is too old. You need at least version 5.')
|
||||
endif
|
||||
|
||||
version_conf = configuration_data()
|
||||
version_conf.set_quoted('PACKAGE', meson.project_name())
|
||||
version_conf.set_quoted('PACKAGE_NAME', meson.project_name())
|
||||
version_conf.set_quoted('VERSION', meson.project_version())
|
||||
version_conf.set_quoted('PROTOCOL_VERSION', '0.22.0')
|
||||
configure_file(output: 'Version.h', configuration: version_conf)
|
||||
|
||||
conf = configuration_data()
|
||||
conf.set_quoted('PACKAGE', meson.project_name())
|
||||
conf.set_quoted('PACKAGE_NAME', meson.project_name())
|
||||
conf.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
conf.set_quoted('VERSION', meson.project_version())
|
||||
conf.set_quoted('PROTOCOL_VERSION', '0.21.11')
|
||||
conf.set_quoted('SYSTEM_CONFIG_FILE_LOCATION', join_paths(get_option('prefix'), get_option('sysconfdir'), 'mpd.conf'))
|
||||
|
||||
common_cppflags = [
|
||||
@@ -40,8 +49,8 @@ common_cxxflags = [
|
||||
]
|
||||
|
||||
test_common_flags = [
|
||||
'-Wall',
|
||||
'-Wextra',
|
||||
'-Wvla',
|
||||
'-Wdouble-promotion',
|
||||
|
||||
'-fvisibility=hidden',
|
||||
|
||||
@@ -59,13 +68,15 @@ test_cxxflags = test_common_flags + [
|
||||
'-Wcast-qual',
|
||||
'-Wwrite-strings',
|
||||
'-Wsign-compare',
|
||||
'-Wcomma',
|
||||
'-Wextra-semi',
|
||||
'-Wheader-hygiene',
|
||||
'-Winconsistent-missing-destructor-override',
|
||||
'-Wunreachable-code-break',
|
||||
'-Wunused',
|
||||
'-Wused-but-marked-unused',
|
||||
|
||||
'-Wno-non-virtual-dtor',
|
||||
|
||||
# work around bogus GCC7 warning "mangled name for ... will change
|
||||
# in C++17 because the exception specification is part of a function
|
||||
# type"
|
||||
'-Wno-noexcept-type',
|
||||
]
|
||||
|
||||
if compiler.get_id() == 'clang'
|
||||
@@ -101,6 +112,13 @@ if get_option('buildtype') != 'debug'
|
||||
]
|
||||
endif
|
||||
|
||||
if get_option('fuzzer')
|
||||
fuzzer_flags = ['-fsanitize=fuzzer,address,undefined']
|
||||
add_global_arguments(fuzzer_flags, language: 'cpp')
|
||||
add_global_arguments(fuzzer_flags, language: 'c')
|
||||
add_global_link_arguments(fuzzer_flags, language: 'cpp')
|
||||
endif
|
||||
|
||||
add_global_arguments(common_cxxflags + compiler.get_supported_arguments(test_cxxflags), language: 'cpp')
|
||||
add_global_arguments(common_cflags + c_compiler.get_supported_arguments(test_cflags), language: 'c')
|
||||
add_global_link_arguments(compiler.get_supported_link_arguments(test_ldflags), language: 'cpp')
|
||||
@@ -136,13 +154,17 @@ add_global_arguments(common_cppflags, language: 'cpp')
|
||||
enable_daemon = not is_windows and not is_android and get_option('daemon')
|
||||
conf.set('ENABLE_DAEMON', enable_daemon)
|
||||
|
||||
conf.set('HAVE_LOCALE_H', compiler.has_header('locale.h'))
|
||||
|
||||
conf.set('HAVE_GETPWNAM_R', compiler.has_function('getpwnam_r'))
|
||||
conf.set('HAVE_GETPWUID_R', compiler.has_function('getpwuid_r'))
|
||||
conf.set('HAVE_INITGROUPS', compiler.has_function('initgroups'))
|
||||
conf.set('HAVE_FNMATCH', compiler.has_function('fnmatch'))
|
||||
conf.set('HAVE_STRNDUP', compiler.has_function('strndup', prefix: '#define _GNU_SOURCE\n#include <string.h>'))
|
||||
|
||||
# Explicitly exclude Windows in this check because
|
||||
# https://github.com/mesonbuild/meson/issues/3672 (reported in 2018,
|
||||
# still not fixed in 2020) causes Meson to believe it exists, because
|
||||
# __builtin_strndup() exists (but strndup() still cannot be used).
|
||||
conf.set('HAVE_STRNDUP', not is_windows and compiler.has_function('strndup', prefix: '#define _GNU_SOURCE\n#include <string.h>'))
|
||||
|
||||
conf.set('HAVE_STRCASESTR', compiler.has_function('strcasestr'))
|
||||
|
||||
conf.set('HAVE_PRCTL', is_linux)
|
||||
@@ -188,6 +210,17 @@ if boost_dep.version() == '1.67'
|
||||
warning('Your Boost version 1.67 is known to be buggy, and the MPD build will fail. Please upgrade to Boost 1.68 or later.')
|
||||
endif
|
||||
|
||||
log = static_library(
|
||||
'log',
|
||||
'src/Log.cxx',
|
||||
'src/LogBackend.cxx',
|
||||
include_directories: inc,
|
||||
)
|
||||
|
||||
log_dep = declare_dependency(
|
||||
link_with: log,
|
||||
)
|
||||
|
||||
sources = [
|
||||
version_cxx,
|
||||
'src/Main.cxx',
|
||||
@@ -216,23 +249,23 @@ sources = [
|
||||
'src/decoder/DecoderPrint.cxx',
|
||||
'src/client/Listener.cxx',
|
||||
'src/client/Client.cxx',
|
||||
'src/client/ClientEvent.cxx',
|
||||
'src/client/ClientExpire.cxx',
|
||||
'src/client/ClientGlobal.cxx',
|
||||
'src/client/ClientIdle.cxx',
|
||||
'src/client/ClientList.cxx',
|
||||
'src/client/ClientNew.cxx',
|
||||
'src/client/ClientProcess.cxx',
|
||||
'src/client/ClientRead.cxx',
|
||||
'src/client/ClientWrite.cxx',
|
||||
'src/client/ClientMessage.cxx',
|
||||
'src/client/ClientSubscribe.cxx',
|
||||
'src/client/ClientFile.cxx',
|
||||
'src/client/Config.cxx',
|
||||
'src/client/Domain.cxx',
|
||||
'src/client/Event.cxx',
|
||||
'src/client/Expire.cxx',
|
||||
'src/client/Idle.cxx',
|
||||
'src/client/List.cxx',
|
||||
'src/client/New.cxx',
|
||||
'src/client/Process.cxx',
|
||||
'src/client/Read.cxx',
|
||||
'src/client/Write.cxx',
|
||||
'src/client/Message.cxx',
|
||||
'src/client/Subscribe.cxx',
|
||||
'src/client/File.cxx',
|
||||
'src/client/Response.cxx',
|
||||
'src/client/ThreadBackgroundCommand.cxx',
|
||||
'src/Listen.cxx',
|
||||
'src/LogInit.cxx',
|
||||
'src/LogBackend.cxx',
|
||||
'src/Log.cxx',
|
||||
'src/ls.cxx',
|
||||
'src/Instance.cxx',
|
||||
'src/win32/Win32Main.cxx',
|
||||
@@ -277,6 +310,7 @@ sources = [
|
||||
'src/TagSave.cxx',
|
||||
'src/TagFile.cxx',
|
||||
'src/TagStream.cxx',
|
||||
'src/TagAny.cxx',
|
||||
'src/TimePrint.cxx',
|
||||
'src/mixer/Volume.cxx',
|
||||
'src/PlaylistFile.cxx',
|
||||
@@ -310,17 +344,22 @@ endif
|
||||
|
||||
subdir('src/util')
|
||||
subdir('src/time')
|
||||
subdir('src/io')
|
||||
subdir('src/io/uring')
|
||||
subdir('src/system')
|
||||
subdir('src/thread')
|
||||
subdir('src/net')
|
||||
subdir('src/event')
|
||||
|
||||
subdir('src/apple')
|
||||
|
||||
subdir('src/lib/dbus')
|
||||
subdir('src/lib/icu')
|
||||
subdir('src/lib/smbclient')
|
||||
subdir('src/lib/zlib')
|
||||
|
||||
subdir('src/lib/alsa')
|
||||
subdir('src/lib/chromaprint')
|
||||
subdir('src/lib/curl')
|
||||
subdir('src/lib/expat')
|
||||
subdir('src/lib/ffmpeg')
|
||||
@@ -335,6 +374,8 @@ subdir('src/lib/systemd')
|
||||
subdir('src/lib/upnp')
|
||||
subdir('src/lib/yajl')
|
||||
|
||||
subdir('src/lib/crypto')
|
||||
|
||||
subdir('src/fs')
|
||||
subdir('src/config')
|
||||
subdir('src/tag')
|
||||
@@ -359,12 +400,19 @@ endif
|
||||
if sqlite_dep.found()
|
||||
sources += [
|
||||
'src/command/StickerCommands.cxx',
|
||||
'src/sticker/StickerDatabase.cxx',
|
||||
'src/sticker/StickerPrint.cxx',
|
||||
'src/sticker/Database.cxx',
|
||||
'src/sticker/Print.cxx',
|
||||
'src/sticker/SongSticker.cxx',
|
||||
]
|
||||
endif
|
||||
|
||||
if chromaprint_dep.found()
|
||||
sources += [
|
||||
'src/command/FingerprintCommands.cxx',
|
||||
'src/lib/chromaprint/DecoderClient.cxx',
|
||||
]
|
||||
endif
|
||||
|
||||
basic = static_library(
|
||||
'basic',
|
||||
'src/ReplayGainInfo.cxx',
|
||||
@@ -458,8 +506,10 @@ mpd = build_target(
|
||||
sqlite_dep,
|
||||
zeroconf_dep,
|
||||
more_deps,
|
||||
chromaprint_dep,
|
||||
],
|
||||
link_args: link_args,
|
||||
build_by_default: not get_option('fuzzer'),
|
||||
install: not is_android and not is_haiku,
|
||||
)
|
||||
|
||||
@@ -495,10 +545,12 @@ install_data(
|
||||
install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()),
|
||||
)
|
||||
|
||||
if get_option('documentation')
|
||||
subdir('doc')
|
||||
endif
|
||||
subdir('doc')
|
||||
|
||||
if get_option('test')
|
||||
subdir('test')
|
||||
endif
|
||||
|
||||
if get_option('fuzzer')
|
||||
subdir('test/fuzzer')
|
||||
endif
|
||||
|
@@ -1,9 +1,10 @@
|
||||
option('documentation', type: 'boolean', value: false, description: 'Build documentation')
|
||||
|
||||
option('test', type: 'boolean', value: false, description: 'Build the unit tests and debug programs')
|
||||
option('documentation', type: 'feature', description: 'Build documentation')
|
||||
option('html_manual', type: 'boolean', value: true, description: 'Build the HTML manual')
|
||||
option('manpages', type: 'boolean', value: true, description: 'Build manual pages')
|
||||
|
||||
option('syslog', type: 'feature', description: 'syslog support')
|
||||
option('inotify', type: 'boolean', value: true, description: 'inotify support (for automatic database update)')
|
||||
option('io_uring', type: 'feature', description: 'Linux io_uring support using liburing')
|
||||
|
||||
option('daemon', type: 'boolean', value: true, description: 'enable daemonization')
|
||||
option('systemd', type: 'feature', description: 'systemd support')
|
||||
@@ -11,6 +12,13 @@ option('systemd', type: 'feature', description: 'systemd support')
|
||||
option('systemd_system_unit_dir', type: 'string', description: 'systemd system service directory')
|
||||
option('systemd_user_unit_dir', type: 'string', description: 'systemd user service directory')
|
||||
|
||||
#
|
||||
# Options for developers
|
||||
#
|
||||
|
||||
option('test', type: 'boolean', value: false, description: 'Build the unit tests and debug programs')
|
||||
option('fuzzer', type: 'boolean', value: false, description: 'Build fuzzers (requires libFuzzer)')
|
||||
|
||||
#
|
||||
# Android
|
||||
#
|
||||
|
45
python/build/cmake.py
Normal file
45
python/build/cmake.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
def configure(toolchain, src, build, args=()):
|
||||
cross_args = []
|
||||
|
||||
if toolchain.is_windows:
|
||||
cross_args.append('-DCMAKE_SYSTEM_NAME=Windows')
|
||||
cross_args.append('-DCMAKE_RC_COMPILER=' + toolchain.windres)
|
||||
|
||||
configure = [
|
||||
'cmake',
|
||||
src,
|
||||
|
||||
'-DCMAKE_INSTALL_PREFIX=' + toolchain.install_prefix,
|
||||
'-DCMAKE_BUILD_TYPE=release',
|
||||
|
||||
'-DCMAKE_C_COMPILER=' + toolchain.cc,
|
||||
'-DCMAKE_CXX_COMPILER=' + toolchain.cxx,
|
||||
|
||||
'-DCMAKE_C_FLAGS=' + toolchain.cflags + ' ' + toolchain.cppflags,
|
||||
'-DCMAKE_CXX_FLAGS=' + toolchain.cxxflags + ' ' + toolchain.cppflags,
|
||||
|
||||
'-GNinja',
|
||||
] + cross_args + args
|
||||
|
||||
subprocess.check_call(configure, env=toolchain.env, cwd=build)
|
||||
|
||||
class CmakeProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
|
||||
def configure(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
build = self.make_build_path(toolchain)
|
||||
configure(toolchain, src, build, self.configure_args)
|
||||
return build
|
||||
|
||||
def build(self, toolchain):
|
||||
build = self.configure(toolchain)
|
||||
subprocess.check_call(['ninja', 'install'],
|
||||
cwd=build, env=toolchain.env)
|
@@ -4,13 +4,14 @@ from os.path import abspath
|
||||
from build.project import Project
|
||||
from build.zlib import ZlibProject
|
||||
from build.meson import MesonProject
|
||||
from build.cmake import CmakeProject
|
||||
from build.autotools import AutotoolsProject
|
||||
from build.ffmpeg import FfmpegProject
|
||||
from build.boost import BoostProject
|
||||
|
||||
libmpdclient = MesonProject(
|
||||
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.18.tar.xz',
|
||||
'4cb01e1f567e0169aca94875fb6e1200e7f5ce35b63a4df768ec1591fb1081fa',
|
||||
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.19.tar.xz',
|
||||
'158aad4c2278ab08e76a3f2b0166c99b39fae00ee17231bd225c5a36e977a189',
|
||||
'lib/libmpdclient.a',
|
||||
)
|
||||
|
||||
@@ -24,8 +25,8 @@ libogg = AutotoolsProject(
|
||||
)
|
||||
|
||||
libvorbis = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.xz',
|
||||
'af00bb5a784e7c9e69f56823de4637c350643deedaf333d0fa86ecdba6fcb415',
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz',
|
||||
'b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b',
|
||||
'lib/libvorbis.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -111,9 +112,44 @@ liblame = AutotoolsProject(
|
||||
],
|
||||
)
|
||||
|
||||
libmodplug = AutotoolsProject(
|
||||
'https://downloads.sourceforge.net/modplug-xmms/libmodplug/0.8.9.0/libmodplug-0.8.9.0.tar.gz',
|
||||
'457ca5a6c179656d66c01505c0d95fafaead4329b9dbaa0f997d00a3508ad9de',
|
||||
'lib/libmodplug.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
],
|
||||
)
|
||||
|
||||
wildmidi = CmakeProject(
|
||||
'https://codeload.github.com/Mindwerks/wildmidi/tar.gz/wildmidi-0.4.3',
|
||||
'498e5a96455bb4b91b37188ad6dcb070824e92c44f5ed452b90adbaec8eef3c5',
|
||||
'lib/libWildMidi.a',
|
||||
[
|
||||
'-DBUILD_SHARED_LIBS=OFF',
|
||||
'-DWANT_PLAYER=OFF',
|
||||
'-DWANT_STATIC=ON',
|
||||
],
|
||||
base='wildmidi-wildmidi-0.4.3',
|
||||
name='wildmidi',
|
||||
version='0.4.3',
|
||||
)
|
||||
|
||||
gme = CmakeProject(
|
||||
'https://bitbucket.org/mpyne/game-music-emu/downloads/game-music-emu-0.6.3.tar.xz',
|
||||
'aba34e53ef0ec6a34b58b84e28bf8cfbccee6585cebca25333604c35db3e051d',
|
||||
'lib/libgme.a',
|
||||
[
|
||||
'-DBUILD_SHARED_LIBS=OFF',
|
||||
'-DENABLE_UBSAN=OFF',
|
||||
'-DZLIB_INCLUDE_DIR=OFF',
|
||||
'-DSDL2_DIR=OFF',
|
||||
],
|
||||
)
|
||||
|
||||
ffmpeg = FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-4.2.2.tar.xz',
|
||||
'cb754255ab0ee2ea5f66f8850e1bd6ad5cac1cd855d0a2f4990fb8c668b0d29c',
|
||||
'http://ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz',
|
||||
'ad009240d46e307b4e03a213a0f49c11b650e445b1f8be0dda2a9212b34d2ffb',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -341,8 +377,8 @@ ffmpeg = FfmpegProject(
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.69.1.tar.xz',
|
||||
'03c7d5e6697f7b7e40ada1b2256e565a555657398e6c1fcfa4cb251ccd819d4f',
|
||||
'http://curl.haxx.se/download/curl-7.73.0.tar.xz',
|
||||
'7c4c7ca4ea88abe00fea4740dcf81075c031b1d0bb23aff2d5efde20a3c2408a',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -393,11 +429,12 @@ libnfs = AutotoolsProject(
|
||||
'--disable-utils', '--disable-examples',
|
||||
],
|
||||
base='libnfs-libnfs-4.0.0',
|
||||
patches='src/lib/nfs/patches',
|
||||
autoreconf=True,
|
||||
)
|
||||
|
||||
boost = BoostProject(
|
||||
'https://dl.bintray.com/boostorg/release/1.72.0/source/boost_1_72_0.tar.bz2',
|
||||
'59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722',
|
||||
'https://dl.bintray.com/boostorg/release/1.74.0/source/boost_1_74_0.tar.bz2',
|
||||
'83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1',
|
||||
'include/boost/version.hpp',
|
||||
)
|
||||
|
@@ -91,7 +91,12 @@ def configure(toolchain, src, build, args=()):
|
||||
'--cross-file', cross_file,
|
||||
] + args
|
||||
|
||||
subprocess.check_call(configure, env=toolchain.env)
|
||||
env = toolchain.env.copy()
|
||||
|
||||
# Meson 0.54 requires the BOOST_ROOT environment variable
|
||||
env['BOOST_ROOT'] = toolchain.install_prefix
|
||||
|
||||
subprocess.check_call(configure, env=env)
|
||||
|
||||
class MesonProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
|
@@ -7,5 +7,11 @@ def untar(tarball_path, parent_path, base):
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(parent_path, exist_ok=True)
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
|
||||
try:
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
|
||||
except FileNotFoundError:
|
||||
import tarfile
|
||||
tar = tarfile.open(tarball_path)
|
||||
tar.extractall(path=parent_path)
|
||||
tar.close()
|
||||
return path
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -95,7 +95,7 @@ public:
|
||||
|
||||
constexpr double ToDoubleS() const {
|
||||
return double(count()) / 1000.;
|
||||
};
|
||||
}
|
||||
|
||||
constexpr bool IsZero() const {
|
||||
return count() == 0;
|
||||
@@ -199,7 +199,7 @@ public:
|
||||
|
||||
constexpr double ToDoubleS() const {
|
||||
return double(count()) / 1000.;
|
||||
};
|
||||
}
|
||||
|
||||
constexpr bool IsZero() const {
|
||||
return count() == 0;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -37,11 +37,15 @@
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/StandardDirectory.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "io/uring/Features.h"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/OptionDef.hxx"
|
||||
#include "util/OptionParser.hxx"
|
||||
#include "Version.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "system/Error.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "db/Registry.hxx"
|
||||
@@ -55,6 +59,7 @@
|
||||
#include "neighbor/NeighborPlugin.hxx"
|
||||
#endif
|
||||
|
||||
#include "encoder/Features.h"
|
||||
#ifdef ENABLE_ENCODER
|
||||
#include "encoder/EncoderList.hxx"
|
||||
#include "encoder/EncoderPlugin.hxx"
|
||||
@@ -65,9 +70,6 @@
|
||||
#include "archive/ArchivePlugin.hxx"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace {
|
||||
#ifdef _WIN32
|
||||
constexpr auto CONFIG_FILE_LOCATION = Path::FromFS(PATH_LITERAL("mpd\\mpd.conf"));
|
||||
@@ -77,7 +79,7 @@ constexpr auto USER_CONFIG_FILE_LOCATION1 = Path::FromFS(PATH_LITERAL(".mpdconf"
|
||||
constexpr auto USER_CONFIG_FILE_LOCATION2 = Path::FromFS(PATH_LITERAL(".mpd/mpd.conf"));
|
||||
constexpr auto USER_CONFIG_FILE_LOCATION_XDG = Path::FromFS(PATH_LITERAL("mpd/mpd.conf"));
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
enum Option {
|
||||
OPTION_KILL,
|
||||
@@ -105,8 +107,8 @@ static constexpr OptionDef option_defs[] = {
|
||||
|
||||
static constexpr Domain cmdline_domain("cmdline");
|
||||
|
||||
gcc_noreturn
|
||||
static void version(void)
|
||||
[[noreturn]]
|
||||
static void version()
|
||||
{
|
||||
printf("Music Player Daemon " VERSION " (%s)"
|
||||
"\n"
|
||||
@@ -145,15 +147,19 @@ static void version(void)
|
||||
"Decoders plugins:\n");
|
||||
|
||||
decoder_plugins_for_each([](const DecoderPlugin &plugin){
|
||||
printf(" [%s]", plugin.name);
|
||||
printf(" [%s]", plugin.name);
|
||||
|
||||
const char *const*suffixes = plugin.suffixes;
|
||||
if (suffixes != nullptr)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
const char *const*suffixes = plugin.suffixes;
|
||||
if (suffixes != nullptr)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
|
||||
printf("\n");
|
||||
});
|
||||
if (plugin.protocols != nullptr)
|
||||
for (const auto &i : plugin.protocols())
|
||||
printf(" %s", i.c_str());
|
||||
|
||||
printf("\n");
|
||||
});
|
||||
|
||||
printf("\n"
|
||||
"Filters:\n"
|
||||
@@ -202,6 +208,9 @@ static void version(void)
|
||||
"\n"
|
||||
"Input plugins:\n"
|
||||
" file"
|
||||
#ifdef HAVE_URING
|
||||
" io_uring"
|
||||
#endif
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
" archive"
|
||||
#endif
|
||||
@@ -255,7 +264,7 @@ static void version(void)
|
||||
#endif
|
||||
"\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void PrintOption(const OptionDef &opt)
|
||||
@@ -271,8 +280,8 @@ static void PrintOption(const OptionDef &opt)
|
||||
opt.GetDescription());
|
||||
}
|
||||
|
||||
gcc_noreturn
|
||||
static void help(void)
|
||||
[[noreturn]]
|
||||
static void help()
|
||||
{
|
||||
printf("Usage:\n"
|
||||
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
||||
@@ -282,10 +291,10 @@ static void help(void)
|
||||
"Options:\n");
|
||||
|
||||
for (const auto &i : option_defs)
|
||||
if(i.HasDescription() == true) // hide hidden options from help print
|
||||
if(i.HasDescription()) // hide hidden options from help print
|
||||
PrintOption(i);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
std::exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
class ConfigLoader
|
||||
@@ -296,7 +305,7 @@ public:
|
||||
explicit ConfigLoader(ConfigData &_config) noexcept
|
||||
:config(_config) {}
|
||||
|
||||
bool TryFile(const Path path);
|
||||
bool TryFile(Path path);
|
||||
bool TryFile(const AllocatedPath &base_path, Path path);
|
||||
};
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,4 +19,4 @@
|
||||
|
||||
#include "GitVersion.hxx"
|
||||
|
||||
char GIT_VERSION[] = "@VCS_TAG@";
|
||||
const char GIT_VERSION[] = "@VCS_TAG@";
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,6 +20,6 @@
|
||||
#ifndef MPD_GIT_VERSION_HXX
|
||||
#define MPD_GIT_VERSION_HXX
|
||||
|
||||
extern char GIT_VERSION[];
|
||||
extern const char GIT_VERSION[];
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -18,16 +18,24 @@
|
||||
*/
|
||||
|
||||
#include "IcyMetaDataParser.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "tag/Builder.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/AllocatedString.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static constexpr Domain icy_metadata_domain("icy_metadata");
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
|
||||
void
|
||||
IcyMetaDataParser::SetCharset(const char *charset)
|
||||
{
|
||||
icu_converter = IcuConverter::Create(charset);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
IcyMetaDataParser::Reset() noexcept
|
||||
@@ -65,29 +73,40 @@ IcyMetaDataParser::Data(size_t length) noexcept
|
||||
}
|
||||
|
||||
static void
|
||||
icy_add_item(TagBuilder &tag, TagType type, const char *value) noexcept
|
||||
icy_add_item(TagBuilder &tag, TagType type, StringView value) noexcept
|
||||
{
|
||||
size_t length = strlen(value);
|
||||
|
||||
if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') {
|
||||
if (value.size >= 2 && value.front() == '\'' && value.back() == '\'') {
|
||||
/* strip the single quotes */
|
||||
++value;
|
||||
length -= 2;
|
||||
++value.data;
|
||||
value.size -= 2;
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
tag.AddItem(type, {value, length});
|
||||
if (value.size > 0)
|
||||
tag.AddItem(type, value);
|
||||
}
|
||||
|
||||
static void
|
||||
icy_parse_tag_item(TagBuilder &tag,
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
const IcuConverter *icu_converter,
|
||||
#endif
|
||||
const char *name, const char *value) noexcept
|
||||
{
|
||||
if (strcmp(name, "StreamTitle") == 0)
|
||||
if (strcmp(name, "StreamTitle") == 0) {
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
if (icu_converter != nullptr) {
|
||||
try {
|
||||
icy_add_item(tag, TAG_TITLE,
|
||||
icu_converter->ToUTF8(value).c_str());
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
icy_add_item(tag, TAG_TITLE, value);
|
||||
else
|
||||
FormatDebug(icy_metadata_domain,
|
||||
"unknown icy-tag: '%s'", name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -116,7 +135,11 @@ find_end_quote(char *p, char *const end) noexcept
|
||||
}
|
||||
|
||||
static std::unique_ptr<Tag>
|
||||
icy_parse_tag(char *p, char *const end) noexcept
|
||||
icy_parse_tag(
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
const IcuConverter *icu_converter,
|
||||
#endif
|
||||
char *p, char *const end) noexcept
|
||||
{
|
||||
assert(p != nullptr);
|
||||
assert(end != nullptr);
|
||||
@@ -153,7 +176,11 @@ icy_parse_tag(char *p, char *const end) noexcept
|
||||
*quote = 0;
|
||||
p = quote + 1;
|
||||
|
||||
icy_parse_tag_item(tag, name, value);
|
||||
icy_parse_tag_item(tag,
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
icu_converter,
|
||||
#endif
|
||||
name, value);
|
||||
|
||||
char *semicolon = std::find(p, end, ';');
|
||||
if (semicolon == end)
|
||||
@@ -167,7 +194,7 @@ icy_parse_tag(char *p, char *const end) noexcept
|
||||
size_t
|
||||
IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *)data;
|
||||
const auto *p = (const unsigned char *)data;
|
||||
|
||||
assert(IsDefined());
|
||||
assert(data_rest == 0);
|
||||
@@ -208,7 +235,11 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
||||
if (meta_position == meta_size) {
|
||||
/* parse */
|
||||
|
||||
tag = icy_parse_tag(meta_data, meta_data + meta_size);
|
||||
tag = icy_parse_tag(
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
icu_converter.get(),
|
||||
#endif
|
||||
meta_data, meta_data + meta_size);
|
||||
delete[] meta_data;
|
||||
|
||||
/* change back to normal data mode */
|
||||
@@ -223,7 +254,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
||||
size_t
|
||||
IcyMetaDataParser::ParseInPlace(void *data, size_t length) noexcept
|
||||
{
|
||||
uint8_t *const dest0 = (uint8_t *)data;
|
||||
auto *const dest0 = (uint8_t *)data;
|
||||
uint8_t *dest = dest0;
|
||||
const uint8_t *src = dest0;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,18 +20,23 @@
|
||||
#ifndef MPD_ICY_META_DATA_PARSER_HXX
|
||||
#define MPD_ICY_META_DATA_PARSER_HXX
|
||||
|
||||
#include "lib/icu/Converter.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "config.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
class IcyMetaDataParser {
|
||||
size_t data_size = 0, data_rest;
|
||||
|
||||
size_t meta_size, meta_position;
|
||||
char *meta_data;
|
||||
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
std::unique_ptr<IcuConverter> icu_converter;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<Tag> tag;
|
||||
|
||||
public:
|
||||
@@ -39,6 +44,13 @@ public:
|
||||
Reset();
|
||||
}
|
||||
|
||||
#ifdef HAVE_ICU_CONVERTER
|
||||
/**
|
||||
* Throws on error.
|
||||
*/
|
||||
void SetCharset(const char *charset);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize an enabled icy_metadata object with the specified
|
||||
* data_size (from the icy-metaint HTTP response header).
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,12 +26,12 @@
|
||||
#include "Main.hxx"
|
||||
#include "Instance.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
void
|
||||
idle_add(unsigned flags)
|
||||
{
|
||||
assert(flags != 0);
|
||||
|
||||
instance->EmitIdle(flags);
|
||||
global_instance->EmitIdle(flags);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "IdleFlags.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
static const char *const idle_names[] = {
|
||||
"database",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,12 +20,15 @@
|
||||
#include "config.h"
|
||||
#include "Instance.hxx"
|
||||
#include "Partition.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "IdleFlags.hxx"
|
||||
#include "StateFile.hxx"
|
||||
#include "Stats.hxx"
|
||||
#include "client/List.hxx"
|
||||
#include "input/cache/Manager.hxx"
|
||||
|
||||
#ifdef ENABLE_CURL
|
||||
#include "RemoteTagCache.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/UriExtract.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
@@ -34,14 +37,16 @@
|
||||
#include "db/update/Service.hxx"
|
||||
#include "storage/StorageInterface.hxx"
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
#include "neighbor/Glue.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
#include "sticker/StickerDatabase.hxx"
|
||||
#include "sticker/Database.hxx"
|
||||
#include "sticker/SongSticker.hxx"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <exception>
|
||||
|
||||
Instance::Instance()
|
||||
:rtio_thread(true),
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
@@ -65,6 +70,13 @@ Instance::~Instance() noexcept
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnStateModified() noexcept
|
||||
{
|
||||
if (state_file)
|
||||
state_file->CheckModified();
|
||||
}
|
||||
|
||||
Partition *
|
||||
Instance::FindPartition(const char *name) noexcept
|
||||
{
|
||||
@@ -75,6 +87,20 @@ Instance::FindPartition(const char *name) noexcept
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
Instance::DeletePartition(Partition &partition) noexcept
|
||||
{
|
||||
// TODO: use boost::intrusive::list to avoid this loop
|
||||
for (auto i = partitions.begin();; ++i) {
|
||||
assert(i != partitions.end());
|
||||
|
||||
if (&*i == &partition) {
|
||||
partitions.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
const Database &
|
||||
@@ -88,7 +114,7 @@ Instance::GetDatabaseOrThrow() const
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseModified()
|
||||
Instance::OnDatabaseModified() noexcept
|
||||
{
|
||||
assert(database != nullptr);
|
||||
|
||||
@@ -101,15 +127,15 @@ Instance::OnDatabaseModified()
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseSongRemoved(const char *uri)
|
||||
Instance::OnDatabaseSongRemoved(const char *uri) noexcept
|
||||
{
|
||||
assert(database != nullptr);
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
/* if the song has a sticker, remove it */
|
||||
if (sticker_enabled()) {
|
||||
if (HasStickerDatabase()) {
|
||||
try {
|
||||
sticker_song_delete(uri);
|
||||
sticker_song_delete(*sticker_database, uri);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
@@ -124,17 +150,15 @@ Instance::OnDatabaseSongRemoved(const char *uri)
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
|
||||
void
|
||||
Instance::FoundNeighbor(gcc_unused const NeighborInfo &info) noexcept
|
||||
Instance::FoundNeighbor([[maybe_unused]] const NeighborInfo &info) noexcept
|
||||
{
|
||||
for (auto &partition : partitions)
|
||||
partition.EmitIdle(IDLE_NEIGHBOR);
|
||||
EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::LostNeighbor(gcc_unused const NeighborInfo &info) noexcept
|
||||
Instance::LostNeighbor([[maybe_unused]] const NeighborInfo &info) noexcept
|
||||
{
|
||||
for (auto &partition : partitions)
|
||||
partition.EmitIdle(IDLE_NEIGHBOR);
|
||||
EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -166,3 +190,18 @@ Instance::OnRemoteTag(const char *uri, const Tag &tag) noexcept
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
Instance::OnIdle(unsigned flags) noexcept
|
||||
{
|
||||
/* broadcast to all partitions */
|
||||
for (auto &partition : partitions)
|
||||
partition.EmitIdle(flags);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::FlushCaches() noexcept
|
||||
{
|
||||
if (input_cache)
|
||||
input_cache->Flush();
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -53,6 +53,8 @@ class ClientList;
|
||||
struct Partition;
|
||||
class StateFile;
|
||||
class RemoteTagCache;
|
||||
class StickerDatabase;
|
||||
class InputCacheManager;
|
||||
|
||||
/**
|
||||
* A utility class which, when used as the first base class, ensures
|
||||
@@ -97,10 +99,16 @@ struct Instance final
|
||||
Systemd::Watchdog systemd_watchdog;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<InputCacheManager> input_cache;
|
||||
|
||||
/**
|
||||
* Monitor for global idle events to be broadcasted to all
|
||||
* partitions.
|
||||
*/
|
||||
MaskMonitor idle_monitor;
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
NeighborGlue *neighbors;
|
||||
std::unique_ptr<NeighborGlue> neighbors;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
@@ -119,11 +127,15 @@ struct Instance final
|
||||
std::unique_ptr<RemoteTagCache> remote_tag_cache;
|
||||
#endif
|
||||
|
||||
ClientList *client_list;
|
||||
std::unique_ptr<ClientList> client_list;
|
||||
|
||||
std::list<Partition> partitions;
|
||||
|
||||
StateFile *state_file = nullptr;
|
||||
std::unique_ptr<StateFile> state_file;
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
std::unique_ptr<StickerDatabase> sticker_database;
|
||||
#endif
|
||||
|
||||
Instance();
|
||||
~Instance() noexcept;
|
||||
@@ -131,14 +143,27 @@ struct Instance final
|
||||
/**
|
||||
* Wrapper for EventLoop::Break(). Call to initiate shutdown.
|
||||
*/
|
||||
void Break() {
|
||||
void Break() noexcept {
|
||||
event_loop.Break();
|
||||
}
|
||||
|
||||
void EmitIdle(unsigned mask) {
|
||||
/**
|
||||
* Emit an "idle" event to all clients of all partitions.
|
||||
*
|
||||
* This method can be called from any thread.
|
||||
*/
|
||||
void EmitIdle(unsigned mask) noexcept {
|
||||
idle_monitor.OrMask(mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the #Instance that the state has been modified, and
|
||||
* the #StateFile may need to be saved.
|
||||
*
|
||||
* This method must be called from the main thread.
|
||||
*/
|
||||
void OnStateModified() noexcept;
|
||||
|
||||
/**
|
||||
* Find a #Partition with the given name. Returns nullptr if
|
||||
* no such partition was found.
|
||||
@@ -146,6 +171,8 @@ struct Instance final
|
||||
gcc_pure
|
||||
Partition *FindPartition(const char *name) noexcept;
|
||||
|
||||
void DeletePartition(Partition &partition) noexcept;
|
||||
|
||||
void BeginShutdownPartitions() noexcept;
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
@@ -154,7 +181,7 @@ struct Instance final
|
||||
* if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
Database *GetDatabase() {
|
||||
Database *GetDatabase() noexcept {
|
||||
return database.get();
|
||||
}
|
||||
|
||||
@@ -166,6 +193,12 @@ struct Instance final
|
||||
const Database &GetDatabaseOrThrow() const;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
bool HasStickerDatabase() noexcept {
|
||||
return sticker_database != nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BeginShutdownUpdate() noexcept;
|
||||
|
||||
#ifdef ENABLE_CURL
|
||||
@@ -176,10 +209,13 @@ struct Instance final
|
||||
}
|
||||
#endif
|
||||
|
||||
void FlushCaches() noexcept;
|
||||
|
||||
private:
|
||||
#ifdef ENABLE_DATABASE
|
||||
void OnDatabaseModified() override;
|
||||
void OnDatabaseSongRemoved(const char *uri) override;
|
||||
/* virtual methods from class DatabaseListener */
|
||||
void OnDatabaseModified() noexcept override;
|
||||
void OnDatabaseSongRemoved(const char *uri) noexcept override;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
@@ -194,7 +230,7 @@ private:
|
||||
#endif
|
||||
|
||||
/* callback for #idle_monitor */
|
||||
void OnIdle(unsigned mask);
|
||||
void OnIdle(unsigned mask) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -34,8 +34,6 @@
|
||||
#include "fs/XDG.hxx"
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
#include <systemd/sd-daemon.h>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,8 +22,8 @@
|
||||
#include "client/Client.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "ls.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/UriExtract.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
@@ -42,11 +42,13 @@ LocateFileUri(const char *uri, const Client *client
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
const auto suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix.data() != nullptr)
|
||||
/* this path was relative to the music
|
||||
directory */
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE,
|
||||
suffix.data());
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -80,9 +82,11 @@ LocateAbsoluteUri(UriPluginKind kind, const char *uri
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
const auto suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix.data() != nullptr)
|
||||
// TODO: don't use suffix.data() (ok for now because we know it's null-terminated)
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE,
|
||||
suffix.data());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,7 +21,6 @@
|
||||
#define MPD_LOCATE_URI_HXX
|
||||
|
||||
#include "config.h"
|
||||
#include "util/Compiler.h"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
109
src/Log.cxx
109
src/Log.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,162 +19,131 @@
|
||||
|
||||
#include "LogV.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/Exception.hxx"
|
||||
|
||||
#include <exception>
|
||||
#include <cerrno>
|
||||
|
||||
#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) noexcept
|
||||
LogFormatV(LogLevel level, const Domain &domain,
|
||||
const char *fmt, std::va_list ap) noexcept
|
||||
{
|
||||
char msg[1024];
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
Log(domain, level, msg);
|
||||
Log(level, domain, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogFormat(const Domain &domain, LogLevel level, const char *fmt, ...) noexcept
|
||||
LogFormat(LogLevel level, const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, level, fmt, ap);
|
||||
LogFormatV(level, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
FormatDebug(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, LogLevel::DEBUG, fmt, ap);
|
||||
LogFormatV(LogLevel::DEBUG, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, LogLevel::INFO, fmt, ap);
|
||||
LogFormatV(LogLevel::INFO, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
FormatDefault(const Domain &domain, const char *fmt, ...) noexcept
|
||||
FormatNotice(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, LogLevel::DEFAULT, fmt, ap);
|
||||
LogFormatV(LogLevel::NOTICE, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
FormatWarning(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, LogLevel::WARNING, fmt, ap);
|
||||
LogFormatV(LogLevel::WARNING, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
LogFormatV(domain, LogLevel::ERROR, fmt, ap);
|
||||
LogFormatV(LogLevel::ERROR, domain, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e) noexcept
|
||||
Log(LogLevel level, const std::exception &e) noexcept
|
||||
{
|
||||
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");
|
||||
}
|
||||
Log(level, exception_domain, GetFullMessage(e).c_str());
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e, const char *msg) noexcept
|
||||
Log(LogLevel level, const std::exception &e, const char *msg) noexcept
|
||||
{
|
||||
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");
|
||||
}
|
||||
LogFormat(level, exception_domain, "%s: %s", msg, GetFullMessage(e).c_str());
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const std::exception &e, const char *fmt, ...) noexcept
|
||||
LogFormat(LogLevel level, const std::exception &e, const char *fmt, ...) noexcept
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(e, msg);
|
||||
Log(level, e, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep) noexcept
|
||||
Log(LogLevel level, const std::exception_ptr &ep) noexcept
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized exception");
|
||||
}
|
||||
Log(level, exception_domain, GetFullMessage(ep).c_str());
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg) noexcept
|
||||
Log(LogLevel level, const std::exception_ptr &ep, const char *msg) noexcept
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e, msg);
|
||||
} catch (...) {
|
||||
FormatError(exception_domain,
|
||||
"%s: Unrecognized exception", msg);
|
||||
}
|
||||
LogFormat(level, exception_domain, "%s: %s", msg,
|
||||
GetFullMessage(ep).c_str());
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...) noexcept
|
||||
LogFormat(LogLevel level, const std::exception_ptr &ep, const char *fmt, ...) noexcept
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(ep, msg);
|
||||
Log(level, ep, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogErrno(const Domain &domain, int e, const char *msg) noexcept
|
||||
{
|
||||
LogFormat(domain, LogLevel::ERROR, "%s: %s", msg, strerror(e));
|
||||
LogFormat(LogLevel::ERROR, domain, "%s: %s", msg, strerror(e));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -184,7 +153,7 @@ LogErrno(const Domain &domain, const char *msg) noexcept
|
||||
}
|
||||
|
||||
static void
|
||||
FormatErrnoV(const Domain &domain, int e, const char *fmt, va_list ap) noexcept
|
||||
FormatErrnoV(const Domain &domain, int e, const char *fmt, std::va_list ap) noexcept
|
||||
{
|
||||
char msg[1024];
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
@@ -195,7 +164,7 @@ FormatErrnoV(const Domain &domain, int e, const char *fmt, va_list ap) noexcept
|
||||
void
|
||||
FormatErrno(const Domain &domain, int e, const char *fmt, ...) noexcept
|
||||
{
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
FormatErrnoV(domain, e, fmt, ap);
|
||||
va_end(ap);
|
||||
@@ -206,7 +175,7 @@ FormatErrno(const Domain &domain, const char *fmt, ...) noexcept
|
||||
{
|
||||
const int e = errno;
|
||||
|
||||
va_list ap;
|
||||
std::va_list ap;
|
||||
va_start(ap, fmt);
|
||||
FormatErrnoV(domain, e, fmt, ap);
|
||||
va_end(ap);
|
||||
|
89
src/Log.hxx
89
src/Log.hxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,16 +28,38 @@
|
||||
class Domain;
|
||||
|
||||
void
|
||||
Log(const Domain &domain, LogLevel level, const char *msg) noexcept;
|
||||
Log(LogLevel level, const Domain &domain, const char *msg) noexcept;
|
||||
|
||||
gcc_printf(3,4)
|
||||
void
|
||||
LogFormat(const Domain &domain, LogLevel level, const char *fmt, ...) noexcept;
|
||||
LogFormat(LogLevel level, const Domain &domain, const char *fmt, ...) noexcept;
|
||||
|
||||
void
|
||||
Log(LogLevel level, const std::exception &e) noexcept;
|
||||
|
||||
void
|
||||
Log(LogLevel level, const std::exception &e, const char *msg) noexcept;
|
||||
|
||||
gcc_printf(3,4)
|
||||
void
|
||||
LogFormat(LogLevel level, const std::exception &e,
|
||||
const char *fmt, ...) noexcept;
|
||||
|
||||
void
|
||||
Log(LogLevel level, const std::exception_ptr &ep) noexcept;
|
||||
|
||||
void
|
||||
Log(LogLevel level, const std::exception_ptr &ep, const char *msg) noexcept;
|
||||
|
||||
gcc_printf(3,4)
|
||||
void
|
||||
LogFormat(LogLevel level, const std::exception_ptr &ep,
|
||||
const char *fmt, ...) noexcept;
|
||||
|
||||
static inline void
|
||||
LogDebug(const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
Log(domain, LogLevel::DEBUG, msg);
|
||||
Log(LogLevel::DEBUG, domain, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
@@ -47,7 +69,7 @@ FormatDebug(const Domain &domain, const char *fmt, ...) noexcept;
|
||||
static inline void
|
||||
LogInfo(const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
Log(domain, LogLevel::INFO, msg);
|
||||
Log(LogLevel::INFO, domain, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
@@ -55,19 +77,19 @@ void
|
||||
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept;
|
||||
|
||||
static inline void
|
||||
LogDefault(const Domain &domain, const char *msg) noexcept
|
||||
LogNotice(const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
Log(domain, LogLevel::DEFAULT, msg);
|
||||
Log(LogLevel::NOTICE, domain, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatDefault(const Domain &domain, const char *fmt, ...) noexcept;
|
||||
FormatNotice(const Domain &domain, const char *fmt, ...) noexcept;
|
||||
|
||||
static inline void
|
||||
LogWarning(const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
Log(domain, LogLevel::WARNING, msg);
|
||||
Log(LogLevel::WARNING, domain, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
@@ -77,28 +99,47 @@ FormatWarning(const Domain &domain, const char *fmt, ...) noexcept;
|
||||
static inline void
|
||||
LogError(const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
Log(domain, LogLevel::ERROR, msg);
|
||||
Log(LogLevel::ERROR, domain, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e) noexcept;
|
||||
inline void
|
||||
LogError(const std::exception &e) noexcept
|
||||
{
|
||||
Log(LogLevel::ERROR, e);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e, const char *msg) noexcept;
|
||||
inline void
|
||||
LogError(const std::exception &e, const char *msg) noexcept
|
||||
{
|
||||
Log(LogLevel::ERROR, e, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception &e, const char *fmt, ...) noexcept;
|
||||
template<typename... Args>
|
||||
inline void
|
||||
FormatError(const std::exception &e, const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
LogFormat(LogLevel::ERROR, e, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep) noexcept;
|
||||
inline void
|
||||
LogError(const std::exception_ptr &ep) noexcept
|
||||
{
|
||||
Log(LogLevel::ERROR, ep);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg) noexcept;
|
||||
inline void
|
||||
LogError(const std::exception_ptr &ep, const char *msg) noexcept
|
||||
{
|
||||
Log(LogLevel::ERROR, ep, msg);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...) noexcept;
|
||||
template<typename... Args>
|
||||
inline void
|
||||
FormatError(const std::exception_ptr &ep,
|
||||
const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
LogFormat(LogLevel::ERROR, ep, fmt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,9 +21,11 @@
|
||||
#include "Log.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringStrip.hxx"
|
||||
#include "Version.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -45,7 +47,7 @@ ToAndroidLogLevel(LogLevel log_level) noexcept
|
||||
return ANDROID_LOG_DEBUG;
|
||||
|
||||
case LogLevel::INFO:
|
||||
case LogLevel::DEFAULT:
|
||||
case LogLevel::NOTICE:
|
||||
return ANDROID_LOG_INFO;
|
||||
|
||||
case LogLevel::WARNING:
|
||||
@@ -61,7 +63,7 @@ ToAndroidLogLevel(LogLevel log_level) noexcept
|
||||
|
||||
#else
|
||||
|
||||
static LogLevel log_threshold = LogLevel::INFO;
|
||||
static LogLevel log_threshold = LogLevel::NOTICE;
|
||||
|
||||
static bool enable_timestamp;
|
||||
|
||||
@@ -120,7 +122,7 @@ ToSysLogLevel(LogLevel log_level) noexcept
|
||||
case LogLevel::INFO:
|
||||
return LOG_INFO;
|
||||
|
||||
case LogLevel::DEFAULT:
|
||||
case LogLevel::NOTICE:
|
||||
return LOG_NOTICE;
|
||||
|
||||
case LogLevel::WARNING:
|
||||
@@ -176,7 +178,7 @@ FileLog(const Domain &domain, const char *message) noexcept
|
||||
#endif /* !ANDROID */
|
||||
|
||||
void
|
||||
Log(const Domain &domain, LogLevel level, const char *msg) noexcept
|
||||
Log(LogLevel level, const Domain &domain, const char *msg) noexcept
|
||||
{
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ToAndroidLogLevel(level), "MPD",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,24 +28,24 @@
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringAPI.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LOG_LEVEL_SECURE LogLevel::INFO
|
||||
|
||||
#define LOG_DATE_BUF_SIZE 16
|
||||
#define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1)
|
||||
|
||||
gcc_unused
|
||||
[[maybe_unused]]
|
||||
static constexpr Domain log_domain("log");
|
||||
|
||||
#ifndef ANDROID
|
||||
@@ -63,7 +63,7 @@ static void redirect_logs(int fd)
|
||||
}
|
||||
|
||||
static int
|
||||
open_log_file(void)
|
||||
open_log_file()
|
||||
{
|
||||
assert(!out_path.IsNull());
|
||||
|
||||
@@ -93,17 +93,24 @@ log_init_file(int line)
|
||||
}
|
||||
|
||||
static inline LogLevel
|
||||
parse_log_level(const char *value, int line)
|
||||
parse_log_level(const char *value)
|
||||
{
|
||||
if (0 == strcmp(value, "default"))
|
||||
return LogLevel::DEFAULT;
|
||||
if (0 == strcmp(value, "secure"))
|
||||
return LOG_LEVEL_SECURE;
|
||||
else if (0 == strcmp(value, "verbose"))
|
||||
if (StringIsEqual(value, "notice") ||
|
||||
/* deprecated name: */
|
||||
StringIsEqual(value, "default"))
|
||||
return LogLevel::NOTICE;
|
||||
else if (StringIsEqual(value, "info") ||
|
||||
/* deprecated since MPD 0.22: */
|
||||
StringIsEqual(value, "secure"))
|
||||
return LogLevel::INFO;
|
||||
else if (StringIsEqual(value, "verbose"))
|
||||
return LogLevel::DEBUG;
|
||||
else if (StringIsEqual(value, "warning"))
|
||||
return LogLevel::WARNING;
|
||||
else if (StringIsEqual(value, "error"))
|
||||
return LogLevel::ERROR;
|
||||
else
|
||||
throw FormatRuntimeError("unknown log level \"%s\" at line %d",
|
||||
value, line);
|
||||
throw FormatRuntimeError("unknown log level \"%s\"", value);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -132,9 +139,12 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
|
||||
#else
|
||||
if (verbose)
|
||||
SetLogThreshold(LogLevel::DEBUG);
|
||||
else if (const auto ¶m = config.GetParam(ConfigOption::LOG_LEVEL))
|
||||
SetLogThreshold(parse_log_level(param->value.c_str(),
|
||||
param->line));
|
||||
else
|
||||
SetLogThreshold(config.With(ConfigOption::LOG_LEVEL, [](const char *s){
|
||||
return s != nullptr
|
||||
? parse_log_level(s)
|
||||
: LogLevel::NOTICE;
|
||||
}));
|
||||
|
||||
if (use_stdout) {
|
||||
out_fd = STDOUT_FILENO;
|
||||
@@ -157,7 +167,7 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
|
||||
throw std::runtime_error("config parameter 'log_file' not found");
|
||||
#endif
|
||||
#ifdef HAVE_SYSLOG
|
||||
} else if (strcmp(param->value.c_str(), "syslog") == 0) {
|
||||
} else if (StringIsEqual(param->value.c_str(), "syslog")) {
|
||||
LogInitSysLog();
|
||||
#endif
|
||||
} else {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 @@ enum class LogLevel {
|
||||
/**
|
||||
* Interesting informational message.
|
||||
*/
|
||||
DEFAULT,
|
||||
NOTICE,
|
||||
|
||||
/**
|
||||
* Warning: something may be wrong.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include "Log.hxx" // IWYU pragma: export
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <cstdarg>
|
||||
|
||||
void
|
||||
LogFormatV(const Domain &domain, LogLevel level,
|
||||
const char *fmt, va_list ap) noexcept;
|
||||
LogFormatV(LogLevel level, const Domain &domain,
|
||||
const char *fmt, std::va_list ap) noexcept;
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
456
src/Main.cxx
456
src/Main.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -27,30 +27,30 @@
|
||||
#include "Mapper.hxx"
|
||||
#include "Permission.hxx"
|
||||
#include "Listen.hxx"
|
||||
#include "client/Listener.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "client/ClientList.hxx"
|
||||
#include "client/Config.hxx"
|
||||
#include "client/List.hxx"
|
||||
#include "command/AllCommands.hxx"
|
||||
#include "Partition.hxx"
|
||||
#include "tag/Config.hxx"
|
||||
#include "ReplayGainGlobal.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "IdleFlags.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "LogInit.hxx"
|
||||
#include "input/Init.hxx"
|
||||
#include "input/cache/Config.hxx"
|
||||
#include "input/cache/Manager.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/Config.hxx"
|
||||
#include "playlist/PlaylistRegistry.hxx"
|
||||
#include "zeroconf/ZeroconfGlue.hxx"
|
||||
#include "decoder/DecoderList.hxx"
|
||||
#include "AudioParser.hxx"
|
||||
#include "pcm/PcmConvert.hxx"
|
||||
#include "pcm/AudioParser.hxx"
|
||||
#include "pcm/Convert.hxx"
|
||||
#include "unix/SignalHandlers.hxx"
|
||||
#include "thread/Slack.hxx"
|
||||
#include "net/Init.hxx"
|
||||
#include "lib/icu/Init.hxx"
|
||||
#include "config/File.hxx"
|
||||
#include "config/Check.hxx"
|
||||
#include "config/Data.hxx"
|
||||
#include "config/Param.hxx"
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "config/Defaults.hxx"
|
||||
#include "config/Option.hxx"
|
||||
#include "config/Domain.hxx"
|
||||
#include "config/Parser.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
|
||||
@@ -82,7 +83,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
#include "sticker/StickerDatabase.hxx"
|
||||
#include "sticker/Database.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
@@ -95,6 +96,7 @@
|
||||
#include "android/Environment.hxx"
|
||||
#include "android/Context.hxx"
|
||||
#include "android/LogListener.hxx"
|
||||
#include "config/File.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "org_musicpd_Bridge.h"
|
||||
#endif
|
||||
@@ -107,14 +109,12 @@
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <climits>
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#ifndef ANDROID
|
||||
#include <clocale>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
static constexpr size_t KILOBYTE = 1024;
|
||||
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||
|
||||
@@ -129,17 +129,14 @@ Context *context;
|
||||
LogListener *logListener;
|
||||
#endif
|
||||
|
||||
Instance *instance;
|
||||
Instance *global_instance;
|
||||
|
||||
struct Config {
|
||||
ReplayGainConfig replay_gain;
|
||||
};
|
||||
|
||||
static Config
|
||||
LoadConfig(const ConfigData &config)
|
||||
{
|
||||
return {LoadReplayGainConfig(config)};
|
||||
}
|
||||
explicit Config(const ConfigData &raw)
|
||||
:replay_gain(LoadReplayGainConfig(raw)) {}
|
||||
};
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
|
||||
@@ -166,14 +163,15 @@ glue_mapper_init(const ConfigData &config)
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
static void
|
||||
InitStorage(const ConfigData &config, EventLoop &event_loop)
|
||||
InitStorage(Instance &instance, EventLoop &event_loop,
|
||||
const ConfigData &config)
|
||||
{
|
||||
auto storage = CreateConfiguredStorage(config, event_loop);
|
||||
if (storage == nullptr)
|
||||
return;
|
||||
|
||||
CompositeStorage *composite = new CompositeStorage();
|
||||
instance->storage = composite;
|
||||
auto *composite = new CompositeStorage();
|
||||
instance.storage = composite;
|
||||
composite->Mount("", std::move(storage));
|
||||
}
|
||||
|
||||
@@ -183,28 +181,29 @@ InitStorage(const ConfigData &config, EventLoop &event_loop)
|
||||
* process has been daemonized.
|
||||
*/
|
||||
static bool
|
||||
glue_db_init_and_load(const ConfigData &config)
|
||||
glue_db_init_and_load(Instance &instance, const ConfigData &config)
|
||||
{
|
||||
auto db = CreateConfiguredDatabase(config, instance->event_loop,
|
||||
instance->io_thread.GetEventLoop(),
|
||||
*instance);
|
||||
auto db = CreateConfiguredDatabase(config, instance.event_loop,
|
||||
instance.io_thread.GetEventLoop(),
|
||||
instance);
|
||||
if (!db)
|
||||
return true;
|
||||
|
||||
if (db->GetPlugin().RequireStorage()) {
|
||||
InitStorage(config, instance->io_thread.GetEventLoop());
|
||||
InitStorage(instance, instance.io_thread.GetEventLoop(),
|
||||
config);
|
||||
|
||||
if (instance->storage == nullptr) {
|
||||
LogDefault(config_domain,
|
||||
"Found database setting without "
|
||||
"music_directory - disabling database");
|
||||
if (instance.storage == nullptr) {
|
||||
LogNotice(config_domain,
|
||||
"Found database setting without "
|
||||
"music_directory - disabling database");
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (IsStorageConfigured(config))
|
||||
LogDefault(config_domain,
|
||||
"Ignoring the storage configuration "
|
||||
"because the database does not need it");
|
||||
LogNotice(config_domain,
|
||||
"Ignoring the storage configuration "
|
||||
"because the database does not need it");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -213,65 +212,66 @@ glue_db_init_and_load(const ConfigData &config)
|
||||
std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
|
||||
}
|
||||
|
||||
instance->database = std::move(db);
|
||||
instance.database = std::move(db);
|
||||
|
||||
auto *sdb = dynamic_cast<SimpleDatabase *>(instance->database.get());
|
||||
auto *sdb = dynamic_cast<SimpleDatabase *>(instance.database.get());
|
||||
if (sdb == nullptr)
|
||||
return true;
|
||||
|
||||
instance->update = new UpdateService(config,
|
||||
instance->event_loop, *sdb,
|
||||
static_cast<CompositeStorage &>(*instance->storage),
|
||||
*instance);
|
||||
instance.update = new UpdateService(config,
|
||||
instance.event_loop, *sdb,
|
||||
static_cast<CompositeStorage &>(*instance.storage),
|
||||
instance);
|
||||
|
||||
/* run database update after daemonization? */
|
||||
return sdb->FileExists();
|
||||
}
|
||||
|
||||
static bool
|
||||
InitDatabaseAndStorage(const ConfigData &config)
|
||||
InitDatabaseAndStorage(Instance &instance, const ConfigData &config)
|
||||
{
|
||||
const bool create_db = !glue_db_init_and_load(config);
|
||||
const bool create_db = !glue_db_init_and_load(instance, config);
|
||||
return create_db;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
|
||||
/**
|
||||
* Configure and initialize the sticker subsystem.
|
||||
*/
|
||||
static void
|
||||
glue_sticker_init(const ConfigData &config)
|
||||
static std::unique_ptr<StickerDatabase>
|
||||
LoadStickerDatabase(const ConfigData &config)
|
||||
{
|
||||
#ifdef ENABLE_SQLITE
|
||||
auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
|
||||
if (sticker_file.IsNull())
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
sticker_global_init(std::move(sticker_file));
|
||||
#else
|
||||
(void)config;
|
||||
#endif
|
||||
return std::make_unique<StickerDatabase>(std::move(sticker_file));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
glue_state_file_init(const ConfigData &raw_config)
|
||||
glue_state_file_init(Instance &instance, const ConfigData &raw_config)
|
||||
{
|
||||
StateFileConfig config(raw_config);
|
||||
if (!config.IsEnabled())
|
||||
return;
|
||||
|
||||
instance->state_file = new StateFile(std::move(config),
|
||||
instance->partitions.front(),
|
||||
instance->event_loop);
|
||||
instance->state_file->Read();
|
||||
instance.state_file = std::make_unique< StateFile>(std::move(config),
|
||||
instance.partitions.front(),
|
||||
instance.event_loop);
|
||||
instance.state_file->Read();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the decoder and player core, including the music pipe.
|
||||
*/
|
||||
static void
|
||||
initialize_decoder_and_player(const ConfigData &config,
|
||||
initialize_decoder_and_player(Instance &instance,
|
||||
const ConfigData &config,
|
||||
const ReplayGainConfig &replay_gain_config)
|
||||
{
|
||||
const ConfigParam *param;
|
||||
@@ -279,20 +279,21 @@ initialize_decoder_and_player(const ConfigData &config,
|
||||
size_t buffer_size;
|
||||
param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
|
||||
if (param != nullptr) {
|
||||
char *test;
|
||||
long tmp = strtol(param->value.c_str(), &test, 10);
|
||||
if (*test != '\0' || tmp <= 0 || tmp == LONG_MAX)
|
||||
throw FormatRuntimeError("buffer size \"%s\" is not a "
|
||||
"positive integer, line %i",
|
||||
param->value.c_str(), param->line);
|
||||
buffer_size = tmp * KILOBYTE;
|
||||
buffer_size = param->With([](const char *s){
|
||||
size_t result = ParseSize(s, KILOBYTE);
|
||||
if (result <= 0)
|
||||
throw FormatRuntimeError("buffer size \"%s\" is not a "
|
||||
"positive integer", s);
|
||||
|
||||
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;
|
||||
}
|
||||
if (result < MIN_BUFFER_SIZE) {
|
||||
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
|
||||
(unsigned long)result,
|
||||
(unsigned long)MIN_BUFFER_SIZE);
|
||||
result = MIN_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
} else
|
||||
buffer_size = DEFAULT_BUFFER_SIZE;
|
||||
|
||||
@@ -306,35 +307,26 @@ initialize_decoder_and_player(const ConfigData &config,
|
||||
config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
|
||||
DEFAULT_PLAYLIST_MAX_LENGTH);
|
||||
|
||||
AudioFormat configured_audio_format = AudioFormat::Undefined();
|
||||
param = config.GetParam(ConfigOption::AUDIO_OUTPUT_FORMAT);
|
||||
if (param != nullptr) {
|
||||
try {
|
||||
configured_audio_format = ParseAudioFormat(param->value.c_str(),
|
||||
true);
|
||||
} catch (...) {
|
||||
std::throw_with_nested(FormatRuntimeError("error parsing line %i",
|
||||
param->line));
|
||||
}
|
||||
}
|
||||
AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
|
||||
if (s == nullptr)
|
||||
return AudioFormat::Undefined();
|
||||
|
||||
instance->partitions.emplace_back(*instance,
|
||||
"default",
|
||||
max_length,
|
||||
buffered_chunks,
|
||||
configured_audio_format,
|
||||
replay_gain_config);
|
||||
auto &partition = instance->partitions.back();
|
||||
return ParseAudioFormat(s, true);
|
||||
});
|
||||
|
||||
try {
|
||||
param = config.GetParam(ConfigOption::REPLAYGAIN);
|
||||
if (param != nullptr)
|
||||
partition.replay_gain_mode =
|
||||
FromString(param->value.c_str());
|
||||
} catch (...) {
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
|
||||
param->line));
|
||||
}
|
||||
instance.partitions.emplace_back(instance,
|
||||
"default",
|
||||
max_length,
|
||||
buffered_chunks,
|
||||
configured_audio_format,
|
||||
replay_gain_config);
|
||||
auto &partition = instance.partitions.back();
|
||||
|
||||
partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){
|
||||
return s != nullptr
|
||||
? FromString(s)
|
||||
: ReplayGainMode::OFF;
|
||||
});
|
||||
}
|
||||
|
||||
inline void
|
||||
@@ -354,56 +346,21 @@ inline void
|
||||
Instance::BeginShutdownPartitions() noexcept
|
||||
{
|
||||
for (auto &partition : partitions) {
|
||||
partition.pc.Kill();
|
||||
partition.listener.reset();
|
||||
partition.BeginShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnIdle(unsigned flags)
|
||||
static inline void
|
||||
MainConfigured(const struct options &options, const ConfigData &raw_config)
|
||||
{
|
||||
/* send "idle" notifications to all subscribed
|
||||
clients */
|
||||
client_list->IdleAdd(flags);
|
||||
|
||||
if (flags & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT) &&
|
||||
state_file != nullptr)
|
||||
state_file->CheckModified();
|
||||
}
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return win32_main(argc, argv);
|
||||
#else
|
||||
return mpd_main(argc, argv);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int
|
||||
mpd_main_after_fork(const ConfigData &raw_config,
|
||||
const Config &config);
|
||||
|
||||
static inline int
|
||||
MainOrThrow(int argc, char *argv[])
|
||||
{
|
||||
struct options options;
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_close_stdin();
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* initialize locale */
|
||||
setlocale(LC_CTYPE,"");
|
||||
setlocale(LC_COLLATE, "");
|
||||
#endif
|
||||
std::setlocale(LC_CTYPE,"");
|
||||
std::setlocale(LC_COLLATE, "");
|
||||
#endif
|
||||
|
||||
const ScopeIcuInit icu_init;
|
||||
@@ -413,25 +370,8 @@ MainOrThrow(int argc, char *argv[])
|
||||
const ODBus::ScopeInit dbus_init;
|
||||
#endif
|
||||
|
||||
ConfigData raw_config;
|
||||
|
||||
#ifdef ANDROID
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
const auto sdcard = Environment::getExternalStorageDirectory();
|
||||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
sdcard / Path::FromFS("mpd.conf");
|
||||
if (FileExists(config_path))
|
||||
ReadConfigFile(raw_config, config_path);
|
||||
}
|
||||
#else
|
||||
ParseCommandLine(argc, argv, options, raw_config);
|
||||
#endif
|
||||
|
||||
InitPathParser(raw_config);
|
||||
const auto config = LoadConfig(raw_config);
|
||||
const Config config(raw_config);
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
glue_daemonize_init(&options, raw_config);
|
||||
@@ -441,31 +381,33 @@ MainOrThrow(int argc, char *argv[])
|
||||
|
||||
log_init(raw_config, options.verbose, options.log_stderr);
|
||||
|
||||
instance = new Instance();
|
||||
AtScopeExit() {
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
};
|
||||
Instance instance;
|
||||
global_instance = &instance;
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
instance->neighbors = new NeighborGlue();
|
||||
instance->neighbors->Init(raw_config,
|
||||
instance->io_thread.GetEventLoop(),
|
||||
*instance);
|
||||
instance.neighbors = std::make_unique<NeighborGlue>();
|
||||
instance.neighbors->Init(raw_config,
|
||||
instance.io_thread.GetEventLoop(),
|
||||
instance);
|
||||
|
||||
if (instance->neighbors->IsEmpty()) {
|
||||
delete instance->neighbors;
|
||||
instance->neighbors = nullptr;
|
||||
}
|
||||
if (instance.neighbors->IsEmpty())
|
||||
instance.neighbors.reset();
|
||||
#endif
|
||||
|
||||
const unsigned max_clients =
|
||||
raw_config.GetPositive(ConfigOption::MAX_CONN, 100);
|
||||
instance->client_list = new ClientList(max_clients);
|
||||
instance.client_list = std::make_unique<ClientList>(max_clients);
|
||||
|
||||
initialize_decoder_and_player(raw_config, config.replay_gain);
|
||||
const auto *input_cache_config = raw_config.GetBlock(ConfigBlockOption::INPUT_CACHE);
|
||||
if (input_cache_config != nullptr) {
|
||||
const InputCacheConfig c(*input_cache_config);
|
||||
instance.input_cache = std::make_unique<InputCacheManager>(c);
|
||||
}
|
||||
|
||||
listen_global_init(raw_config, *instance->partitions.front().listener);
|
||||
initialize_decoder_and_player(instance,
|
||||
raw_config, config.replay_gain);
|
||||
|
||||
listen_global_init(raw_config, *instance.partitions.front().listener);
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_set_user();
|
||||
@@ -473,27 +415,6 @@ MainOrThrow(int argc, char *argv[])
|
||||
AtScopeExit() { daemonize_finish(); };
|
||||
#endif
|
||||
|
||||
return mpd_main_after_fork(raw_config, config);
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
static inline
|
||||
#endif
|
||||
int mpd_main(int argc, char *argv[]) noexcept
|
||||
{
|
||||
AtScopeExit() { log_deinit(); };
|
||||
|
||||
try {
|
||||
return MainOrThrow(argc, argv);
|
||||
} catch (...) {
|
||||
LogError(std::current_exception());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
{
|
||||
ConfigureFS(raw_config);
|
||||
AtScopeExit() { DeinitFS(); };
|
||||
|
||||
@@ -510,24 +431,26 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
const bool create_db = InitDatabaseAndStorage(raw_config);
|
||||
const bool create_db = InitDatabaseAndStorage(instance, raw_config);
|
||||
#endif
|
||||
|
||||
glue_sticker_init(raw_config);
|
||||
#ifdef ENABLE_SQLITE
|
||||
instance.sticker_database = LoadStickerDatabase(raw_config);
|
||||
#endif
|
||||
|
||||
command_init();
|
||||
|
||||
for (auto &partition : instance->partitions) {
|
||||
partition.outputs.Configure(instance->rtio_thread.GetEventLoop(),
|
||||
for (auto &partition : instance.partitions) {
|
||||
partition.outputs.Configure(instance.rtio_thread.GetEventLoop(),
|
||||
raw_config,
|
||||
config.replay_gain,
|
||||
partition.pc);
|
||||
config.replay_gain);
|
||||
partition.UpdateEffectiveReplayGainMode();
|
||||
}
|
||||
|
||||
client_manager_init(raw_config);
|
||||
const ScopeInputPluginsInit input_plugins_init(raw_config,
|
||||
instance->io_thread.GetEventLoop());
|
||||
instance.io_thread.GetEventLoop());
|
||||
|
||||
const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
@@ -537,37 +460,42 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
#ifndef ANDROID
|
||||
setup_log_output();
|
||||
|
||||
const ScopeSignalHandlersInit signal_handlers_init(instance->event_loop);
|
||||
const ScopeSignalHandlersInit signal_handlers_init(instance);
|
||||
#endif
|
||||
|
||||
instance->io_thread.Start();
|
||||
instance->rtio_thread.Start();
|
||||
instance.io_thread.Start();
|
||||
instance.rtio_thread.Start();
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
if (instance->neighbors != nullptr)
|
||||
instance->neighbors->Open();
|
||||
if (instance.neighbors != nullptr)
|
||||
instance.neighbors->Open();
|
||||
|
||||
AtScopeExit(&instance) {
|
||||
if (instance.neighbors != nullptr)
|
||||
instance.neighbors->Close();
|
||||
};
|
||||
#endif
|
||||
|
||||
ZeroconfInit(raw_config, instance->event_loop);
|
||||
ZeroconfInit(raw_config, instance.event_loop);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (create_db) {
|
||||
/* the database failed to load: recreate the
|
||||
database */
|
||||
instance->update->Enqueue("", true);
|
||||
instance.update->Enqueue("", true);
|
||||
}
|
||||
#endif
|
||||
|
||||
glue_state_file_init(raw_config);
|
||||
glue_state_file_init(instance, raw_config);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
|
||||
#ifdef ENABLE_INOTIFY
|
||||
if (instance->storage != nullptr &&
|
||||
instance->update != nullptr)
|
||||
mpd_inotify_init(instance->event_loop,
|
||||
*instance->storage,
|
||||
*instance->update,
|
||||
if (instance.storage != nullptr &&
|
||||
instance.update != nullptr)
|
||||
mpd_inotify_init(instance.event_loop,
|
||||
*instance.storage,
|
||||
*instance.update,
|
||||
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
||||
INT_MAX));
|
||||
#else
|
||||
@@ -581,7 +509,7 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
|
||||
/* enable all audio outputs (if not already done by
|
||||
playlist_state_restore() */
|
||||
for (auto &partition : instance->partitions)
|
||||
for (auto &partition : instance.partitions)
|
||||
partition.pc.LockUpdateAudio();
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -590,14 +518,14 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
|
||||
/* the MPD frontend does not care about timer slack; set it to
|
||||
a huge value to allow the kernel to reduce CPU wakeups */
|
||||
SetThreadTimerSlackMS(100);
|
||||
SetThreadTimerSlack(std::chrono::milliseconds(100));
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
sd_notify(0, "READY=1");
|
||||
#endif
|
||||
|
||||
/* run the main loop */
|
||||
instance->event_loop.Run();
|
||||
instance.event_loop.Run();
|
||||
|
||||
#ifdef _WIN32
|
||||
win32_app_stopping();
|
||||
@@ -605,60 +533,98 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
||||
|
||||
/* cleanup */
|
||||
|
||||
instance->BeginShutdownUpdate();
|
||||
|
||||
if (instance->state_file != nullptr) {
|
||||
instance->state_file->Write();
|
||||
delete instance->state_file;
|
||||
}
|
||||
instance.BeginShutdownUpdate();
|
||||
|
||||
ZeroconfDeinit();
|
||||
|
||||
instance->BeginShutdownPartitions();
|
||||
|
||||
delete instance->client_list;
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
if (instance->neighbors != nullptr) {
|
||||
instance->neighbors->Close();
|
||||
delete instance->neighbors;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
sticker_global_finish();
|
||||
#endif
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
instance.BeginShutdownPartitions();
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
static void
|
||||
AndroidMain()
|
||||
{
|
||||
struct options options;
|
||||
ConfigData raw_config;
|
||||
|
||||
const auto sdcard = Environment::getExternalStorageDirectory();
|
||||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
sdcard / Path::FromFS("mpd.conf");
|
||||
if (FileExists(config_path))
|
||||
ReadConfigFile(raw_config, config_path);
|
||||
}
|
||||
|
||||
MainConfigured(options, raw_config);
|
||||
}
|
||||
|
||||
gcc_visibility_default
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
|
||||
{
|
||||
Java::Init(env);
|
||||
Java::Object::Initialise(env);
|
||||
Java::File::Initialise(env);
|
||||
Environment::Initialise(env);
|
||||
AtScopeExit(env) { Environment::Deinitialise(env); };
|
||||
|
||||
context = new Context(env, _context);
|
||||
AtScopeExit() { delete context; };
|
||||
|
||||
if (_logListener != nullptr)
|
||||
logListener = new LogListener(env, _logListener);
|
||||
AtScopeExit() { delete logListener; };
|
||||
|
||||
mpd_main(0, nullptr);
|
||||
|
||||
delete logListener;
|
||||
delete context;
|
||||
Environment::Deinitialise(env);
|
||||
try {
|
||||
AndroidMain();
|
||||
} catch (...) {
|
||||
LogError(std::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
gcc_visibility_default
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->Break();
|
||||
if (global_instance != nullptr)
|
||||
global_instance->Break();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline void
|
||||
MainOrThrow(int argc, char *argv[])
|
||||
{
|
||||
struct options options;
|
||||
ConfigData raw_config;
|
||||
|
||||
ParseCommandLine(argc, argv, options, raw_config);
|
||||
|
||||
MainConfigured(options, raw_config);
|
||||
}
|
||||
|
||||
int mpd_main(int argc, char *argv[]) noexcept
|
||||
{
|
||||
AtScopeExit() { log_deinit(); };
|
||||
|
||||
try {
|
||||
MainOrThrow(argc, argv);
|
||||
return EXIT_SUCCESS;
|
||||
} catch (...) {
|
||||
LogError(std::current_exception());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) noexcept
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return win32_main(argc, argv);
|
||||
#else
|
||||
return mpd_main(argc, argv);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,18 +20,16 @@
|
||||
#ifndef MPD_MAIN_HXX
|
||||
#define MPD_MAIN_HXX
|
||||
|
||||
class EventLoop;
|
||||
class Context;
|
||||
struct Instance;
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "android/LogListener.hxx"
|
||||
|
||||
extern Context *context;
|
||||
extern class Context *context;
|
||||
extern LogListener *logListener;
|
||||
#endif
|
||||
|
||||
extern Instance *instance;
|
||||
extern Instance *global_instance;
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "Main.hxx"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
/**
|
||||
* The absolute path of the playlist directory encoded in the
|
||||
@@ -66,10 +66,10 @@ map_uri_fs(const char *uri) noexcept
|
||||
assert(uri != nullptr);
|
||||
assert(*uri != '/');
|
||||
|
||||
if (instance->storage == nullptr)
|
||||
if (global_instance->storage == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const auto music_dir_fs = instance->storage->MapFS("");
|
||||
const auto music_dir_fs = global_instance->storage->MapFS("");
|
||||
if (music_dir_fs.IsNull())
|
||||
return nullptr;
|
||||
|
||||
@@ -84,10 +84,10 @@ std::string
|
||||
map_fs_to_utf8(Path path_fs) noexcept
|
||||
{
|
||||
if (path_fs.IsAbsolute()) {
|
||||
if (instance->storage == nullptr)
|
||||
if (global_instance->storage == nullptr)
|
||||
return std::string();
|
||||
|
||||
const auto music_dir_fs = instance->storage->MapFS("");
|
||||
const auto music_dir_fs = global_instance->storage->MapFS("");
|
||||
if (music_dir_fs.IsNull())
|
||||
return std::string();
|
||||
|
||||
@@ -119,7 +119,7 @@ map_spl_utf8_to_fs(const char *name) noexcept
|
||||
filename_utf8.append(PLAYLIST_FILE_SUFFIX);
|
||||
|
||||
const auto filename_fs =
|
||||
AllocatedPath::FromUTF8(filename_utf8.c_str());
|
||||
AllocatedPath::FromUTF8(filename_utf8);
|
||||
if (filename_fs.IsNull())
|
||||
return nullptr;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 @@
|
||||
#include "MusicBuffer.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
||||
:buffer(num_chunks) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -18,10 +18,10 @@
|
||||
*/
|
||||
|
||||
#include "MusicChunk.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "pcm/AudioFormat.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
MusicChunkInfo::MusicChunkInfo() noexcept = default;
|
||||
MusicChunkInfo::~MusicChunkInfo() noexcept = default;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,14 +26,13 @@
|
||||
#include "util/WritableBuffer.hxx"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "AudioFormat.hxx"
|
||||
#include "pcm/AudioFormat.hxx"
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static constexpr size_t CHUNK_SIZE = 4096;
|
||||
|
||||
struct AudioFormat;
|
||||
@@ -43,15 +42,7 @@ struct MusicChunk;
|
||||
/**
|
||||
* Meta information for #MusicChunk.
|
||||
*/
|
||||
struct alignas(8) MusicChunkInfo {
|
||||
/* align to multiple of 8 bytes, which adds padding at the
|
||||
end, so the size of MusicChunk::data is also a multiple of
|
||||
8 bytes; this is a workaround for a bug in the DSD_U32 and
|
||||
DoP converters which require processing 8 bytes at a time,
|
||||
discarding the remainder */
|
||||
/* TODO: once all converters have been fixed, we should remove
|
||||
this workaround */
|
||||
|
||||
struct MusicChunkInfo {
|
||||
/** the next chunk in a linked list */
|
||||
MusicChunkPtr next;
|
||||
|
||||
@@ -127,10 +118,6 @@ struct MusicChunk : MusicChunkInfo {
|
||||
/** the data (probably PCM) */
|
||||
uint8_t data[CHUNK_SIZE - sizeof(MusicChunkInfo)];
|
||||
|
||||
/* TODO: remove this check once all converters have been fixed
|
||||
(see comment in struct MusicChunkInfo for details) */
|
||||
static_assert(sizeof(data) % 8 == 0, "Wrong alignment");
|
||||
|
||||
/**
|
||||
* Prepares appending to the music chunk. Returns a buffer
|
||||
* where you may write into. After you are finished, call
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "MusicPipe.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
bool
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,11 +25,9 @@
|
||||
#include "util/Compiler.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include "AudioFormat.hxx"
|
||||
#include "pcm/AudioFormat.hxx"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* A queue of #MusicChunk objects. One party appends chunks at the
|
||||
* tail, and the other consumes them from the head.
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,24 +20,33 @@
|
||||
#include "config.h"
|
||||
#include "Partition.hxx"
|
||||
#include "Instance.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "song/DetachedSong.hxx"
|
||||
#include "mixer/Volume.hxx"
|
||||
#include "IdleFlags.hxx"
|
||||
#include "client/Listener.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "input/cache/Manager.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
static constexpr Domain cache_domain("cache");
|
||||
|
||||
Partition::Partition(Instance &_instance,
|
||||
const char *_name,
|
||||
unsigned max_length,
|
||||
unsigned buffer_chunks,
|
||||
AudioFormat configured_audio_format,
|
||||
const ReplayGainConfig &replay_gain_config)
|
||||
const ReplayGainConfig &replay_gain_config) noexcept
|
||||
:instance(_instance),
|
||||
name(_name),
|
||||
listener(new ClientListener(instance.event_loop, *this)),
|
||||
idle_monitor(instance.event_loop, BIND_THIS_METHOD(OnIdleMonitor)),
|
||||
global_events(instance.event_loop, BIND_THIS_METHOD(OnGlobalEvent)),
|
||||
playlist(max_length, *this),
|
||||
outputs(*this),
|
||||
pc(*this, outputs, buffer_chunks,
|
||||
outputs(pc, *this),
|
||||
pc(*this, outputs,
|
||||
instance.input_cache.get(),
|
||||
buffer_chunks,
|
||||
configured_audio_format, replay_gain_config)
|
||||
{
|
||||
UpdateEffectiveReplayGainMode();
|
||||
@@ -46,13 +55,51 @@ Partition::Partition(Instance &_instance,
|
||||
Partition::~Partition() noexcept = default;
|
||||
|
||||
void
|
||||
Partition::EmitIdle(unsigned mask)
|
||||
Partition::BeginShutdown() noexcept
|
||||
{
|
||||
instance.EmitIdle(mask);
|
||||
pc.Kill();
|
||||
listener.reset();
|
||||
}
|
||||
|
||||
static void
|
||||
PrefetchSong(InputCacheManager &cache, const char *uri) noexcept
|
||||
{
|
||||
if (cache.Contains(uri))
|
||||
return;
|
||||
|
||||
FormatDebug(cache_domain, "Prefetch '%s'", uri);
|
||||
|
||||
try {
|
||||
cache.Prefetch(uri);
|
||||
} catch (...) {
|
||||
FormatError(std::current_exception(),
|
||||
"Prefetch '%s' failed", uri);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PrefetchSong(InputCacheManager &cache, const DetachedSong &song) noexcept
|
||||
{
|
||||
PrefetchSong(cache, song.GetURI());
|
||||
}
|
||||
|
||||
inline void
|
||||
Partition::PrefetchQueue() noexcept
|
||||
{
|
||||
if (!instance.input_cache)
|
||||
return;
|
||||
|
||||
auto &cache = *instance.input_cache;
|
||||
|
||||
int next = playlist.GetNextPosition();
|
||||
if (next >= 0)
|
||||
PrefetchSong(cache, playlist.queue.Get(next));
|
||||
|
||||
// TODO: prefetch more songs
|
||||
}
|
||||
|
||||
void
|
||||
Partition::UpdateEffectiveReplayGainMode()
|
||||
Partition::UpdateEffectiveReplayGainMode() noexcept
|
||||
{
|
||||
auto mode = replay_gain_mode;
|
||||
if (mode == ReplayGainMode::AUTO)
|
||||
@@ -68,7 +115,7 @@ Partition::UpdateEffectiveReplayGainMode()
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
const Database *
|
||||
Partition::GetDatabase() const
|
||||
Partition::GetDatabase() const noexcept
|
||||
{
|
||||
return instance.GetDatabase();
|
||||
}
|
||||
@@ -80,7 +127,7 @@ Partition::GetDatabaseOrThrow() const
|
||||
}
|
||||
|
||||
void
|
||||
Partition::DatabaseModified(const Database &db)
|
||||
Partition::DatabaseModified(const Database &db) noexcept
|
||||
{
|
||||
playlist.DatabaseModified(db);
|
||||
EmitIdle(IDLE_DATABASE);
|
||||
@@ -89,7 +136,7 @@ Partition::DatabaseModified(const Database &db)
|
||||
#endif
|
||||
|
||||
void
|
||||
Partition::TagModified()
|
||||
Partition::TagModified() noexcept
|
||||
{
|
||||
auto song = pc.LockReadTaggedSong();
|
||||
if (song)
|
||||
@@ -103,31 +150,35 @@ Partition::TagModified(const char *uri, const Tag &tag) noexcept
|
||||
}
|
||||
|
||||
void
|
||||
Partition::SyncWithPlayer()
|
||||
Partition::SyncWithPlayer() noexcept
|
||||
{
|
||||
playlist.SyncWithPlayer(pc);
|
||||
|
||||
/* TODO: invoke this function in batches, to let the hard disk
|
||||
spin down in between */
|
||||
PrefetchQueue();
|
||||
}
|
||||
|
||||
void
|
||||
Partition::BorderPause()
|
||||
Partition::BorderPause() noexcept
|
||||
{
|
||||
playlist.BorderPause(pc);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueModified()
|
||||
Partition::OnQueueModified() noexcept
|
||||
{
|
||||
EmitIdle(IDLE_PLAYLIST);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueOptionsChanged()
|
||||
Partition::OnQueueOptionsChanged() noexcept
|
||||
{
|
||||
EmitIdle(IDLE_OPTIONS);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueSongStarted()
|
||||
Partition::OnQueueSongStarted() noexcept
|
||||
{
|
||||
EmitIdle(IDLE_PLAYER);
|
||||
}
|
||||
@@ -151,7 +202,7 @@ Partition::OnBorderPause() noexcept
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
||||
Partition::OnMixerVolumeChanged(Mixer &, int) noexcept
|
||||
{
|
||||
InvalidateHardwareVolume();
|
||||
|
||||
@@ -160,7 +211,19 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnGlobalEvent(unsigned mask)
|
||||
Partition::OnIdleMonitor(unsigned mask) noexcept
|
||||
{
|
||||
/* send "idle" notifications to all subscribed
|
||||
clients */
|
||||
for (auto &client : clients)
|
||||
client.IdleAdd(mask);
|
||||
|
||||
if (mask & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT))
|
||||
instance.OnStateModified();
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnGlobalEvent(unsigned mask) noexcept
|
||||
{
|
||||
if ((mask & SYNC_WITH_PLAYER) != 0)
|
||||
SyncWithPlayer();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,9 +30,10 @@
|
||||
#include "ReplayGainMode.hxx"
|
||||
#include "SingleMode.hxx"
|
||||
#include "Chrono.hxx"
|
||||
#include "util/Compiler.h"
|
||||
#include "config.h"
|
||||
|
||||
#include <boost/intrusive/list.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -40,6 +41,7 @@ struct Instance;
|
||||
class MultipleOutputs;
|
||||
class SongLoader;
|
||||
class ClientListener;
|
||||
class Client;
|
||||
|
||||
/**
|
||||
* A partition of the Music Player Daemon. It is a separate unit with
|
||||
@@ -56,6 +58,16 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
|
||||
std::unique_ptr<ClientListener> listener;
|
||||
|
||||
boost::intrusive::list<Client,
|
||||
boost::intrusive::base_hook<boost::intrusive::list_base_hook<boost::intrusive::tag<Partition>,
|
||||
boost::intrusive::link_mode<boost::intrusive::normal_link>>>,
|
||||
boost::intrusive::constant_time_size<false>> clients;
|
||||
|
||||
/**
|
||||
* Monitor for idle events local to this partition.
|
||||
*/
|
||||
MaskMonitor idle_monitor;
|
||||
|
||||
MaskMonitor global_events;
|
||||
|
||||
struct playlist playlist;
|
||||
@@ -71,17 +83,34 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
unsigned max_length,
|
||||
unsigned buffer_chunks,
|
||||
AudioFormat configured_audio_format,
|
||||
const ReplayGainConfig &replay_gain_config);
|
||||
const ReplayGainConfig &replay_gain_config) noexcept;
|
||||
|
||||
~Partition() noexcept;
|
||||
|
||||
void EmitGlobalEvent(unsigned mask) {
|
||||
void BeginShutdown() noexcept;
|
||||
|
||||
void EmitGlobalEvent(unsigned mask) noexcept {
|
||||
global_events.OrMask(mask);
|
||||
}
|
||||
|
||||
void EmitIdle(unsigned mask);
|
||||
/**
|
||||
* Emit an "idle" event to all clients of this partition.
|
||||
*
|
||||
* This method can be called from any thread.
|
||||
*/
|
||||
void EmitIdle(unsigned mask) noexcept {
|
||||
idle_monitor.OrMask(mask);
|
||||
}
|
||||
|
||||
void ClearQueue() {
|
||||
/**
|
||||
* Populate the #InputCacheManager with soon-to-be-played song
|
||||
* files.
|
||||
*
|
||||
* Errors will be logged.
|
||||
*/
|
||||
void PrefetchQueue() noexcept;
|
||||
|
||||
void ClearQueue() noexcept {
|
||||
playlist.Clear(pc);
|
||||
}
|
||||
|
||||
@@ -108,11 +137,11 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
playlist.DeleteRange(pc, start, end);
|
||||
}
|
||||
|
||||
void StaleSong(const char *uri) {
|
||||
void StaleSong(const char *uri) noexcept {
|
||||
playlist.StaleSong(pc, uri);
|
||||
}
|
||||
|
||||
void Shuffle(unsigned start, unsigned end) {
|
||||
void Shuffle(unsigned start, unsigned end) noexcept {
|
||||
playlist.Shuffle(pc, start, end);
|
||||
}
|
||||
|
||||
@@ -142,7 +171,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
playlist.SetPriorityId(pc, song_id, priority);
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
void Stop() noexcept {
|
||||
playlist.Stop(pc);
|
||||
}
|
||||
|
||||
@@ -174,27 +203,27 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
playlist.SeekCurrent(pc, seek_time, relative);
|
||||
}
|
||||
|
||||
void SetRepeat(bool new_value) {
|
||||
void SetRepeat(bool new_value) noexcept {
|
||||
playlist.SetRepeat(pc, new_value);
|
||||
}
|
||||
|
||||
bool GetRandom() const {
|
||||
bool GetRandom() const noexcept {
|
||||
return playlist.GetRandom();
|
||||
}
|
||||
|
||||
void SetRandom(bool new_value) {
|
||||
void SetRandom(bool new_value) noexcept {
|
||||
playlist.SetRandom(pc, new_value);
|
||||
}
|
||||
|
||||
void SetSingle(SingleMode new_value) {
|
||||
void SetSingle(SingleMode new_value) noexcept {
|
||||
playlist.SetSingle(pc, new_value);
|
||||
}
|
||||
|
||||
void SetConsume(bool new_value) {
|
||||
void SetConsume(bool new_value) noexcept {
|
||||
playlist.SetConsume(new_value);
|
||||
}
|
||||
|
||||
void SetReplayGainMode(ReplayGainMode mode) {
|
||||
void SetReplayGainMode(ReplayGainMode mode) noexcept {
|
||||
replay_gain_mode = mode;
|
||||
UpdateEffectiveReplayGainMode();
|
||||
}
|
||||
@@ -203,7 +232,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
* Publishes the effective #ReplayGainMode to all subsystems.
|
||||
* #ReplayGainMode::AUTO is substituted.
|
||||
*/
|
||||
void UpdateEffectiveReplayGainMode();
|
||||
void UpdateEffectiveReplayGainMode() noexcept;
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
/**
|
||||
@@ -211,7 +240,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
* if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
const Database *GetDatabase() const;
|
||||
const Database *GetDatabase() const noexcept;
|
||||
|
||||
const Database &GetDatabaseOrThrow() const;
|
||||
|
||||
@@ -219,14 +248,14 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
* The database has been modified. Propagate the change to
|
||||
* all subsystems.
|
||||
*/
|
||||
void DatabaseModified(const Database &db);
|
||||
void DatabaseModified(const Database &db) noexcept;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A tag in the play queue has been modified by the player
|
||||
* thread. Propagate the change to all subsystems.
|
||||
*/
|
||||
void TagModified();
|
||||
void TagModified() noexcept;
|
||||
|
||||
/**
|
||||
* The tag of the given song has been modified. Propagate the
|
||||
@@ -237,19 +266,19 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
/**
|
||||
* Synchronize the player with the play queue.
|
||||
*/
|
||||
void SyncWithPlayer();
|
||||
void SyncWithPlayer() noexcept;
|
||||
|
||||
/**
|
||||
* Border pause has just been enabled. Change single mode to off
|
||||
* if it was one-shot.
|
||||
*/
|
||||
void BorderPause();
|
||||
void BorderPause() noexcept;
|
||||
|
||||
private:
|
||||
/* virtual methods from class QueueListener */
|
||||
void OnQueueModified() override;
|
||||
void OnQueueOptionsChanged() override;
|
||||
void OnQueueSongStarted() override;
|
||||
void OnQueueModified() noexcept override;
|
||||
void OnQueueOptionsChanged() noexcept override;
|
||||
void OnQueueSongStarted() noexcept override;
|
||||
|
||||
/* virtual methods from class PlayerListener */
|
||||
void OnPlayerSync() noexcept override;
|
||||
@@ -257,10 +286,13 @@ private:
|
||||
void OnBorderPause() noexcept override;
|
||||
|
||||
/* virtual methods from class MixerListener */
|
||||
void OnMixerVolumeChanged(Mixer &mixer, int volume) override;
|
||||
void OnMixerVolumeChanged(Mixer &mixer, int volume) noexcept override;
|
||||
|
||||
/* callback for #idle_monitor */
|
||||
void OnIdleMonitor(unsigned mask) noexcept;
|
||||
|
||||
/* callback for #global_events */
|
||||
void OnGlobalEvent(unsigned mask);
|
||||
void OnGlobalEvent(unsigned mask) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,14 +22,15 @@
|
||||
#include "config/Param.hxx"
|
||||
#include "config/Data.hxx"
|
||||
#include "config/Option.hxx"
|
||||
#include "util/IterableSplitString.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <utility>
|
||||
|
||||
static constexpr char PERMISSION_PASSWORD_CHAR = '@';
|
||||
static constexpr char PERMISSION_SEPARATOR = ',';
|
||||
@@ -54,35 +55,25 @@ static unsigned local_permissions;
|
||||
#endif
|
||||
|
||||
static unsigned
|
||||
ParsePermission(const char *p)
|
||||
ParsePermission(StringView s)
|
||||
{
|
||||
for (auto i = permission_names; i->name != nullptr; ++i)
|
||||
if (strcmp(p, i->name) == 0)
|
||||
if (s.Equals(i->name))
|
||||
return i->value;
|
||||
|
||||
throw FormatRuntimeError("unknown permission \"%s\"", p);
|
||||
throw FormatRuntimeError("unknown permission \"%.*s\"",
|
||||
int(s.size), s.data);
|
||||
}
|
||||
|
||||
static unsigned parsePermissions(const char *string)
|
||||
{
|
||||
assert(string != nullptr);
|
||||
|
||||
const char *const end = string + strlen(string);
|
||||
|
||||
unsigned permission = 0;
|
||||
while (true) {
|
||||
const char *comma = std::find(string, end,
|
||||
PERMISSION_SEPARATOR);
|
||||
if (comma > string) {
|
||||
const std::string name(string, comma);
|
||||
permission |= ParsePermission(name.c_str());
|
||||
}
|
||||
|
||||
if (comma == end)
|
||||
break;
|
||||
|
||||
string = comma + 1;
|
||||
}
|
||||
for (const auto i : IterableSplitString(string, PERMISSION_SEPARATOR))
|
||||
if (!i.empty())
|
||||
permission |= ParsePermission(i);
|
||||
|
||||
return permission;
|
||||
}
|
||||
@@ -90,48 +81,44 @@ static unsigned parsePermissions(const char *string)
|
||||
void
|
||||
initPermissions(const ConfigData &config)
|
||||
{
|
||||
unsigned permission;
|
||||
|
||||
permission_default = PERMISSION_READ | PERMISSION_ADD |
|
||||
PERMISSION_CONTROL | PERMISSION_ADMIN;
|
||||
|
||||
for (const auto ¶m : config.GetParamList(ConfigOption::PASSWORD)) {
|
||||
permission_default = 0;
|
||||
|
||||
const char *separator = strchr(param.value.c_str(),
|
||||
PERMISSION_PASSWORD_CHAR);
|
||||
param.With([](const char *value){
|
||||
const char *separator = std::strchr(value,
|
||||
PERMISSION_PASSWORD_CHAR);
|
||||
|
||||
if (separator == NULL)
|
||||
throw FormatRuntimeError("\"%c\" not found in password string "
|
||||
"\"%s\", line %i",
|
||||
PERMISSION_PASSWORD_CHAR,
|
||||
param.value.c_str(),
|
||||
param.line);
|
||||
if (separator == nullptr)
|
||||
throw FormatRuntimeError("\"%c\" not found in password string",
|
||||
PERMISSION_PASSWORD_CHAR);
|
||||
|
||||
std::string password(param.value.c_str(), separator);
|
||||
std::string password(value, separator);
|
||||
|
||||
permission = parsePermissions(separator + 1);
|
||||
|
||||
permission_passwords.insert(std::make_pair(std::move(password),
|
||||
permission));
|
||||
unsigned permission = parsePermissions(separator + 1);
|
||||
permission_passwords.insert(std::make_pair(std::move(password),
|
||||
permission));
|
||||
});
|
||||
}
|
||||
|
||||
const ConfigParam *param;
|
||||
param = config.GetParam(ConfigOption::DEFAULT_PERMS);
|
||||
|
||||
if (param)
|
||||
permission_default = parsePermissions(param->value.c_str());
|
||||
config.With(ConfigOption::DEFAULT_PERMS, [](const char *value){
|
||||
if (value != nullptr)
|
||||
permission_default = parsePermissions(value);
|
||||
});
|
||||
|
||||
#ifdef HAVE_UN
|
||||
param = config.GetParam(ConfigOption::LOCAL_PERMISSIONS);
|
||||
if (param != nullptr)
|
||||
local_permissions = parsePermissions(param->value.c_str());
|
||||
else
|
||||
local_permissions = permission_default;
|
||||
local_permissions = config.With(ConfigOption::LOCAL_PERMISSIONS, [](const char *value){
|
||||
return value != nullptr
|
||||
? parsePermissions(value)
|
||||
: permission_default;
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
int getPermissionFromPassword(char const* password, unsigned* permission)
|
||||
int
|
||||
getPermissionFromPassword(const char *password, unsigned *permission) noexcept
|
||||
{
|
||||
auto i = permission_passwords.find(password);
|
||||
if (i == permission_passwords.end())
|
||||
@@ -141,7 +128,8 @@ int getPermissionFromPassword(char const* password, unsigned* permission)
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getDefaultPermissions(void)
|
||||
unsigned
|
||||
getDefaultPermissions() noexcept
|
||||
{
|
||||
return permission_default;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,10 +30,11 @@ static constexpr unsigned PERMISSION_ADD = 2;
|
||||
static constexpr unsigned PERMISSION_CONTROL = 4;
|
||||
static constexpr unsigned PERMISSION_ADMIN = 8;
|
||||
|
||||
int getPermissionFromPassword(char const* password, unsigned* permission);
|
||||
int
|
||||
getPermissionFromPassword(const char *password, unsigned *permission) noexcept;
|
||||
|
||||
unsigned
|
||||
getDefaultPermissions();
|
||||
getDefaultPermissions() noexcept;
|
||||
|
||||
#ifdef HAVE_UN
|
||||
unsigned
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,7 +25,8 @@
|
||||
#include "util/StringStrip.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <string.h>
|
||||
#include <cstring>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void
|
||||
@@ -49,8 +50,8 @@ playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
|
||||
const char *value;
|
||||
|
||||
while ((line = file.ReadLine()) != nullptr &&
|
||||
strcmp(line, "playlist_end") != 0) {
|
||||
colon = strchr(line, ':');
|
||||
std::strcmp(line, "playlist_end") != 0) {
|
||||
colon = std::strchr(line, ':');
|
||||
if (colon == nullptr || colon == line)
|
||||
throw FormatRuntimeError("unknown line in db: %s",
|
||||
line);
|
||||
@@ -58,7 +59,7 @@ playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
|
||||
*colon++ = 0;
|
||||
value = StripLeft(colon);
|
||||
|
||||
if (strcmp(line, "mtime") == 0)
|
||||
if (std::strcmp(line, "mtime") == 0)
|
||||
pm.mtime = std::chrono::system_clock::from_time_t(strtol(value, nullptr, 10));
|
||||
else
|
||||
throw FormatRuntimeError("unknown line in db: %s",
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -39,15 +39,11 @@
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/FileInfo.hxx"
|
||||
#include "fs/DirectoryReader.hxx"
|
||||
#include "util/Macros.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/UriExtract.hxx"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
static const char PLAYLIST_COMMENT = '#';
|
||||
|
||||
@@ -84,9 +80,9 @@ spl_valid_name(const char *name_utf8)
|
||||
* filenames isn't going to happen, either.
|
||||
*/
|
||||
|
||||
return strchr(name_utf8, '/') == nullptr &&
|
||||
strchr(name_utf8, '\n') == nullptr &&
|
||||
strchr(name_utf8, '\r') == nullptr;
|
||||
return std::strchr(name_utf8, '/') == nullptr &&
|
||||
std::strchr(name_utf8, '\n') == nullptr &&
|
||||
std::strchr(name_utf8, '\r') == nullptr;
|
||||
}
|
||||
|
||||
static const AllocatedPath &
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,11 +22,6 @@
|
||||
#include "PlaylistError.hxx"
|
||||
#include "queue/Playlist.hxx"
|
||||
#include "queue/QueuePrint.hxx"
|
||||
#include "SongPrint.hxx"
|
||||
#include "Partition.hxx"
|
||||
#include "Instance.hxx"
|
||||
#include "db/Interface.hxx"
|
||||
#include "client/Response.hxx"
|
||||
|
||||
#define SONG_FILE "file: "
|
||||
#define SONG_TIME "Time: "
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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_PLAYLIST_PRINT_HXX
|
||||
#define MPD_PLAYLIST_PRINT_HXX
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
struct playlist;
|
||||
class SongFilter;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,9 +30,7 @@
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/io/FileOutputStream.hxx"
|
||||
#include "fs/io/BufferedOutputStream.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
|
||||
#include <exception>
|
||||
#include "util/UriExtract.hxx"
|
||||
|
||||
static void
|
||||
playlist_print_path(BufferedOutputStream &os, const Path path)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -27,10 +27,20 @@
|
||||
* that this plugin is unavailable. It will be disabled, and MPD can
|
||||
* continue initialization.
|
||||
*/
|
||||
class PluginUnavailable final : public std::runtime_error {
|
||||
class PluginUnavailable : public std::runtime_error {
|
||||
public:
|
||||
explicit PluginUnavailable(const char *msg)
|
||||
:std::runtime_error(msg) {}
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/**
|
||||
* Like #PluginUnavailable, but denotes that the plugin is not
|
||||
* available because it was not explicitly enabled in the
|
||||
* configuration. The message may describe the necessary steps to
|
||||
* enable it.
|
||||
*/
|
||||
class PluginUnconfigured : public PluginUnavailable {
|
||||
public:
|
||||
using PluginUnavailable::PluginUnavailable;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,13 +19,12 @@
|
||||
|
||||
#include "ReplayGainGlobal.hxx"
|
||||
#include "ReplayGainConfig.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/Data.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
static float
|
||||
ParsePreamp(const char *s)
|
||||
@@ -33,25 +32,14 @@ ParsePreamp(const char *s)
|
||||
assert(s != nullptr);
|
||||
|
||||
char *endptr;
|
||||
float f = strtod(s, &endptr);
|
||||
float f = std::strtof(s, &endptr);
|
||||
if (endptr == s || *endptr != '\0')
|
||||
throw std::invalid_argument("Not a numeric value");
|
||||
|
||||
if (f < -15 || f > 15)
|
||||
if (f < -15.0f || f > 15.0f)
|
||||
throw std::invalid_argument("Number must be between -15 and 15");
|
||||
|
||||
return pow(10, f / 20.0);
|
||||
}
|
||||
|
||||
static float
|
||||
ParsePreamp(const ConfigParam &p)
|
||||
{
|
||||
try {
|
||||
return ParsePreamp(p.value.c_str());
|
||||
} catch (...) {
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
|
||||
p.line));
|
||||
}
|
||||
return std::pow(10.0f, f / 20.0f);
|
||||
}
|
||||
|
||||
ReplayGainConfig
|
||||
@@ -59,13 +47,17 @@ LoadReplayGainConfig(const ConfigData &config)
|
||||
{
|
||||
ReplayGainConfig replay_gain_config;
|
||||
|
||||
const auto *param = config.GetParam(ConfigOption::REPLAYGAIN_PREAMP);
|
||||
if (param)
|
||||
replay_gain_config.preamp = ParsePreamp(*param);
|
||||
replay_gain_config.preamp = config.With(ConfigOption::REPLAYGAIN_PREAMP, [](const char *s){
|
||||
return s != nullptr
|
||||
? ParsePreamp(s)
|
||||
: 1.0f;
|
||||
});
|
||||
|
||||
param = config.GetParam(ConfigOption::REPLAYGAIN_MISSING_PREAMP);
|
||||
if (param)
|
||||
replay_gain_config.missing_preamp = ParsePreamp(*param);
|
||||
replay_gain_config.missing_preamp = config.With(ConfigOption::REPLAYGAIN_MISSING_PREAMP, [](const char *s){
|
||||
return s != nullptr
|
||||
? ParsePreamp(s)
|
||||
: 1.0f;
|
||||
});
|
||||
|
||||
replay_gain_config.limit = config.GetBool(ConfigOption::REPLAYGAIN_LIMIT,
|
||||
ReplayGainConfig::DEFAULT_LIMIT);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 @@
|
||||
#include "ReplayGainInfo.hxx"
|
||||
#include "ReplayGainConfig.hxx"
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
float
|
||||
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
||||
@@ -28,13 +28,13 @@ ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
||||
float scale;
|
||||
|
||||
if (IsDefined()) {
|
||||
scale = pow(10.0, gain / 20.0);
|
||||
scale = std::pow(10.0f, gain / 20.0f);
|
||||
scale *= config.preamp;
|
||||
if (scale > 15.0)
|
||||
scale = 15.0;
|
||||
if (scale > 15.0f)
|
||||
scale = 15.0f;
|
||||
|
||||
if (config.limit && scale * peak > 1.0)
|
||||
scale = 1.0 / peak;
|
||||
if (config.limit && scale * peak > 1.0f)
|
||||
scale = 1.0f / peak;
|
||||
} else
|
||||
scale = config.missing_preamp;
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 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 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "ReplayGainMode.hxx"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "util/Compiler.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
enum class ReplayGainMode : uint8_t {
|
||||
OFF,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "SingleMode.hxx"
|
||||
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "util/Compiler.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <cstdint>
|
||||
|
||||
enum class SingleMode : uint8_t {
|
||||
OFF,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "PlaylistError.hxx"
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
@@ -54,11 +54,11 @@ SongLoader::LoadFile(const char *path_utf8, Path path_fs) const
|
||||
{
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(path_utf8);
|
||||
if (suffix != nullptr)
|
||||
const auto suffix = storage->MapToRelativeUTF8(path_utf8);
|
||||
if (suffix.data() != nullptr)
|
||||
/* this path was relative to the music
|
||||
directory - obtain it from the database */
|
||||
return LoadFromDatabase(suffix);
|
||||
return LoadFromDatabase(std::string(suffix).c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* Copyright 2003-2020 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user