Compare commits
1773 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6c65cba58 | ||
|
|
f849b07766 | ||
|
|
2da3cff1e8 | ||
|
|
0c965d0573 | ||
|
|
77c14692c9 | ||
|
|
226eb26300 | ||
|
|
2d606fa989 | ||
|
|
7a0342c8bb | ||
|
|
42c9d765cf | ||
|
|
a8a80ee689 | ||
|
|
f9bdb4b0b8 | ||
|
|
9332527872 | ||
|
|
84f772357e | ||
|
|
f2b9785a67 | ||
|
|
eeaec99c59 | ||
|
|
b0002e3b73 | ||
|
|
27c589da97 | ||
|
|
6484af472b | ||
|
|
92a218b7a9 | ||
|
|
d69a1f98af | ||
|
|
23a6f62ea3 | ||
|
|
e0d3ca71b3 | ||
|
|
4f40b9f7cf | ||
|
|
bb009daf66 | ||
|
|
dc432f3ffa | ||
|
|
37710195ca | ||
|
|
7b9295ff99 | ||
|
|
5f61d440eb | ||
|
|
6bc73a9ebe | ||
|
|
1195eb266e | ||
|
|
3562a3e51e | ||
|
|
bbfa6fe632 | ||
|
|
bf97d13d0b | ||
|
|
b5673b6333 | ||
|
|
ee802867df | ||
|
|
ecaa51e322 | ||
|
|
0779333064 | ||
|
|
6f1a4a73b7 | ||
|
|
945ed2610a | ||
|
|
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 | ||
|
|
6c240f667c | ||
|
|
3040ddb5ec | ||
|
|
fdb28eb0c4 | ||
|
|
7ded244a61 | ||
|
|
8ed533acf3 | ||
|
|
a27580d0cc | ||
|
|
905db05cf9 | ||
|
|
4242aee21e | ||
|
|
e71bd2a08b | ||
|
|
e53a4d0a9e | ||
|
|
159389164a | ||
|
|
0a92fbc18e | ||
|
|
138c29320b | ||
|
|
8f00dbea45 | ||
|
|
f3fd2eb618 | ||
|
|
fc92db83cf | ||
|
|
3b0f8d5516 | ||
|
|
a5273d6992 | ||
|
|
6979be008c | ||
|
|
71792ffd43 | ||
|
|
3c145c0f49 | ||
|
|
b18074f899 | ||
|
|
3d8067a041 | ||
|
|
f6fe001fa9 | ||
|
|
55b8f2c533 | ||
|
|
32a5bf043b | ||
|
|
8437b141a4 | ||
|
|
1f0881eec0 | ||
|
|
8d2079482f | ||
|
|
c331c75fde | ||
|
|
6080c3b4ba | ||
|
|
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 | ||
|
|
5ccfcffcc1 | ||
|
|
afe2aaa5f6 | ||
|
|
9b11caa0e6 | ||
|
|
a689b881d3 | ||
|
|
e94c436264 | ||
|
|
bad829509e | ||
|
|
9c66b0414a | ||
|
|
4d453a8313 | ||
|
|
61d7b436a2 | ||
|
|
cdddaf21b0 | ||
|
|
b267ba5f0a | ||
|
|
8270043053 | ||
|
|
c00ce42bca | ||
|
|
3852ddbbce | ||
|
|
672bc3ab67 | ||
|
|
62229f14da | ||
|
|
a4c925c8d7 | ||
|
|
60610e90b1 | ||
|
|
90184e0ce7 | ||
|
|
7d7bd51bc0 | ||
|
|
71e551df42 | ||
|
|
9c3e1d450a | ||
|
|
3540cf26b1 | ||
|
|
60f2116202 | ||
|
|
4ff2532330 | ||
|
|
9c15760c4d | ||
|
|
e1c43ec65f | ||
|
|
4dd10894ba | ||
|
|
608d7ec1e7 | ||
|
|
8474599ed6 | ||
|
|
ab39f64fc0 | ||
|
|
185fbca282 | ||
|
|
6e3b2fd844 | ||
|
|
dab39dc778 | ||
|
|
8cd5e79fbd | ||
|
|
1de3ac6c78 | ||
|
|
abe06a5fa6 | ||
|
|
85c27840a3 | ||
|
|
81c16273c5 | ||
|
|
801ae86b5d | ||
|
|
5619fd0bba | ||
|
|
200258c7c3 | ||
|
|
5418bb49fb | ||
|
|
3449c14ff5 | ||
|
|
cfa4524cb3 | ||
|
|
4fd0c84f46 | ||
|
|
e41a52d909 | ||
|
|
01e00632cc | ||
|
|
9bad5ee3c5 | ||
|
|
e87454ae88 | ||
|
|
f319f88df4 | ||
|
|
637840264a | ||
|
|
3888bafc1f | ||
|
|
adad4c7298 | ||
|
|
d54acbcffd | ||
|
|
36a89e8fe7 | ||
|
|
8e6a21a9c2 | ||
|
|
86613af37e | ||
|
|
ba3ff10ccd | ||
|
|
1ec283d213 | ||
|
|
2261bcb5d3 | ||
|
|
0e17629445 | ||
|
|
0da6344726 | ||
|
|
c560ec8ea6 | ||
|
|
cade4e71c4 | ||
|
|
403612c666 | ||
|
|
7fe49cf24d | ||
|
|
d2115e908a | ||
|
|
56c234b410 | ||
|
|
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 | ||
|
|
82743dfd02 | ||
|
|
f00f8b002a | ||
|
|
33694642bd | ||
|
|
c71242d743 | ||
|
|
2229e86673 | ||
|
|
f24c274f5c | ||
|
|
3824bf66ca | ||
|
|
d942f874ae | ||
|
|
01632d37ef | ||
|
|
c45f113856 | ||
|
|
e0a8fd398c | ||
|
|
3e97058151 | ||
|
|
51b1dd8672 | ||
|
|
98a7d8da6c | ||
|
|
acb29f792f | ||
|
|
cd364023ae | ||
|
|
8d34a1cfc6 | ||
|
|
73a1f078a6 | ||
|
|
b7ce452308 | ||
|
|
5faf76051d | ||
|
|
5fe70a3417 | ||
|
|
7a68b1e71f | ||
|
|
d5468dfe89 | ||
|
|
976372ff63 | ||
|
|
c977d646c7 | ||
|
|
ac50bb5d2b | ||
|
|
85e33f7d60 | ||
|
|
7646866a32 | ||
|
|
d072b3cb17 | ||
|
|
646fef108a | ||
|
|
d1cc73775f | ||
|
|
29d05cdb8e | ||
|
|
322d6f2a40 | ||
|
|
7729713924 | ||
|
|
351a4a80d2 | ||
|
|
87f7b0f0bb | ||
|
|
6d3190fe5f | ||
|
|
5d787806fe | ||
|
|
9abb686eeb | ||
|
|
dea0cc165d | ||
|
|
07e0a31d02 | ||
|
|
f24bcc7f42 | ||
|
|
89800324cb | ||
|
|
050e30418c | ||
|
|
36a678276b | ||
|
|
d4a6d647a0 | ||
|
|
5397d18ed9 | ||
|
|
2d3b51665e | ||
|
|
7b03f55cb4 | ||
|
|
b84444b680 | ||
|
|
1e421cbcb2 | ||
|
|
a4eed3e330 | ||
|
|
b9db8ddee6 | ||
|
|
9cf1385765 | ||
|
|
a3963de668 | ||
|
|
7d2c4ec775 | ||
|
|
1de5bd64d8 | ||
|
|
1923cf3844 | ||
|
|
196d5fde65 | ||
|
|
140d8547c7 | ||
|
|
42eb69f46f | ||
|
|
6f579ddc95 | ||
|
|
8e4cb3217e | ||
|
|
7bcccbedad | ||
|
|
7c62887df7 | ||
|
|
3fc859c42d | ||
|
|
f1ad21d2bf | ||
|
|
535a099a27 | ||
|
|
50003f6ad2 | ||
|
|
0914644d2b | ||
|
|
7e41c4de58 | ||
|
|
452c41b71f | ||
|
|
4b0444e760 | ||
|
|
ecad6d936a | ||
|
|
568deefd68 | ||
|
|
40d0420648 | ||
|
|
afb29942b0 | ||
|
|
15fa780c99 | ||
|
|
9db3809c7b | ||
|
|
dfed9546aa | ||
|
|
469cd9582f | ||
|
|
bc6eca2115 | ||
|
|
72ec641f0d | ||
|
|
4f22f4d357 | ||
|
|
4c52001a35 | ||
|
|
faa04966af | ||
|
|
302eff0a59 | ||
|
|
bcc4e97c60 | ||
|
|
4968dd4faa | ||
|
|
0896f44455 | ||
|
|
620872390b | ||
|
|
f7c326dbeb | ||
|
|
50de3a7886 | ||
|
|
36cad54ccd | ||
|
|
5ad6e7fec5 | ||
|
|
0bb943ba3e | ||
|
|
b64fdae938 | ||
|
|
80a0cf694f | ||
|
|
0b2444450f | ||
|
|
faf149d08e | ||
|
|
e01bbad7bb | ||
|
|
7e3eaa5921 | ||
|
|
6fe4068c8e | ||
|
|
8472135859 | ||
|
|
0c9e25b3c4 | ||
|
|
943a67c805 | ||
|
|
881d91f86b | ||
|
|
54d57fdcc2 | ||
|
|
f6f30d6d64 | ||
|
|
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 | ||
|
|
4013fa15b9 | ||
|
|
ac1b844c15 | ||
|
|
b8614048d4 | ||
|
|
aed0d13591 | ||
|
|
9d02103ebe | ||
|
|
61784c2144 | ||
|
|
7059215795 | ||
|
|
2190cc7927 | ||
|
|
75dc9506c2 | ||
|
|
4f11fa0d41 | ||
|
|
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 | ||
|
|
ce7ec2b3f5 | ||
|
|
b11c5f8d30 | ||
|
|
fada4aa529 | ||
|
|
aa0e121ade | ||
|
|
b4700039fd | ||
|
|
ab41c16eb5 | ||
|
|
04101f37b8 | ||
|
|
8c31370534 | ||
|
|
2306b0d78c | ||
|
|
cb1a9045e6 | ||
|
|
e92af06664 | ||
|
|
af20a1c994 | ||
|
|
44d7a1d8d2 | ||
|
|
4937d77cb6 | ||
|
|
53f8053188 | ||
|
|
e654c6e005 | ||
|
|
4b0e288f00 | ||
|
|
71ace2fbac | ||
|
|
fb450d2f41 | ||
|
|
84784badce | ||
|
|
5990e46de2 | ||
|
|
7dea5db5df | ||
|
|
756560eac3 | ||
|
|
dca0519336 | ||
|
|
b9a7f30443 | ||
|
|
32a17a997a | ||
|
|
803a48e96d | ||
|
|
bf41d1ad2b | ||
|
|
d27e534a85 | ||
|
|
6d54928d7c | ||
|
|
0dffe05bf7 | ||
|
|
9ef1f10319 | ||
|
|
23fcfdbd2a | ||
|
|
3401d26d4c | ||
|
|
256753ea46 | ||
|
|
76cd5f8595 | ||
|
|
5684025847 | ||
|
|
744bd1eadc | ||
|
|
2bc127bb43 | ||
|
|
7770298a65 | ||
|
|
fa50cdb39e | ||
|
|
816ef12088 | ||
|
|
5ff786e59c | ||
|
|
80fe88e8f6 | ||
|
|
a1afe9afc6 | ||
|
|
fe598e7d30 | ||
|
|
4475b8ca04 | ||
|
|
a714bdb0ce | ||
|
|
087874620f | ||
|
|
f1116c9258 | ||
|
|
d01fb6730a | ||
|
|
7bfe6a3304 | ||
|
|
57b8e7f651 | ||
|
|
9a577f8060 | ||
|
|
d75a0d714e | ||
|
|
9be3a1554e | ||
|
|
7764719513 | ||
|
|
dcbb9fe07c | ||
|
|
e3b347820a | ||
|
|
83acbe1002 | ||
|
|
a84bf5a92e | ||
|
|
732bdc800d | ||
|
|
a8661b5931 | ||
|
|
a72878c5b9 | ||
|
|
bd4df1ae5d | ||
|
|
a93b7172aa | ||
|
|
908b6a1939 | ||
|
|
561ccf600f | ||
|
|
aee861c009 | ||
|
|
2cc1dd28cd | ||
|
|
f8d7bc1c34 | ||
|
|
a684b4fff1 | ||
|
|
c82cef3aa6 | ||
|
|
683d5848f4 | ||
|
|
5680a3a4b7 | ||
|
|
15ce8eb487 | ||
|
|
b7744be208 | ||
|
|
63c5d66016 | ||
|
|
d09bd9178f | ||
|
|
7d8b1860c3 | ||
|
|
b06825829b | ||
|
|
ba4cd47fd8 | ||
|
|
bbe403f141 | ||
|
|
5df2707d98 | ||
|
|
4859ea468f | ||
|
|
2a8830db70 | ||
|
|
fed9b6fd74 | ||
|
|
b02890eb8a | ||
|
|
da882a6eb6 | ||
|
|
aeb89aa9d6 | ||
|
|
f885807ecc | ||
|
|
b826fd71f0 | ||
|
|
ae35df1126 | ||
|
|
80e55f6bfc | ||
|
|
e7411c0c4b | ||
|
|
e9af692973 | ||
|
|
0cf90ee8b6 | ||
|
|
dc3c0c8866 | ||
|
|
1c46bb1ba6 | ||
|
|
2e8f42c6ad | ||
|
|
b449627265 | ||
|
|
2b301ffd2c | ||
|
|
ef0765ca10 | ||
|
|
9766ac6db3 | ||
|
|
940206d106 | ||
|
|
65bbb975d2 | ||
|
|
32799ff682 | ||
|
|
ce093be12c | ||
|
|
2c276770f0 | ||
|
|
75a592f629 | ||
|
|
c129ca9f63 | ||
|
|
1e03457746 | ||
|
|
13ce07d181 | ||
|
|
43ac264f54 | ||
|
|
cbaa98c1a1 | ||
|
|
ed327c597a | ||
|
|
496f43e25d | ||
|
|
d659c7df19 | ||
|
|
f8403a1d29 | ||
|
|
ebb952c4ad | ||
|
|
bea3b954a5 | ||
|
|
129d8e89b9 | ||
|
|
65778a3774 | ||
|
|
d9841668ff | ||
|
|
3f4437266b | ||
|
|
799097c385 | ||
|
|
4ecd4761c2 | ||
|
|
85d27cbcb9 | ||
|
|
e1867a99e9 | ||
|
|
9b95e65bd9 | ||
|
|
12a86c4975 | ||
|
|
0b9435858b | ||
|
|
f0386459ee | ||
|
|
e98d4670b8 | ||
|
|
56cc42b752 | ||
|
|
ead208987d | ||
|
|
364acc8949 | ||
|
|
a8f4d2b6fc | ||
|
|
0eb113e7c6 | ||
|
|
b2c4a5db14 | ||
|
|
cadfccfd0c | ||
|
|
c89c7f71a2 | ||
|
|
96a9670c69 | ||
|
|
dcc5ce6792 | ||
|
|
23d08820a2 | ||
|
|
b9b906ab20 | ||
|
|
2f3e94f8d0 | ||
|
|
f616bfe354 | ||
|
|
f2c3d86612 | ||
|
|
d7dbf47a3f | ||
|
|
3db584a3ea | ||
|
|
409002b1c3 | ||
|
|
29b542fd36 | ||
|
|
c9590db188 | ||
|
|
0643b5abad | ||
|
|
964804a4c2 | ||
|
|
92495d2b0b | ||
|
|
9270829b5b | ||
|
|
b6243a9945 | ||
|
|
496f88653d | ||
|
|
5ef645df97 | ||
|
|
bf49c9e4e2 | ||
|
|
0da9c91af2 | ||
|
|
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 | ||
|
|
193e637dd9 | ||
|
|
928bee933d | ||
|
|
4d1720c886 | ||
|
|
8f8ed87327 | ||
|
|
28a441c977 | ||
|
|
8cf50b08f2 | ||
|
|
d3cc54d4eb | ||
|
|
71ef0faa2c | ||
|
|
328a6de86e | ||
|
|
f750c8012a | ||
|
|
b0a04b3da8 | ||
|
|
9617bd6c85 | ||
|
|
4c7154bd23 | ||
|
|
4f5c3b349d | ||
|
|
4fabfdabde | ||
|
|
2e9b5e4e78 | ||
|
|
115dd2b5ce | ||
|
|
b18003ddfd | ||
|
|
6ec335dcd5 | ||
|
|
d5d6746ddf | ||
|
|
00d7759cee | ||
|
|
2ecc4e3eed | ||
|
|
7d98145ea8 | ||
|
|
e7c5a59e39 | ||
|
|
71c45d8ebe | ||
|
|
c9081a206a | ||
|
|
818b7e0641 | ||
|
|
e70f40fac1 | ||
|
|
f2cdbeace6 | ||
|
|
e6600b8562 | ||
|
|
bc89ca92b4 | ||
|
|
b968e1b6de | ||
|
|
6c9f9c136b | ||
|
|
9bff5f9e36 | ||
|
|
2bf26a2ff8 | ||
|
|
e33b50d9c5 | ||
|
|
21fa44c0d5 | ||
|
|
44444e1b89 | ||
|
|
ca450663d0 | ||
|
|
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 | ||
|
|
f3d16f6d1b | ||
|
|
6b51429203 | ||
|
|
e2da13b0d3 | ||
|
|
54daa85ac2 | ||
|
|
575ba51931 | ||
|
|
96a1c69c29 | ||
|
|
3895d35a52 | ||
|
|
b717ab0383 | ||
|
|
4f61cd0b93 | ||
|
|
4464cdcc67 | ||
|
|
989790e7f1 | ||
|
|
831bc711ca | ||
|
|
d640961420 | ||
|
|
828c614d57 | ||
|
|
4964ad7800 | ||
|
|
a7976cd0f2 | ||
|
|
bed8a0e040 | ||
|
|
b8a64771c0 | ||
|
|
f357f743a3 | ||
|
|
91e565d92e | ||
|
|
a189a9e478 | ||
|
|
9654a33218 | ||
|
|
9bcd02d178 | ||
|
|
2d61e526de | ||
|
|
7723c481db | ||
|
|
cf9ee33928 | ||
|
|
4a47bbd816 | ||
|
|
7654038d65 | ||
|
|
e4612ecb66 | ||
|
|
9c6850210d | ||
|
|
40a2880857 | ||
|
|
ade712d711 | ||
|
|
175e13099c | ||
|
|
0ed10542cc | ||
|
|
ab830f9afd | ||
|
|
349a2ea7eb | ||
|
|
192ad91010 | ||
|
|
d4d2bc072e | ||
|
|
bcccc8f66c | ||
|
|
848c63e2d5 | ||
|
|
f6d0310f9c | ||
|
|
3ef043392c | ||
|
|
864d6f312d | ||
|
|
f44c67de09 | ||
|
|
91fb91d89c | ||
|
|
8b399b7133 | ||
|
|
9d24f68f51 | ||
|
|
44652fdb13 | ||
|
|
2892a6f5e2 | ||
|
|
2fc40e5575 | ||
|
|
7363fe90bb | ||
|
|
d146bef740 | ||
|
|
1f4c4be1f1 | ||
|
|
90067d16c0 | ||
|
|
cde6c46d2f | ||
|
|
d305f187d5 | ||
|
|
4f6a713b32 | ||
|
|
8f981845dc | ||
|
|
c764b70b3a | ||
|
|
52bb03e136 | ||
|
|
a90685d6cf | ||
|
|
ae19bda1f2 | ||
|
|
f2d8fd769d | ||
|
|
9661062ae2 | ||
|
|
2a07354cad | ||
|
|
fc18fd571c | ||
|
|
51abed9732 | ||
|
|
d00afc912c | ||
|
|
9d0fe725eb | ||
|
|
8a432c9b7f | ||
|
|
187204f03c | ||
|
|
5e5fadb5f2 | ||
|
|
952c793235 | ||
|
|
3e3d8c7f9d | ||
|
|
9b99a9897a | ||
|
|
4f56fdc397 | ||
|
|
c87d6825ec | ||
|
|
00830a20e3 | ||
|
|
d39d2874b4 | ||
|
|
a0a74951b8 | ||
|
|
779a6855ff | ||
|
|
f7ed7446ae | ||
|
|
9d44a6d2ae | ||
|
|
10da9ee7ba | ||
|
|
f9eff31205 | ||
|
|
1d74a029a2 | ||
|
|
6b8ca514bb | ||
|
|
f51e555154 | ||
|
|
61a3c69a06 | ||
|
|
089615a01e | ||
|
|
52bee8f81f | ||
|
|
adc25e648f | ||
|
|
31da8eac9b | ||
|
|
e00464435b | ||
|
|
b81138bda1 | ||
|
|
fe2f8c088a | ||
|
|
6de088140b | ||
|
|
86d0534638 | ||
|
|
af99f9fc90 | ||
|
|
a784c8b1ae | ||
|
|
991bbea875 | ||
|
|
1033dbca2b | ||
|
|
a2d2210713 | ||
|
|
b955334882 | ||
|
|
90ea3bf985 | ||
|
|
83b0871248 | ||
|
|
d8aec4b2dc | ||
|
|
39b302dcad | ||
|
|
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 | ||
|
|
f6125f0c35 | ||
|
|
44aaf51345 | ||
|
|
4e2a551f30 | ||
|
|
f780ac418a | ||
|
|
61a72a5d13 | ||
|
|
0c0a354753 | ||
|
|
3c5f860fb8 | ||
|
|
3da1fa88d0 | ||
|
|
fac15aaffb | ||
|
|
5b01373356 | ||
|
|
a92aa0bedc | ||
|
|
d66f5a8590 | ||
|
|
30ca6b8881 | ||
|
|
c926021599 | ||
|
|
543776d9c9 | ||
|
|
cf631fca50 | ||
|
|
f0ac63d5af | ||
|
|
c1eb0583c4 | ||
|
|
549faa8a9c | ||
|
|
8f6c750064 | ||
|
|
9fc1668de3 | ||
|
|
e9190f4249 | ||
|
|
127b464c59 | ||
|
|
048990cd2f | ||
|
|
01fd6e5e82 | ||
|
|
8bf3f9b874 | ||
|
|
f07f8f7d88 | ||
|
|
39b40ac1fd | ||
|
|
ea639269d8 | ||
|
|
0abaa3ecc5 | ||
|
|
c4d3efe71d | ||
|
|
85e82e3d4d | ||
|
|
beed004b10 | ||
|
|
730e67d766 | ||
|
|
34c6337887 | ||
|
|
2093e53641 | ||
|
|
2f243f2295 | ||
|
|
e69fd0300a | ||
|
|
f43cafbf7d | ||
|
|
53faf77d20 | ||
|
|
bf574dcb0a | ||
|
|
f44011519c | ||
|
|
72b8f33272 | ||
|
|
a17f420d6b | ||
|
|
f97a9ce765 | ||
|
|
bf26adf555 | ||
|
|
0cc94fe30c | ||
|
|
d5d5705213 | ||
|
|
96d74e77eb | ||
|
|
ca8451cdbc | ||
|
|
28e07e900f | ||
|
|
c75dc4a647 | ||
|
|
32380d1db0 | ||
|
|
c9f1354e4d | ||
|
|
e3f9e96eef | ||
|
|
8f9b3cbf0e | ||
|
|
458a1beed9 | ||
|
|
47bb1cd8b5 | ||
|
|
ccc96e25d3 | ||
|
|
33f5e03e80 | ||
|
|
2c3eeb7194 | ||
|
|
79839db3a3 | ||
|
|
d478bdda8e | ||
|
|
fd7caab872 | ||
|
|
e87f0ca771 | ||
|
|
a139279575 | ||
|
|
9fcd33cc8d | ||
|
|
96ff6b9b8b | ||
|
|
fd5e74dbd0 | ||
|
|
b64571f4a5 | ||
|
|
1eae9339f2 | ||
|
|
22a9e866bc | ||
|
|
97e6ea57c4 | ||
|
|
527642a90b | ||
|
|
aebb1baad8 | ||
|
|
bd6b7aa88e | ||
|
|
fcf6415963 | ||
|
|
be79b44dc8 | ||
|
|
17f207ffd1 | ||
|
|
476647bfa0 | ||
|
|
9f246fc0dc | ||
|
|
7de6e4dbac | ||
|
|
15dbb8082e | ||
|
|
1a7e3bb358 | ||
|
|
74380d2ae4 | ||
|
|
d43ce8413a | ||
|
|
923c1b6220 | ||
|
|
09884e608b | ||
|
|
3055c1266d | ||
|
|
931c3a1de0 | ||
|
|
a7b30fcb9e | ||
|
|
e153407b51 | ||
|
|
5675431eaf | ||
|
|
8a136b79e5 | ||
|
|
dffa25c55e | ||
|
|
72a0aeb265 | ||
|
|
e556cd20f7 | ||
|
|
80ec6f976c | ||
|
|
589639f80f | ||
|
|
548aa00111 | ||
|
|
76eb550011 | ||
|
|
c1719a5200 | ||
|
|
b07bbb928a | ||
|
|
3b5a128097 | ||
|
|
fad60f977e | ||
|
|
71f9332bd3 | ||
|
|
3eae3a2826 | ||
|
|
3c1f7c77f0 | ||
|
|
3e40b1d9d2 | ||
|
|
adffbba2a5 | ||
|
|
e239009295 | ||
|
|
3fae2150f5 | ||
|
|
f9ca2f52c1 | ||
|
|
4b81cf0c2c | ||
|
|
e7acbf112c | ||
|
|
120e570da7 | ||
|
|
0019231a37 | ||
|
|
9ae1256ae7 | ||
|
|
e1ac377812 | ||
|
|
7866d1a005 | ||
|
|
3e3ee581a8 | ||
|
|
0e8ca44968 | ||
|
|
12e75a523a | ||
|
|
508ba22789 | ||
|
|
fa13648f2c | ||
|
|
2f83ed90d0 | ||
|
|
5d74b5cee1 | ||
|
|
e8a0ce643a | ||
|
|
9ed4fac341 | ||
|
|
81b2b4a85c | ||
|
|
304d45b551 | ||
|
|
0f488dcecf | ||
|
|
17039aec70 | ||
|
|
fb6cb07912 | ||
|
|
e9e0e02db3 | ||
|
|
03507037e8 | ||
|
|
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 | ||
|
|
66a8fac25e | ||
|
|
1b902e00b4 | ||
|
|
45a091c00c | ||
|
|
923e66738c | ||
|
|
ff3e2c0514 | ||
|
|
6922a2f55e | ||
|
|
219546cb81 | ||
|
|
555a4d738c | ||
|
|
813567bf5c | ||
|
|
16a07bc201 | ||
|
|
1153715608 | ||
|
|
b5c7c16fb4 | ||
|
|
302c0515b7 | ||
|
|
19e4672a54 | ||
|
|
c2dd6808e1 | ||
|
|
2cf6b77627 | ||
|
|
a5c09f4ddb | ||
|
|
1acb9bcedb | ||
|
|
0626e3d21e | ||
|
|
869d215058 | ||
|
|
0cf922b2da | ||
|
|
5e266cd8e4 | ||
|
|
ca5a400dbe | ||
|
|
63fe4d1d17 | ||
|
|
a199f58db5 | ||
|
|
5277297336 | ||
|
|
604d08b2c6 | ||
|
|
ca06d9d3bf | ||
|
|
ed2db04f43 | ||
|
|
de0afa0e08 | ||
|
|
f0d3227d7b | ||
|
|
fb07a7cecc | ||
|
|
c6b08a4d48 | ||
|
|
040e87ad8d | ||
|
|
d5521ead56 | ||
|
|
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 | ||
|
|
f8468451c9 | ||
|
|
65df6ca14e | ||
|
|
36dec47bf7 | ||
|
|
478cedcadf | ||
|
|
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 | ||
|
|
cabcbb059d | ||
|
|
5e21b2db3c | ||
|
|
3a0d6d96c1 | ||
|
|
f39d2d33c0 | ||
|
|
ccc58f2a32 | ||
|
|
ead3dc6a92 | ||
|
|
7d814cc899 | ||
|
|
f5b4606c09 | ||
|
|
d6dbf64efb | ||
|
|
8d18b4c24b | ||
|
|
d28307e082 | ||
|
|
aa5c5bf14f | ||
|
|
2e80477218 | ||
|
|
8b9df85daa | ||
|
|
38d0f02e83 | ||
|
|
edafe4cad6 | ||
|
|
3cbadf42a5 | ||
|
|
1d49f1108f | ||
|
|
791245dec2 | ||
|
|
fe8621906d | ||
|
|
b4fcbdb235 | ||
|
|
f4b5a28596 | ||
|
|
6cbd77fc57 | ||
|
|
1bc78e9f2c | ||
|
|
cb6282e0a7 | ||
|
|
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 | ||
|
|
f6941f9a44 | ||
|
|
d2eb4df8fc | ||
|
|
df33a898d7 | ||
|
|
325c7b8e8b | ||
|
|
380656d8c9 | ||
|
|
9111bc2c21 | ||
|
|
c1272c72b0 | ||
|
|
7d1db5c19f | ||
|
|
2142d070a3 | ||
|
|
9711cee26d | ||
|
|
39baa4e364 | ||
|
|
f339a53e3c | ||
|
|
d9117a272b | ||
|
|
b8a8bdeaec | ||
|
|
8f20edac9d | ||
|
|
8499a662ea | ||
|
|
3f05b7d8b4 | ||
|
|
1d563700a4 | ||
|
|
def6b936c8 | ||
|
|
3610f55479 | ||
|
|
6db84852ae | ||
|
|
41dc36ba92 | ||
|
|
fe32db17d7 | ||
|
|
772aa4f165 | ||
|
|
38298e0cd8 | ||
|
|
1213d979f8 | ||
|
|
a9cb12b745 | ||
|
|
380f73c112 | ||
|
|
9f79d034b3 | ||
|
|
37b54179d8 | ||
|
|
4a745a399f | ||
|
|
c340485dd5 | ||
|
|
f8570dd79f | ||
|
|
4a49f3cce8 | ||
|
|
a1ae455c69 | ||
|
|
7a1b56fe96 | ||
|
|
511826763a | ||
|
|
ef10354d06 | ||
|
|
158458db5f | ||
|
|
e183ab5cf8 | ||
|
|
fef839e2a9 | ||
|
|
9776e43bbe | ||
|
|
5201147ab1 | ||
|
|
fb7daa0d05 | ||
|
|
508e522188 | ||
|
|
2e9f3d8b9f | ||
|
|
976731ab6c | ||
|
|
0d8942e64a | ||
|
|
37a0f04712 | ||
|
|
cde9348009 | ||
|
|
095e6e6ad4 | ||
|
|
9d0bf5e95c | ||
|
|
b1b630a4cc | ||
|
|
c60d374fc8 | ||
|
|
de4fd4c059 | ||
|
|
95d8b30864 | ||
|
|
eb94f409d5 | ||
|
|
93d91936b5 | ||
|
|
2220383d83 | ||
|
|
3231706628 | ||
|
|
ca4e53859d | ||
|
|
8b327f1d9b | ||
|
|
aef0507abb | ||
|
|
61120d2059 | ||
|
|
cc1822810f | ||
|
|
a21c6884f2 | ||
|
|
2700eed08d | ||
|
|
ec2badbedd | ||
|
|
054a7557fa | ||
|
|
977a4570d9 | ||
|
|
6c2077eb7c | ||
|
|
6bab3bcfea | ||
|
|
1d436b3c86 | ||
|
|
a854595886 | ||
|
|
8fc3c5c612 | ||
|
|
4f408bd952 | ||
|
|
f86b14bfc5 | ||
|
|
ec5be91ff6 | ||
|
|
a7a9490a0c | ||
|
|
c0d6008781 | ||
|
|
9f62824e98 | ||
|
|
b824ba3299 | ||
|
|
59c4f9a089 | ||
|
|
7de8fd04a4 | ||
|
|
8158bd218c | ||
|
|
aa1d867b72 | ||
|
|
34c8242133 | ||
|
|
c673528cff | ||
|
|
321f01b95c | ||
|
|
e88667e01c | ||
|
|
fb96907b52 | ||
|
|
09ece26200 | ||
|
|
0c6d22fe47 | ||
|
|
c563eb81a3 | ||
|
|
e864a0dd05 | ||
|
|
42a05bc904 | ||
|
|
4722175049 | ||
|
|
e22bdee808 | ||
|
|
7f87de783f | ||
|
|
c66389a453 | ||
|
|
b63c1a2144 | ||
|
|
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 |
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/
|
/output/
|
||||||
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
||||||
|
/.clangd/
|
||||||
|
/compile_commands.json
|
||||||
|
|||||||
117
.travis.yml
117
.travis.yml
@@ -1,32 +1,73 @@
|
|||||||
language: cpp
|
language: cpp
|
||||||
|
|
||||||
matrix:
|
jobs:
|
||||||
include:
|
include:
|
||||||
|
# Ubuntu Bionic (18.04) with GCC 7
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: bionic
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
|
||||||
- sourceline: 'ppa:saiarcot895/chromium-dev' # for ninja-build
|
|
||||||
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
||||||
packages:
|
packages:
|
||||||
- g++-6
|
|
||||||
- libgtest-dev
|
- libgtest-dev
|
||||||
- boost1.67
|
- libboost-dev
|
||||||
- python3.6
|
- python3.6
|
||||||
- python3-urllib3
|
- python3-urllib3
|
||||||
- ninja-build
|
- ninja-build
|
||||||
before_install:
|
before_install:
|
||||||
- wget https://bootstrap.pypa.io/get-pip.py
|
- wget https://bootstrap.pypa.io/get-pip.py
|
||||||
- /usr/bin/python3.6 get-pip.py --user
|
- /usr/bin/python3.6 get-pip.py --user --no-cache-dir
|
||||||
install:
|
install:
|
||||||
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson
|
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir
|
||||||
env:
|
env:
|
||||||
# use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068
|
- MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH"
|
||||||
- MATRIX_EVAL="export CC=gcc-6 CXX=g++-6 LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH"
|
|
||||||
|
|
||||||
|
# Ubuntu Bionic (18.04) with GCC 7 on big-endian
|
||||||
|
- os: linux
|
||||||
|
arch: s390x
|
||||||
|
dist: bionic
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
||||||
|
packages:
|
||||||
|
- libgtest-dev
|
||||||
|
- libboost-dev
|
||||||
|
- 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:
|
||||||
|
- MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH"
|
||||||
|
|
||||||
|
# Ubuntu Bionic (18.04) with GCC 7 on ARM64
|
||||||
|
- os: linux
|
||||||
|
arch: arm64
|
||||||
|
dist: bionic
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
sources:
|
||||||
|
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
||||||
|
packages:
|
||||||
|
- libgtest-dev
|
||||||
|
- libboost-dev
|
||||||
|
- 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:
|
||||||
|
- MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH"
|
||||||
|
|
||||||
|
# Ubuntu Trusty (16.04) with GCC 8
|
||||||
- os: linux
|
- os: linux
|
||||||
dist: trusty
|
dist: trusty
|
||||||
addons:
|
addons:
|
||||||
@@ -34,7 +75,7 @@ matrix:
|
|||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
- sourceline: 'ppa:mhier/libboost-latest'
|
- sourceline: 'ppa:mhier/libboost-latest'
|
||||||
- sourceline: 'ppa:saiarcot895/chromium-dev' # for ninja-build
|
- sourceline: 'ppa:mstipicevic/ninja-build-1-7-2'
|
||||||
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
- sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson)
|
||||||
packages:
|
packages:
|
||||||
- g++-8
|
- g++-8
|
||||||
@@ -45,31 +86,61 @@ matrix:
|
|||||||
- ninja-build
|
- ninja-build
|
||||||
before_install:
|
before_install:
|
||||||
- wget https://bootstrap.pypa.io/get-pip.py
|
- wget https://bootstrap.pypa.io/get-pip.py
|
||||||
- /usr/bin/python3.6 get-pip.py --user
|
- /usr/bin/python3.6 get-pip.py --user --no-cache-dir
|
||||||
install:
|
install:
|
||||||
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson
|
- /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir
|
||||||
env:
|
env:
|
||||||
# use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068
|
# use gold as workaround for https://sourceware.org/bugzilla/show_bug.cgi?id=17068
|
||||||
- MATRIX_EVAL="export CC=gcc-8 CXX=g++-8 LDFLAGS=-fuse-ld=gold PATH=$HOME/.local/bin:$PATH"
|
- MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH"
|
||||||
|
|
||||||
- os: osx
|
- os: osx
|
||||||
osx_image: xcode9.3beta
|
osx_image: xcode10.3
|
||||||
|
addons:
|
||||||
|
homebrew:
|
||||||
|
packages:
|
||||||
|
- ccache
|
||||||
|
- meson
|
||||||
|
- icu4c
|
||||||
|
- ffmpeg
|
||||||
|
- libnfs
|
||||||
|
- yajl
|
||||||
|
- libupnp
|
||||||
|
- libid3tag
|
||||||
|
- chromaprint
|
||||||
|
- libsamplerate
|
||||||
|
- libsoxr
|
||||||
|
# libzzip appears to be broken on Homebrew: "ld: library not found for -lzzip"
|
||||||
|
#- libzzip
|
||||||
|
- flac
|
||||||
|
- opus
|
||||||
|
- libvorbis
|
||||||
|
- faad2
|
||||||
|
- wavpack
|
||||||
|
- libmpdclient
|
||||||
|
update: true
|
||||||
env:
|
env:
|
||||||
- MATRIX_EVAL=""
|
- MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1"
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
- apt
|
apt: true
|
||||||
- ccache
|
ccache: true
|
||||||
|
directories:
|
||||||
|
- $HOME/Library/Caches/Homebrew
|
||||||
|
|
||||||
|
before_cache:
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew cleanup
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- eval "${MATRIX_EVAL}"
|
- eval "${MATRIX_EVAL}"
|
||||||
# C++14
|
|
||||||
- test "$TRAVIS_OS_NAME" != "osx" || brew update
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# C++14
|
# C++14
|
||||||
- test "$TRAVIS_OS_NAME" != "osx" || brew install ccache meson
|
|
||||||
- test "$TRAVIS_OS_NAME" != "osx" || brew install --HEAD https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb
|
# Work around "Target /usr/local/lib/libgtest.a is a symlink
|
||||||
|
# belonging to nss. You can unlink it" during gtest install
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss
|
||||||
|
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew install https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- ccache -s
|
- ccache -s
|
||||||
|
|||||||
2
AUTHORS
2
AUTHORS
@@ -1,5 +1,5 @@
|
|||||||
Music Player Daemon - http://www.musicpd.org
|
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:
|
The following people have contributed code to MPD:
|
||||||
|
|
||||||
|
|||||||
323
NEWS
323
NEWS
@@ -1,3 +1,326 @@
|
|||||||
|
ver 0.22.3 (2020/11/06)
|
||||||
|
* playlist
|
||||||
|
- add option "as_directory", making CUE file expansion optional
|
||||||
|
* storage
|
||||||
|
- curl: fix crash bug
|
||||||
|
* filter
|
||||||
|
- fix garbage after "Audio format not supported by filter" message
|
||||||
|
- ffmpeg: support planar output
|
||||||
|
- ffmpeg: support sample formats other than 16 bit
|
||||||
|
|
||||||
|
ver 0.22.2 (2020/10/28)
|
||||||
|
* database
|
||||||
|
- simple: purge songs and virtual directories for unavailable plugins
|
||||||
|
on update
|
||||||
|
* input
|
||||||
|
- qobuz/tidal: fix protocol errors due to newlines in error messages
|
||||||
|
- smbclient: disable by default due to libsmbclient crash bug
|
||||||
|
* playlist
|
||||||
|
- soundcloud: fix protocol errors due to newlines in error messages
|
||||||
|
* state_file: save on shutdown
|
||||||
|
|
||||||
|
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
|
||||||
|
* storage
|
||||||
|
- curl: fix corrupt "href" values in the presence of XML entities
|
||||||
|
- curl: unescape "href" values
|
||||||
|
* input
|
||||||
|
- nfs: fix crash bug
|
||||||
|
- nfs: fix freeze bug on reconnect
|
||||||
|
* decoder
|
||||||
|
- gme: adapt to API change in the upcoming version 0.7.0
|
||||||
|
* output
|
||||||
|
- alsa: implement channel mapping for 5.0 and 7.0
|
||||||
|
* player
|
||||||
|
- drain outputs at end of song in "single" mode
|
||||||
|
* Windows
|
||||||
|
- fix case insensitive search
|
||||||
|
|
||||||
|
ver 0.21.22 (2020/04/02)
|
||||||
|
* database
|
||||||
|
- simple: optimize startup
|
||||||
|
* input
|
||||||
|
- curl: fix streaming errors on Android
|
||||||
|
* playlist
|
||||||
|
- rss: support MIME type application/xml
|
||||||
|
* mixer
|
||||||
|
- android: new mixer plugin for "sles" output
|
||||||
|
* Android
|
||||||
|
- TV support
|
||||||
|
* Windows
|
||||||
|
- fix time zone offset check
|
||||||
|
* fix build failures with uClibc-ng
|
||||||
|
|
||||||
|
ver 0.21.21 (2020/03/19)
|
||||||
|
* configuration
|
||||||
|
- fix bug in "metadata_to_use" setting
|
||||||
|
* playlist
|
||||||
|
- asx, xspf: fix corrupt tags in the presence of XML entities
|
||||||
|
* archive
|
||||||
|
- iso9660: skip empty file names to work around libcdio bug
|
||||||
|
* decoder
|
||||||
|
- gme: ignore empty tags
|
||||||
|
* output
|
||||||
|
- solaris: port to NetBSD
|
||||||
|
* raise default "max_connections" value to 100
|
||||||
|
|
||||||
|
ver 0.21.20 (2020/02/16)
|
||||||
|
* decoder
|
||||||
|
- audiofile, ffmpeg, sndfile: handle MIME type "audio/wav"
|
||||||
|
- ffmpeg: fix playback of AIFF and TTA
|
||||||
|
- vorbis, opus: fix seeking in small files
|
||||||
|
* fix backwards seeking on ARM (and other non-x86 CPUs)
|
||||||
|
|
||||||
|
ver 0.21.19 (2020/01/17)
|
||||||
|
* configuration
|
||||||
|
- allow overriding top-level settings in includes
|
||||||
|
* output
|
||||||
|
- pulse: obey Pulse's maximum sample rate (fixes DSD128 playback)
|
||||||
|
* fix build failure with clang 10
|
||||||
|
* fix build failure with Android NDK r20
|
||||||
|
|
||||||
|
ver 0.21.18 (2019/12/24)
|
||||||
|
* protocol
|
||||||
|
- work around Mac OS X bug in the ISO 8601 parser
|
||||||
|
* output
|
||||||
|
- alsa: fix hang bug with ALSA "null" outputs
|
||||||
|
* storage
|
||||||
|
- curl: fix crash bug
|
||||||
|
* drop support for CURL versions older than 7.32.0
|
||||||
|
* reduce unnecessary CPU wakeups
|
||||||
|
|
||||||
|
ver 0.21.17 (2019/12/16)
|
||||||
|
* protocol
|
||||||
|
- relax the ISO 8601 parser: allow omitting field separators, the
|
||||||
|
time of day and the "Z" suffix
|
||||||
|
* archive
|
||||||
|
- zzip: improve error reporting
|
||||||
|
* outputs
|
||||||
|
- jack: mark ports as terminal
|
||||||
|
- shout: declare metadata as UTF-8
|
||||||
|
* fix build failure with -Ddatabase=false
|
||||||
|
|
||||||
|
ver 0.21.16 (2019/10/16)
|
||||||
|
* queue
|
||||||
|
- fix relative destination offset when moving a range
|
||||||
|
* storage
|
||||||
|
- curl: request the "resourcetype" property to fix database update
|
||||||
|
- curl: URL-encode more paths
|
||||||
|
- curl: follow redirects for collections without trailing slash
|
||||||
|
* update
|
||||||
|
- fix crash when music_directory is not a directory
|
||||||
|
* fix build with iconv() instead of ICU
|
||||||
|
|
||||||
|
ver 0.21.15 (2019/09/25)
|
||||||
|
* decoder
|
||||||
|
- dsdiff, dsf: fix displayed bit rate
|
||||||
|
- mpcdec: fix bogus ReplayGain values
|
||||||
|
* output
|
||||||
|
- solaris: fix build with glibc 2.30
|
||||||
|
|
||||||
|
ver 0.21.14 (2019/08/21)
|
||||||
|
* decoder
|
||||||
|
- sidplay: show track durations in database
|
||||||
|
- sidplay: convert tag values from Windows-1252 charset
|
||||||
|
- sidplay: strip text from "Date" tag
|
||||||
|
* player
|
||||||
|
- fix crash after song change
|
||||||
|
- fix seek position after restarting the decoder
|
||||||
|
* protocol
|
||||||
|
- include command name in error responses
|
||||||
|
|
||||||
|
ver 0.21.13 (2019/08/06)
|
||||||
|
* input
|
||||||
|
- cdio_paranoia: require libcdio-paranoia 10.2+0.93+1
|
||||||
|
* decoder
|
||||||
|
- mad: fix crackling sound (0.21.12 regression)
|
||||||
|
* output
|
||||||
|
- jack: improved Windows compatibility
|
||||||
|
|
||||||
|
ver 0.21.12 (2019/08/03)
|
||||||
|
* decoder
|
||||||
|
- mad: update bit rate after seeking
|
||||||
|
- mad: fix several bugs preventing the plugin from decoding the last frame
|
||||||
|
- opus: ignore case in replay gain tag names
|
||||||
|
- opus, vorbis: decode the "end of stream" packet
|
||||||
|
* output
|
||||||
|
- jack: fix mono-to-stereo conversion
|
||||||
|
* player
|
||||||
|
- don't restart unseekable song after failed seek attempt
|
||||||
|
* Windows
|
||||||
|
- support backslash in relative URIs loaded from playlists
|
||||||
|
|
||||||
|
ver 0.21.11 (2019/07/03)
|
||||||
|
* input
|
||||||
|
- tidal: deprecated because Tidal has changed the protocol
|
||||||
|
* decoder
|
||||||
|
- wildmidi: log error if library initialization fails
|
||||||
|
* output
|
||||||
|
- alsa: fix busy loop while draining
|
||||||
|
- alsa: fix missing drain call
|
||||||
|
- alsa: improve xrun-avoiding silence generator
|
||||||
|
- alsa: log when generating silence due to slow decoder
|
||||||
|
- alsa, osx: fix distortions with DSD_U32 and DoP on 32 bit CPUs
|
||||||
|
* protocol
|
||||||
|
- fix "list" with multiple "group" levels
|
||||||
|
|
||||||
|
ver 0.21.10 (2019/06/05)
|
||||||
|
* decoder
|
||||||
|
- opus: fix duplicate tags
|
||||||
|
* output
|
||||||
|
- httpd: reject some well-known URIs
|
||||||
|
* fix crash bug (0.21.9 regression)
|
||||||
|
|
||||||
|
ver 0.21.9 (2019/05/20)
|
||||||
|
* input
|
||||||
|
- buffer: fix deadlock bug
|
||||||
|
* Android
|
||||||
|
- fix crash on ARMv7
|
||||||
|
- request storage permission on Android 6+
|
||||||
|
* fix spurious "single" mode bug
|
||||||
|
|
||||||
|
ver 0.21.8 (2019/04/23)
|
||||||
|
* input
|
||||||
|
- smbclient: download to buffer instead of throttling transfer
|
||||||
|
* output
|
||||||
|
- httpd: add missing mutex lock
|
||||||
|
- httpd: fix use-after-free bug
|
||||||
|
* playlist
|
||||||
|
- soundcloud: fix "Unsupported URI scheme" (0.21.6 regression)
|
||||||
|
* fix Bonjour bug
|
||||||
|
* fix build failure with GCC 9
|
||||||
|
* fix build failure with -Ddatabase=false
|
||||||
|
* systemd: add user socket unit
|
||||||
|
* doc: "list file" is deprecated
|
||||||
|
|
||||||
|
ver 0.21.7 (2019/04/03)
|
||||||
|
* input
|
||||||
|
- qobuz/tidal: scan tags when loading a playlist
|
||||||
|
* require Meson 0.49.0 for native libgcrypt-config support
|
||||||
|
* fix build failure with -Dlocal_socket=false
|
||||||
|
* Haiku
|
||||||
|
- fix build
|
||||||
|
- add version info
|
||||||
|
|
||||||
ver 0.21.6 (2019/03/17)
|
ver 0.21.6 (2019/03/17)
|
||||||
* protocol
|
* protocol
|
||||||
- allow loading playlists specified as absolute filesystem paths
|
- allow loading playlists specified as absolute filesystem paths
|
||||||
|
|||||||
@@ -2,18 +2,25 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.musicpd"
|
package="org.musicpd"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
android:versionCode="28"
|
android:versionCode="51"
|
||||||
android:versionName="0.21.6">
|
android:versionName="0.22.1">
|
||||||
|
|
||||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="26"/>
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28"/>
|
||||||
|
|
||||||
|
<uses-feature android:name="android.software.leanback"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature android:name="android.hardware.touchscreen"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
|
||||||
<application android:allowBackup="true"
|
<application android:allowBackup="true"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
|
android:banner="@drawable/icon"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<activity android:name=".Settings"
|
<activity android:name=".Settings"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
@@ -22,6 +29,14 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".Settings"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<receiver android:name=".Receiver">
|
<receiver android:name=".Receiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
|
|||||||
@@ -25,25 +25,32 @@ android_abis = {
|
|||||||
'arch': 'arm-linux-androideabi',
|
'arch': 'arm-linux-androideabi',
|
||||||
'ndk_arch': 'arm',
|
'ndk_arch': 'arm',
|
||||||
'toolchain_arch': 'arm-linux-androideabi',
|
'toolchain_arch': 'arm-linux-androideabi',
|
||||||
'llvm_triple': 'armv7-none-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': {
|
'arm64-v8a': {
|
||||||
'android_api_level': '21',
|
|
||||||
'arch': 'aarch64-linux-android',
|
'arch': 'aarch64-linux-android',
|
||||||
'ndk_arch': 'arm64',
|
'ndk_arch': 'arm64',
|
||||||
'toolchain_arch': 'aarch64-linux-android',
|
'toolchain_arch': 'aarch64-linux-android',
|
||||||
'llvm_triple': 'aarch64-none-linux-android',
|
'llvm_triple': 'aarch64-linux-android',
|
||||||
'cflags': '',
|
'cflags': '-fpic',
|
||||||
},
|
},
|
||||||
|
|
||||||
'x86': {
|
'x86': {
|
||||||
'arch': 'i686-linux-android',
|
'arch': 'i686-linux-android',
|
||||||
'ndk_arch': 'x86',
|
'ndk_arch': 'x86',
|
||||||
'toolchain_arch': 'x86',
|
'toolchain_arch': 'x86',
|
||||||
'llvm_triple': 'i686-none-linux-android',
|
'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': {
|
||||||
|
'arch': 'x86_64-linux-android',
|
||||||
|
'ndk_arch': 'x86_64',
|
||||||
|
'toolchain_arch': 'x86_64',
|
||||||
|
'llvm_triple': 'x86_64-linux-android',
|
||||||
|
'cflags': '-fPIC -m64',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,27 +83,20 @@ class AndroidNdkToolchain:
|
|||||||
|
|
||||||
ndk_arch = abi_info['ndk_arch']
|
ndk_arch = abi_info['ndk_arch']
|
||||||
android_api_level = '21'
|
android_api_level = '21'
|
||||||
ndk_platform = 'android-' + android_api_level
|
|
||||||
|
|
||||||
# select the NDK compiler
|
# select the NDK compiler
|
||||||
gcc_version = '4.9'
|
gcc_version = '4.9'
|
||||||
|
|
||||||
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
|
|
||||||
sysroot = os.path.join(ndk_path, 'sysroot')
|
|
||||||
target_root = os.path.join(ndk_platform_path, 'arch-' + ndk_arch)
|
|
||||||
|
|
||||||
install_prefix = os.path.join(arch_path, 'root')
|
install_prefix = os.path.join(arch_path, 'root')
|
||||||
|
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
self.install_prefix = install_prefix
|
self.install_prefix = install_prefix
|
||||||
self.sysroot = sysroot
|
|
||||||
|
|
||||||
toolchain_path = os.path.join(ndk_path, 'toolchains', abi_info['toolchain_arch'] + '-' + gcc_version, 'prebuilt', build_arch)
|
toolchain_path = os.path.join(ndk_path, 'toolchains', abi_info['toolchain_arch'] + '-' + gcc_version, 'prebuilt', build_arch)
|
||||||
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
||||||
llvm_triple = abi_info['llvm_triple']
|
llvm_triple = abi_info['llvm_triple'] + android_api_level
|
||||||
|
|
||||||
common_flags = '-Os -g'
|
common_flags = '-Os -g'
|
||||||
common_flags += ' -fPIC'
|
|
||||||
common_flags += ' ' + abi_info['cflags']
|
common_flags += ' ' + abi_info['cflags']
|
||||||
|
|
||||||
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||||
@@ -107,6 +107,9 @@ class AndroidNdkToolchain:
|
|||||||
|
|
||||||
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
||||||
|
|
||||||
|
# required flags from https://android.googlesource.com/platform/ndk/+/ndk-release-r20/docs/BuildSystemMaintainers.md#additional-required-arguments
|
||||||
|
common_flags += ' -fno-addrsig'
|
||||||
|
|
||||||
self.ar = os.path.join(toolchain_bin, arch + '-ar')
|
self.ar = os.path.join(toolchain_bin, arch + '-ar')
|
||||||
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
|
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
|
||||||
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
||||||
@@ -114,15 +117,11 @@ class AndroidNdkToolchain:
|
|||||||
|
|
||||||
self.cflags = common_flags
|
self.cflags = common_flags
|
||||||
self.cxxflags = common_flags
|
self.cxxflags = common_flags
|
||||||
self.cppflags = '--sysroot=' + sysroot + \
|
self.cppflags = ' -isystem ' + os.path.join(install_prefix, 'include')
|
||||||
' -isystem ' + os.path.join(install_prefix, 'include') + \
|
self.ldflags = ' -L' + os.path.join(install_prefix, 'lib') + \
|
||||||
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
|
' -Wl,--exclude-libs=ALL' + \
|
||||||
' -D__ANDROID_API__=' + android_api_level
|
|
||||||
self.ldflags = '--sysroot=' + sysroot + \
|
|
||||||
' -L' + os.path.join(install_prefix, 'lib') + \
|
|
||||||
' -L' + os.path.join(target_root, 'usr', 'lib') + \
|
|
||||||
' -B' + os.path.join(target_root, 'usr', 'lib') + \
|
|
||||||
' ' + common_flags
|
' ' + common_flags
|
||||||
|
self.ldflags = common_flags
|
||||||
self.libs = ''
|
self.libs = ''
|
||||||
|
|
||||||
self.is_arm = ndk_arch == 'arm'
|
self.is_arm = ndk_arch == 'arm'
|
||||||
@@ -130,13 +129,16 @@ class AndroidNdkToolchain:
|
|||||||
self.is_aarch64 = ndk_arch == 'arm64'
|
self.is_aarch64 = ndk_arch == 'arm64'
|
||||||
self.is_windows = False
|
self.is_windows = False
|
||||||
|
|
||||||
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
|
|
||||||
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
|
|
||||||
|
|
||||||
libstdcxx_flags = ''
|
libstdcxx_flags = ''
|
||||||
libstdcxx_cxxflags = libstdcxx_flags + ' -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
libstdcxx_cxxflags = ''
|
||||||
libstdcxx_ldflags = libstdcxx_flags + ' -L' + libcxx_libs_path
|
libstdcxx_ldflags = ''
|
||||||
libstdcxx_libs = '-lc++_static -lc++abi'
|
libstdcxx_libs = '-static-libstdc++'
|
||||||
|
|
||||||
|
if self.is_armv7:
|
||||||
|
# On 32 bit ARM, clang generates no ".eh_frame" section;
|
||||||
|
# instead, the LLVM unwinder library is used for unwinding
|
||||||
|
# the stack after a C++ exception was thrown
|
||||||
|
libstdcxx_libs += ' -lunwind'
|
||||||
|
|
||||||
if use_cxx:
|
if use_cxx:
|
||||||
self.cxxflags += ' ' + libstdcxx_cxxflags
|
self.cxxflags += ' ' + libstdcxx_cxxflags
|
||||||
@@ -166,6 +168,9 @@ thirdparty_libs = [
|
|||||||
opus,
|
opus,
|
||||||
flac,
|
flac,
|
||||||
libid3tag,
|
libid3tag,
|
||||||
|
libmodplug,
|
||||||
|
wildmidi,
|
||||||
|
gme,
|
||||||
ffmpeg,
|
ffmpeg,
|
||||||
curl,
|
curl,
|
||||||
libexpat,
|
libexpat,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ android_sdk = get_option('android_sdk')
|
|||||||
android_abi = get_option('android_abi')
|
android_abi = get_option('android_abi')
|
||||||
|
|
||||||
android_sdk_build_tools_version = '27.0.0'
|
android_sdk_build_tools_version = '27.0.0'
|
||||||
android_sdk_platform = 'android-21'
|
android_sdk_platform = 'android-23'
|
||||||
|
|
||||||
android_build_tools_dir = join_paths(android_sdk, 'build-tools', android_sdk_build_tools_version)
|
android_build_tools_dir = join_paths(android_sdk, 'build-tools', android_sdk_build_tools_version)
|
||||||
android_sdk_platform_dir = join_paths(android_sdk, 'platforms', android_sdk_platform)
|
android_sdk_platform_dir = join_paths(android_sdk, 'platforms', android_sdk_platform)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2018 The Music Player Daemon Project
|
* Copyright 2003-2020 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -21,6 +21,7 @@ package org.musicpd;
|
|||||||
|
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
@@ -35,6 +36,9 @@ import android.os.RemoteException;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.RemoteViews;
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
public class Main extends Service implements Runnable {
|
public class Main extends Service implements Runnable {
|
||||||
private static final String TAG = "Main";
|
private static final String TAG = "Main";
|
||||||
private static final String REMOTE_ERROR = "MPD process was killed";
|
private static final String REMOTE_ERROR = "MPD process was killed";
|
||||||
@@ -156,11 +160,36 @@ public class Main extends Service implements Runnable {
|
|||||||
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError);
|
sendMessage(MSG_SEND_STATUS, mStatus, 0, mError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Notification.Builder createNotificationBuilderWithChannel() {
|
||||||
|
final NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
|
if (notificationManager == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
final String id = "org.musicpd";
|
||||||
|
final String name = "MPD service";
|
||||||
|
final int importance = 3; /* NotificationManager.IMPORTANCE_DEFAULT */
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<?> ncClass = Class.forName("android.app.NotificationChannel");
|
||||||
|
Constructor<?> ncCtor = ncClass.getConstructor(String.class, CharSequence.class, int.class);
|
||||||
|
Object nc = ncCtor.newInstance(id, name, importance);
|
||||||
|
|
||||||
|
Method nmCreateNotificationChannelMethod =
|
||||||
|
NotificationManager.class.getMethod("createNotificationChannel", ncClass);
|
||||||
|
nmCreateNotificationChannelMethod.invoke(notificationManager, nc);
|
||||||
|
|
||||||
|
Constructor nbCtor = Notification.Builder.class.getConstructor(Context.class, String.class);
|
||||||
|
return (Notification.Builder) nbCtor.newInstance(this, id);
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.e(TAG, "error creating the NotificationChannel", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void start() {
|
private void start() {
|
||||||
if (mThread != null)
|
if (mThread != null)
|
||||||
return;
|
return;
|
||||||
mThread = new Thread(this);
|
|
||||||
mThread.start();
|
|
||||||
|
|
||||||
final Intent mainIntent = new Intent(this, Settings.class);
|
final Intent mainIntent = new Intent(this, Settings.class);
|
||||||
mainIntent.setAction("android.intent.action.MAIN");
|
mainIntent.setAction("android.intent.action.MAIN");
|
||||||
@@ -168,13 +197,25 @@ public class Main extends Service implements Runnable {
|
|||||||
final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
final PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
mainIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
mainIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||||
|
|
||||||
Notification notification = new Notification.Builder(this)
|
Notification.Builder nBuilder;
|
||||||
.setContentTitle(getText(R.string.notification_title_mpd_running))
|
if (Build.VERSION.SDK_INT >= 26 /* Build.VERSION_CODES.O */)
|
||||||
|
{
|
||||||
|
nBuilder = createNotificationBuilderWithChannel();
|
||||||
|
if (nBuilder == null)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
nBuilder = new Notification.Builder(this);
|
||||||
|
|
||||||
|
Notification notification = nBuilder.setContentTitle(getText(R.string.notification_title_mpd_running))
|
||||||
.setContentText(getText(R.string.notification_text_mpd_running))
|
.setContentText(getText(R.string.notification_text_mpd_running))
|
||||||
.setSmallIcon(R.drawable.notification_icon)
|
.setSmallIcon(R.drawable.notification_icon)
|
||||||
.setContentIntent(contentIntent)
|
.setContentIntent(contentIntent)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
mThread = new Thread(this);
|
||||||
|
mThread.start();
|
||||||
|
|
||||||
startForeground(R.string.notification_title_mpd_running, notification);
|
startForeground(R.string.notification_title_mpd_running, notification);
|
||||||
startService(new Intent(this, Main.class));
|
startService(new Intent(this, Main.class));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2018 The Music Player Daemon Project
|
* Copyright 2003-2020 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -21,10 +21,12 @@ package org.musicpd;
|
|||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
@@ -103,12 +105,13 @@ public class Settings extends Activity {
|
|||||||
else
|
else
|
||||||
mRunButton.setChecked(false);
|
mRunButton.setChecked(false);
|
||||||
mFirstRun = true;
|
mFirstRun = true;
|
||||||
|
mTextStatus.setText("");
|
||||||
break;
|
break;
|
||||||
case MSG_STARTED:
|
case MSG_STARTED:
|
||||||
Log.d(TAG, "onStarted");
|
Log.d(TAG, "onStarted");
|
||||||
mRunButton.setChecked(true);
|
mRunButton.setChecked(true);
|
||||||
mFirstRun = true;
|
mFirstRun = true;
|
||||||
mTextStatus.setText("CAUTION: this version is EXPERIMENTAL!"); // XXX
|
mTextStatus.setText("MPD service started");
|
||||||
break;
|
break;
|
||||||
case MSG_LOG:
|
case MSG_LOG:
|
||||||
if (mLogListArray.size() > MAX_LOGS)
|
if (mLogListArray.size() > MAX_LOGS)
|
||||||
@@ -178,6 +181,14 @@ public class Settings extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
/* TODO: this sure is the wrong place to request
|
||||||
|
permissions - it will cause MPD to quit
|
||||||
|
immediately; we should request permissions when we
|
||||||
|
need them, but implementing that is complicated, so
|
||||||
|
for now, we do it here to give users a quick
|
||||||
|
solution for the problem */
|
||||||
|
requestAllPermissions();
|
||||||
|
|
||||||
setContentView(R.layout.settings);
|
setContentView(R.layout.settings);
|
||||||
mRunButton = (ToggleButton) findViewById(R.id.run);
|
mRunButton = (ToggleButton) findViewById(R.id.run);
|
||||||
mRunButton.setOnCheckedChangeListener(mOnRunChangeListener);
|
mRunButton.setOnCheckedChangeListener(mOnRunChangeListener);
|
||||||
@@ -203,6 +214,31 @@ public class Settings extends Activity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkRequestPermission(String permission) {
|
||||||
|
if (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.requestPermissions(new String[]{permission}, 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "requestPermissions(" + permission + ") failed",
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestAllPermissions() {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < 23)
|
||||||
|
/* we don't need to request permissions on
|
||||||
|
this old Android version */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* starting with Android 6.0, we need to explicitly
|
||||||
|
request all permissions before using them;
|
||||||
|
mentioning them in the manifest is not enough */
|
||||||
|
|
||||||
|
checkRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
private void connectClient() {
|
private void connectClient() {
|
||||||
mClient = new Main.Client(this, new Main.Client.Callback() {
|
mClient = new Main.Client(this, new Main.Client.Callback() {
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ master_doc = 'index'
|
|||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = 'Music Player Daemon'
|
project = 'Music Player Daemon'
|
||||||
copyright = '2003-2018 The Music Player Daemon Project'
|
copyright = '2003-2020 The Music Player Daemon Project'
|
||||||
author = 'Max Kellermann'
|
author = 'Max Kellermann'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
@@ -38,7 +38,7 @@ author = 'Max Kellermann'
|
|||||||
# built documents.
|
# built documents.
|
||||||
#
|
#
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.21.6'
|
version = '0.22.3'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = version
|
release = version
|
||||||
|
|
||||||
@@ -212,3 +212,7 @@ html_static_path = ['_static']
|
|||||||
# implements a search results scorer. If empty, the default will be used.
|
# implements a search results scorer. If empty, the default will be used.
|
||||||
#
|
#
|
||||||
# html_search_scorer = 'scorer.js'
|
# html_search_scorer = 'scorer.js'
|
||||||
|
man_pages = [
|
||||||
|
('mpd.1', 'mpd', 'MPD documentation', [author], 1),
|
||||||
|
('mpd.conf.5', 'mpd.conf', 'mpd.conf documentation', [author], 5)
|
||||||
|
]
|
||||||
|
|||||||
@@ -2,23 +2,21 @@ Developer's Manual
|
|||||||
##################
|
##################
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
************
|
||||||
|
|
||||||
This is a guide for those who wish to hack on the MPD source code. MPD is an open project, and we are always happy about contributions. So far, more than 150 people have contributed patches. This document is work in progress. Most of it may be incomplete yet. Please help!
|
This is a guide for those who wish to hack on the MPD source code. MPD is an open project, and we are always happy about contributions. So far, more than 150 people have contributed patches. This document is work in progress. Most of it may be incomplete yet. Please help!
|
||||||
|
|
||||||
Code Style
|
Code Style
|
||||||
==========
|
**********
|
||||||
|
|
||||||
* indent with tabs (width 8)
|
* indent with tabs (width 8)
|
||||||
* don't write CPP when you can write C++: use inline functions and constexpr instead of macros
|
* don't write CPP when you can write C++: use inline functions and constexpr instead of macros
|
||||||
* comment your code, document your APIs
|
* 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
|
* the code should be C++17 compliant, and must compile with :program:`GCC` 8 and :program:`clang` 5
|
||||||
* report error conditions with C++ exceptions, preferable derived from :envvar:`std::runtime_error`
|
|
||||||
* all code must be exception-safe
|
* all code must be exception-safe
|
||||||
* classes and functions names use CamelCase; variables are lower-case with words separated by underscore
|
* classes and functions names use CamelCase; variables are lower-case with words separated by underscore
|
||||||
|
|
||||||
Some example code:
|
Some example code:
|
||||||
~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@@ -32,8 +30,58 @@ Some example code:
|
|||||||
return xyz;
|
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
|
Hacking The Source
|
||||||
==================
|
******************
|
||||||
|
|
||||||
MPD sources are managed in a git repository on
|
MPD sources are managed in a git repository on
|
||||||
`Github <https://github.com/MusicPlayerDaemon/>`_.
|
`Github <https://github.com/MusicPlayerDaemon/>`_.
|
||||||
@@ -59,7 +107,7 @@ possible, to be sure that you don't break any disabled code.
|
|||||||
Don't mix several changes in one single patch. Create a separate patch for every change. Tools like :program:`stgit` help you with that. This way, we can review your patches more easily, and we can pick the patches we like most first.
|
Don't mix several changes in one single patch. Create a separate patch for every change. Tools like :program:`stgit` help you with that. This way, we can review your patches more easily, and we can pick the patches we like most first.
|
||||||
|
|
||||||
Basic stgit usage
|
Basic stgit usage
|
||||||
-----------------
|
=================
|
||||||
|
|
||||||
stgit allows you to create a set of patches and refine all of them: you can go back to any patch at any time, and re-edit it (both the code and the commit message). You can reorder patches and insert new patches at any position. It encourages creating separate patches for tiny changes.
|
stgit allows you to create a set of patches and refine all of them: you can go back to any patch at any time, and re-edit it (both the code and the commit message). You can reorder patches and insert new patches at any position. It encourages creating separate patches for tiny changes.
|
||||||
|
|
||||||
@@ -94,35 +142,7 @@ When the whole patch series is finished, convert stgit patches to git commits:
|
|||||||
stg commit
|
stg commit
|
||||||
|
|
||||||
Submitting Patches
|
Submitting Patches
|
||||||
==================
|
******************
|
||||||
|
|
||||||
Send your patches to the mailing list:
|
Submit pull requests on GitHub:
|
||||||
Email: `mpd-devel <mpd-devel@musicpd.org>`_
|
https://github.com/MusicPlayerDaemon/MPD/pulls
|
||||||
|
|
||||||
:program:`git pull` requests are preferred.
|
|
||||||
|
|
||||||
Development Tools
|
|
||||||
=================
|
|
||||||
|
|
||||||
Clang Static Analyzer
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
The `static analyzer <http://clang-analyzer.llvm.org/>`_ is a tool that helps find bugs. To run it on the MPD code base, install LLVM and clang. configure MPD to use clang:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
./configure --enable-debug CXX=clang++ CC=clang ...
|
|
||||||
|
|
||||||
It is recommended to use :code:`--enable-debug`, because the analyzer
|
|
||||||
takes advantage of :dfn:`assert()` calls, which are only enabled in
|
|
||||||
the debug build.
|
|
||||||
|
|
||||||
Now run the analyzer:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
scan-build --use-c++=clang++ --use-cc=clang make
|
|
||||||
|
|
||||||
The options :code:`--use-c++` and :code:`--use-cc` are necessary
|
|
||||||
because it invokes :command:`cc` for actually compiling the sources by
|
|
||||||
default. That breaks, because MPD requires a C99 compiler.
|
|
||||||
|
|||||||
@@ -1,165 +0,0 @@
|
|||||||
<?xml version='1.0' encoding="utf-8"?>
|
|
||||||
<!DOCTYPE itemizedlist PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
||||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
||||||
|
|
||||||
<itemizedlist>
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>artist</varname>: the artist name. Its meaning is not
|
|
||||||
well-defined; see <varname>composer</varname> and
|
|
||||||
<varname>performer</varname> for more specific tags.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>artistsort</varname>: same as
|
|
||||||
<varname>artist</varname>, but for sorting. This usually omits
|
|
||||||
prefixes such as "The".
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>album</varname>: the album name.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>albumsort</varname>: same as <varname>album</varname>,
|
|
||||||
but for sorting.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>albumartist</varname>: on multi-artist albums, this is
|
|
||||||
the artist name which shall be used for the whole album. The
|
|
||||||
exact meaning of this tag is not well-defined.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>albumartistsort</varname>: same as
|
|
||||||
<varname>albumartist</varname>, but for sorting.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>title</varname>: the song title.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>track</varname>: the decimal track number within the
|
|
||||||
album.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>name</varname>: a name for this song. This is not the
|
|
||||||
song title. The exact meaning of this tag is not well-defined.
|
|
||||||
It is often used by badly configured internet radio stations
|
|
||||||
with broken tags to squeeze both the artist name and the song
|
|
||||||
title in one tag.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>genre</varname>: the music genre.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>date</varname>: the song's release date. This is
|
|
||||||
usually a 4-digit year.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>composer</varname>: the artist who composed the song.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>performer</varname>: the artist who performed the song.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>comment</varname>: a human-readable comment about this
|
|
||||||
song. The exact meaning of this tag is not well-defined.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>disc</varname>: the decimal disc number in a multi-disc
|
|
||||||
album.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_artistid</varname>: the artist id in the
|
|
||||||
<ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_albumid</varname>: the album id in the
|
|
||||||
<ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_albumartistid</varname>: the album artist
|
|
||||||
id in the <ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_trackid</varname>: the track id in the
|
|
||||||
<ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_releasetrackid</varname>: the release track
|
|
||||||
id in the <ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
|
|
||||||
<listitem>
|
|
||||||
<para>
|
|
||||||
<varname>musicbrainz_workid</varname>: the work id in the
|
|
||||||
<ulink
|
|
||||||
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
|
|
||||||
database.
|
|
||||||
</para>
|
|
||||||
</listitem>
|
|
||||||
</itemizedlist>
|
|
||||||
@@ -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 = find_program('sphinx-build', required: get_option('documentation'))
|
||||||
sphinx_output = custom_target(
|
if not sphinx.found()
|
||||||
'HTML documentation',
|
subdir_done()
|
||||||
output: 'html',
|
endif
|
||||||
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(
|
if get_option('html_manual')
|
||||||
'upload',
|
sphinx_output = custom_target(
|
||||||
input: sphinx_output,
|
'HTML documentation',
|
||||||
output: 'upload',
|
output: 'html',
|
||||||
build_always_stale: true,
|
input: [
|
||||||
command: [
|
'index.rst', 'user.rst', 'developer.rst',
|
||||||
'rsync', '-vpruz', '--delete', meson.current_build_dir() + '/',
|
'plugins.rst',
|
||||||
'www.musicpd.org:/var/www/mpd/doc/',
|
'protocol.rst',
|
||||||
'--chmod=Dug+rwx,Do+rx,Fug+rw,Fo+r',
|
'conf.py',
|
||||||
'--include=html', '--include=html/**',
|
],
|
||||||
'--exclude=*',
|
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/
|
||||||
226
doc/mpd.conf.5
226
doc/mpd.conf.5
@@ -1,226 +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.
|
|
||||||
.TP
|
|
||||||
.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.
|
|
||||||
.SH OPTIONAL ALSA OUTPUT PARAMETERS
|
|
||||||
.TP
|
|
||||||
.B device <dev>
|
|
||||||
This specifies the device to use for audio output. The default is "default".
|
|
||||||
.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.
|
|
||||||
.TP
|
|
||||||
.B mixer_device <mixer dev>
|
|
||||||
This specifies which mixer to use. The default is "default". To use
|
|
||||||
the second sound card in a system, use "hw:1".
|
|
||||||
.TP
|
|
||||||
.B mixer_control <mixer ctrl>
|
|
||||||
This specifies which mixer control to use (sometimes referred to as
|
|
||||||
the "device"). The default is "PCM". Use "amixer scontrols" to see
|
|
||||||
the list of possible controls.
|
|
||||||
.TP
|
|
||||||
.B mixer_index <mixer index>
|
|
||||||
A number identifying the index of the named mixer control. This is
|
|
||||||
probably only useful if your alsa device has more than one
|
|
||||||
identically\-named mixer control. The default is "0". Use "amixer
|
|
||||||
scontrols" to see the list of controls with their indexes.
|
|
||||||
.TP
|
|
||||||
.B auto_resample <yes or no>
|
|
||||||
Setting this to "no" disables ALSA's software resampling, if the
|
|
||||||
hardware does not support a specific sample rate. This lets MPD do
|
|
||||||
the resampling. "yes" is the default and allows ALSA to resample.
|
|
||||||
.TP
|
|
||||||
.B auto_channels <yes or no>
|
|
||||||
Setting this to "no" disables ALSA's channel conversion, if the
|
|
||||||
hardware does not support a specific number of channels. Default: "yes".
|
|
||||||
.TP
|
|
||||||
.B auto_format <yes or no>
|
|
||||||
Setting this to "no" disables ALSA's sample format conversion, if the
|
|
||||||
hardware does not support a specific sample format. Default: "yes".
|
|
||||||
.TP
|
|
||||||
.B buffer_time <time in microseconds>
|
|
||||||
This sets the length of the hardware sample buffer in microseconds. Increasing
|
|
||||||
it may help to reduce or eliminate skipping on certain setups. Most users do
|
|
||||||
not need to change this. The default is 500000 microseconds (0.5 seconds).
|
|
||||||
.TP
|
|
||||||
.B period_time <time in microseconds>
|
|
||||||
This sets the time between hardware sample transfers in microseconds.
|
|
||||||
Increasing this can reduce CPU usage while lowering it can reduce underrun
|
|
||||||
errors on bandwidth-limited devices. Some users have reported good results
|
|
||||||
with this set to 50000, but not all devices support values this high. Most
|
|
||||||
users do not need to change this. The default is 256000000 / sample_rate(kHz),
|
|
||||||
or 5804 microseconds for CD-quality audio.
|
|
||||||
.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"
|
#port "6600"
|
||||||
#
|
#
|
||||||
# This setting controls the type of information which is logged. Available
|
# Suppress all messages below the given threshold. Use "verbose" for
|
||||||
# setting arguments are "default", "secure" or "verbose". The "verbose" setting
|
# troubleshooting.
|
||||||
# argument is recommended for troubleshooting, though can quickly stretch
|
|
||||||
# available resources on limited hardware storage.
|
|
||||||
#
|
#
|
||||||
#log_level "default"
|
#log_level "notice"
|
||||||
#
|
#
|
||||||
# Setting "restore_paused" to "yes" puts MPD into pause mode instead
|
# Setting "restore_paused" to "yes" puts MPD into pause mode instead
|
||||||
# of starting playback after startup.
|
# of starting playback after startup.
|
||||||
@@ -280,6 +278,7 @@ input {
|
|||||||
# name "My Pulse Output"
|
# name "My Pulse Output"
|
||||||
## server "remote_server" # optional
|
## server "remote_server" # optional
|
||||||
## sink "remote_server_sink" # optional
|
## sink "remote_server_sink" # optional
|
||||||
|
## media_role "media_role" #optional
|
||||||
#}
|
#}
|
||||||
#
|
#
|
||||||
# An example of a winmm output (Windows multimedia API).
|
# An example of a winmm output (Windows multimedia API).
|
||||||
@@ -293,6 +292,20 @@ input {
|
|||||||
## mixer_type "hardware" # optional
|
## 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.
|
# An example of an openal output.
|
||||||
#
|
#
|
||||||
#audio_output {
|
#audio_output {
|
||||||
|
|||||||
481
doc/plugins.rst
481
doc/plugins.rst
@@ -4,10 +4,10 @@ Plugin reference
|
|||||||
.. _database_plugins:
|
.. _database_plugins:
|
||||||
|
|
||||||
Database plugins
|
Database plugins
|
||||||
----------------
|
================
|
||||||
|
|
||||||
simple
|
simple
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
The default plugin. Stores a copy of the database in memory. A file is used for permanent storage.
|
The default plugin. Stores a copy of the database in memory. A file is used for permanent storage.
|
||||||
|
|
||||||
@@ -25,9 +25,9 @@ The default plugin. Stores a copy of the database in memory. A file is used for
|
|||||||
- Compress the database file using gzip? Enabled by default (if built with zlib).
|
- Compress the database file using gzip? Enabled by default (if built with zlib).
|
||||||
|
|
||||||
proxy
|
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::
|
.. list-table::
|
||||||
:widths: 20 80
|
:widths: 20 80
|
||||||
@@ -42,46 +42,51 @@ Provides access to the database of another :program:`MPD` instance using libmpdc
|
|||||||
* - **password**
|
* - **password**
|
||||||
- The password used to log in to the "master" :program:`MPD` instance.
|
- The password used to log in to the "master" :program:`MPD` instance.
|
||||||
* - **keepalive yes|no**
|
* - **keepalive yes|no**
|
||||||
- Send TCP keepalive packets to the "master" :program:`MPD` instance? This option can help avoid certain firewalls dropping inactive connections, at the expensive of a very small amount of additional network traffic. Disabled by default.
|
- Send TCP keepalive packets to the "master" :program:`MPD` instance? This option can help avoid certain firewalls dropping inactive connections, at the expense of a very small amount of additional network traffic. Disabled by default.
|
||||||
|
|
||||||
upnp
|
upnp
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Provides access to UPnP media servers.
|
Provides access to UPnP media servers.
|
||||||
|
|
||||||
Storage plugins
|
Storage plugins
|
||||||
---------------
|
===============
|
||||||
|
|
||||||
local
|
local
|
||||||
~~~~~
|
-----
|
||||||
|
|
||||||
The default plugin which gives :program:`MPD` access to local files. It is used when music_directory refers to a local directory.
|
The default plugin which gives :program:`MPD` access to local files. It is used when music_directory refers to a local directory.
|
||||||
|
|
||||||
curl
|
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
|
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`.
|
||||||
|
|
||||||
|
Note that :file:`libsmbclient` has a serious bug which causes MPD to
|
||||||
|
crash, and therefore this plugin is disabled by default and should not
|
||||||
|
be used until the bug is fixed:
|
||||||
|
https://bugzilla.samba.org/show_bug.cgi?id=11413
|
||||||
|
|
||||||
nfs
|
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`:
|
See :ref:`input_nfs` for more information.
|
||||||
|
|
||||||
.. 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.
|
|
||||||
|
|
||||||
udisks
|
udisks
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Mount file systems (e.g. USB sticks or other removable media) using
|
Mount file systems (e.g. USB sticks or other removable media) using
|
||||||
the udisks2 daemon via D-Bus. To obtain a valid udisks2 URI, consult
|
the udisks2 daemon via D-Bus. To obtain a valid udisks2 URI, consult
|
||||||
@@ -106,42 +111,67 @@ MPD user.
|
|||||||
.. _neighbor_plugin:
|
.. _neighbor_plugin:
|
||||||
|
|
||||||
Neighbor plugins
|
Neighbor plugins
|
||||||
----------------
|
================
|
||||||
|
|
||||||
smbclient
|
smbclient
|
||||||
~~~~~~~~~
|
---------
|
||||||
|
|
||||||
Provides a list of SMB/CIFS servers on the local network.
|
Provides a list of SMB/CIFS servers on the local network.
|
||||||
|
|
||||||
udisks
|
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
|
upnp
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Provides a list of UPnP servers on the local network.
|
Provides a list of UPnP servers on the local network.
|
||||||
|
|
||||||
.. _input_plugins:
|
.. _input_plugins:
|
||||||
|
|
||||||
Input plugins
|
Input plugins
|
||||||
-------------
|
=============
|
||||||
|
|
||||||
alsa
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
mpc add alsa:// plays audio from device hw:0,0
|
mpc add alsa:// plays audio from device default
|
||||||
|
|
||||||
.. code-block:: none
|
.. 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
|
cdio_paranoia
|
||||||
~~~~~~~~~~~~~
|
-------------
|
||||||
|
|
||||||
Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]". The simplest form cdda:// plays the whole disc in the default drive.
|
Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]". The simplest form cdda:// plays the whole disc in the default drive.
|
||||||
|
|
||||||
@@ -157,11 +187,14 @@ Plays audio CDs using libcdio. The URI has the form: "cdda://[DEVICE][/TRACK]".
|
|||||||
- Request CDParanoia cap the extraction speed to Nx normal CD audio rotation speed, keeping the drive quiet.
|
- Request CDParanoia cap the extraction speed to Nx normal CD audio rotation speed, keeping the drive quiet.
|
||||||
|
|
||||||
curl
|
curl
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Opens remote files or streams over HTTP using libcurl.
|
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::
|
.. list-table::
|
||||||
:widths: 20 80
|
:widths: 20 80
|
||||||
@@ -179,44 +212,67 @@ Note that unless overridden by the below settings (e.g. by setting them to a bla
|
|||||||
- Verify the certificate's name against host? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html>`_.
|
- Verify the certificate's name against host? `More information <http://curl.haxx.se/libcurl/c/CURLOPT_SSL_VERIFYHOST.html>`_.
|
||||||
|
|
||||||
ffmpeg
|
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
|
file
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Opens local files
|
Opens local files
|
||||||
|
|
||||||
mms
|
mms
|
||||||
~~~
|
---
|
||||||
|
|
||||||
Plays streams with the MMS protocol using `libmms <https://launchpad.net/libmms>`_.
|
Plays streams with the MMS protocol using `libmms <https://launchpad.net/libmms>`_.
|
||||||
|
|
||||||
nfs
|
.. _input_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:
|
nfs
|
||||||
|
---
|
||||||
|
|
||||||
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
mpc add nfs://servername/path/filename.ogg
|
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
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
mpc add smb://servername/sharename/filename.ogg
|
mpc add smb://servername/sharename/filename.ogg
|
||||||
|
mpc add smb://username:password@servername/sharename/filename.ogg
|
||||||
|
|
||||||
qobuz
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
@@ -240,9 +296,16 @@ Play songs from the commercial streaming service Qobuz. It plays URLs in the for
|
|||||||
- The `Qobuz format identifier <https://github.com/Qobuz/api-documentation/blob/master/endpoints/track/getFileUrl.md#parameters>`_, i.e. a number which chooses the format and quality to be requested from Qobuz. The default is "5" (320 kbit/s MP3).
|
- The `Qobuz format identifier <https://github.com/Qobuz/api-documentation/blob/master/endpoints/track/getFileUrl.md#parameters>`_, i.e. a number which chooses the format and quality to be requested from Qobuz. The default is "5" (320 kbit/s MP3).
|
||||||
|
|
||||||
tidal
|
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::
|
||||||
|
|
||||||
|
This plugin is currently defunct because Tidal has changed the
|
||||||
|
protocol and decided not to share documentation.
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
@@ -266,10 +329,10 @@ Play songs from the commercial streaming service `Tidal <http://tidal.com/>`_. I
|
|||||||
.. _decoder_plugins:
|
.. _decoder_plugins:
|
||||||
|
|
||||||
Decoder plugins
|
Decoder plugins
|
||||||
---------------
|
===============
|
||||||
|
|
||||||
adplug
|
adplug
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Decodes AdLib files using libadplug.
|
Decodes AdLib files using libadplug.
|
||||||
|
|
||||||
@@ -283,17 +346,19 @@ Decodes AdLib files using libadplug.
|
|||||||
- The sample rate that shall be synthesized by the plugin. Defaults to 48000.
|
- The sample rate that shall be synthesized by the plugin. Defaults to 48000.
|
||||||
|
|
||||||
audiofile
|
audiofile
|
||||||
~~~~~~~~~
|
---------
|
||||||
|
|
||||||
Decodes WAV and AIFF files using libaudiofile.
|
Decodes WAV and AIFF files using libaudiofile.
|
||||||
|
|
||||||
faad
|
faad
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Decodes AAC files using libfaad.
|
Decodes AAC files using libfaad.
|
||||||
|
|
||||||
|
.. _decoder_ffmpeg:
|
||||||
|
|
||||||
ffmpeg
|
ffmpeg
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Decodes various codecs using FFmpeg.
|
Decodes various codecs using FFmpeg.
|
||||||
|
|
||||||
@@ -309,12 +374,12 @@ Decodes various codecs using FFmpeg.
|
|||||||
- Sets the FFmpeg muxer option probesize, which specifies probing size in bytes, i.e. the size of the data to analyze to get stream information. The `FFmpeg formats documentation <https://ffmpeg.org/ffmpeg-formats.html>`_ has more information.
|
- Sets the FFmpeg muxer option probesize, which specifies probing size in bytes, i.e. the size of the data to analyze to get stream information. The `FFmpeg formats documentation <https://ffmpeg.org/ffmpeg-formats.html>`_ has more information.
|
||||||
|
|
||||||
flac
|
flac
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Decodes FLAC files using libFLAC.
|
Decodes FLAC files using libFLAC.
|
||||||
|
|
||||||
dsdiff
|
dsdiff
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Decodes DFF files containing DSDIFF data (e.g. SACD rips).
|
Decodes DFF files containing DSDIFF data (e.g. SACD rips).
|
||||||
|
|
||||||
@@ -328,12 +393,12 @@ Decodes DFF files containing DSDIFF data (e.g. SACD rips).
|
|||||||
- Decode the least significant bit first. Default is no.
|
- Decode the least significant bit first. Default is no.
|
||||||
|
|
||||||
dsf
|
dsf
|
||||||
~~~
|
---
|
||||||
|
|
||||||
Decodes DSF files containing DSDIFF data (e.g. SACD rips).
|
Decodes DSF files containing DSDIFF data (e.g. SACD rips).
|
||||||
|
|
||||||
fluidsynth
|
fluidsynth
|
||||||
~~~~~~~~~~
|
----------
|
||||||
|
|
||||||
MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_.
|
MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_.
|
||||||
|
|
||||||
@@ -349,7 +414,7 @@ MIDI decoder based on `FluidSynth <http://www.fluidsynth.org/>`_.
|
|||||||
- The absolute path of the soundfont file. Defaults to :file:`/usr/share/sounds/sf2/FluidR3_GM.sf2`.
|
- The absolute path of the soundfont file. Defaults to :file:`/usr/share/sounds/sf2/FluidR3_GM.sf2`.
|
||||||
|
|
||||||
gme
|
gme
|
||||||
~~~
|
---
|
||||||
|
|
||||||
Video game music file emulator based on `game-music-emu <https://bitbucket.org/mpyne/game-music-emu/wiki/Home>`_.
|
Video game music file emulator based on `game-music-emu <https://bitbucket.org/mpyne/game-music-emu/wiki/Home>`_.
|
||||||
|
|
||||||
@@ -361,37 +426,29 @@ Video game music file emulator based on `game-music-emu <https://bitbucket.org/m
|
|||||||
- Description
|
- Description
|
||||||
* - **accuracy yes|no**
|
* - **accuracy yes|no**
|
||||||
- Enable more accurate sound emulation.
|
- 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
|
||||||
~~~~~~~~~~
|
----------
|
||||||
|
|
||||||
`Hybrid-DSD
|
`Hybrid-DSD
|
||||||
<http://dsdmaster.blogspot.de/p/bitperfect-introduces-hybrid-dsd-file.html>`_
|
<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
|
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
|
enable it. Without this plugin, the ALAC parts gets handled by the
|
||||||
`FFmpeg decoder plugin
|
:ref:`FFmpeg decoder plugin <decoder_ffmpeg>`. This
|
||||||
<https://www.musicpd.org/doc/user/decoder_plugins.html#ffmpeg_decoder>`_. This
|
|
||||||
plugin should be enabled only if you have a bit-perfect playback path
|
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
|
to a DSD-capable DAC; for everybody else, playing back the ALAC copy
|
||||||
of the file is better.
|
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
|
mad
|
||||||
~~~
|
---
|
||||||
|
|
||||||
Decodes MP3 files using `libmad <http://www.underbit.com/products/mad/>`_.
|
Decodes MP3 files using `libmad <http://www.underbit.com/products/mad/>`_.
|
||||||
|
|
||||||
mikmod
|
mikmod
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Module player based on `MikMod <http://mikmod.sourceforge.net/>`_.
|
Module player based on `MikMod <http://mikmod.sourceforge.net/>`_.
|
||||||
|
|
||||||
@@ -407,7 +464,7 @@ Module player based on `MikMod <http://mikmod.sourceforge.net/>`_.
|
|||||||
- Sets the sample rate generated by libmikmod. Default is 44100.
|
- Sets the sample rate generated by libmikmod. Default is 44100.
|
||||||
|
|
||||||
modplug
|
modplug
|
||||||
~~~~~~~
|
-------
|
||||||
|
|
||||||
Module player based on MODPlug.
|
Module player based on MODPlug.
|
||||||
|
|
||||||
@@ -421,27 +478,29 @@ Module player based on MODPlug.
|
|||||||
- Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever.
|
- Number of times to loop the module if it uses backward loops. Default is 0 which prevents looping. -1 loops forever.
|
||||||
|
|
||||||
mpcdec
|
mpcdec
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Decodes Musepack files using `libmpcdec <http://www.musepack.net/>`_.
|
Decodes Musepack files using `libmpcdec <http://www.musepack.net/>`_.
|
||||||
|
|
||||||
mpg123
|
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
|
opus
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Decodes Opus files using `libopus <http://www.opus-codec.org/>`_.
|
Decodes Opus files using `libopus <http://www.opus-codec.org/>`_.
|
||||||
|
|
||||||
pcm
|
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
|
sidplay
|
||||||
~~~~~~~
|
-------
|
||||||
|
|
||||||
C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay-residfp/>`_ or `libsidplay2 <https://sourceforge.net/projects/sidplay2/>`_.
|
C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay-residfp/>`_ or `libsidplay2 <https://sourceforge.net/projects/sidplay2/>`_.
|
||||||
|
|
||||||
@@ -452,9 +511,11 @@ C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay
|
|||||||
* - Setting
|
* - Setting
|
||||||
- Description
|
- Description
|
||||||
* - **songlength_database PATH**
|
* - **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**
|
* - **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.
|
- 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**
|
* - **filter yes|no**
|
||||||
- Turns the SID filter emulation on or off.
|
- Turns the SID filter emulation on or off.
|
||||||
* - **kernal**
|
* - **kernal**
|
||||||
@@ -463,23 +524,23 @@ C64 SID decoder based on `libsidplayfp <https://sourceforge.net/projects/sidplay
|
|||||||
- Only libsidplayfp. Absolute path to basic rom image file.
|
- Only libsidplayfp. Absolute path to basic rom image file.
|
||||||
|
|
||||||
sndfile
|
sndfile
|
||||||
~~~~~~~
|
-------
|
||||||
|
|
||||||
Decodes WAV and AIFF files using `libsndfile <http://www.mega-nerd.com/libsndfile/>`_.
|
Decodes WAV and AIFF files using `libsndfile <http://www.mega-nerd.com/libsndfile/>`_.
|
||||||
|
|
||||||
|
|
||||||
vorbis
|
vorbis
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Decodes Ogg-Vorbis files using `libvorbis <http://www.xiph.org/ogg/vorbis/>`_.
|
Decodes Ogg-Vorbis files using `libvorbis <http://www.xiph.org/ogg/vorbis/>`_.
|
||||||
|
|
||||||
wavpack
|
wavpack
|
||||||
~~~~~~~
|
-------
|
||||||
|
|
||||||
Decodes WavPack files using `libwavpack <http://www.wavpack.com/>`_.
|
Decodes WavPack files using `libwavpack <http://www.wavpack.com/>`_.
|
||||||
|
|
||||||
wildmidi
|
wildmidi
|
||||||
~~~~~~~~
|
--------
|
||||||
|
|
||||||
MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>`_.
|
MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>`_.
|
||||||
|
|
||||||
@@ -495,10 +556,11 @@ MIDI decoder based on `libwildmidi <http://www.mindwerks.net/projects/wildmidi/>
|
|||||||
.. _encoder_plugins:
|
.. _encoder_plugins:
|
||||||
|
|
||||||
Encoder plugins
|
Encoder plugins
|
||||||
---------------
|
===============
|
||||||
|
|
||||||
flac
|
flac
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
|
Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -511,7 +573,7 @@ Encodes into `FLAC <https://xiph.org/flac/>`_ (lossless).
|
|||||||
- Sets the libFLAC compression level. The levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
|
- Sets the libFLAC compression level. The levels range from 0 (fastest, least compression) to 8 (slowest, most compression).
|
||||||
|
|
||||||
lame
|
lame
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library.
|
Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library.
|
||||||
|
|
||||||
@@ -527,12 +589,12 @@ Encodes into MP3 using the `LAME <http://lame.sourceforge.net/>`_ library.
|
|||||||
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
||||||
|
|
||||||
null
|
null
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Does not encode anything, passes the input PCM data as-is.
|
Does not encode anything, passes the input PCM data as-is.
|
||||||
|
|
||||||
shine
|
shine
|
||||||
~~~~~
|
-----
|
||||||
|
|
||||||
Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library.
|
Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library.
|
||||||
|
|
||||||
@@ -546,7 +608,7 @@ Encodes into MP3 using the `Shine <https://github.com/savonet/shine>`_ library.
|
|||||||
- Sets the bit rate in kilobit per second.
|
- Sets the bit rate in kilobit per second.
|
||||||
|
|
||||||
twolame
|
twolame
|
||||||
~~~~~~~
|
-------
|
||||||
|
|
||||||
Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library.
|
Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library.
|
||||||
|
|
||||||
@@ -562,7 +624,7 @@ Encodes into MP2 using the `TwoLAME <http://www.twolame.org/>`_ library.
|
|||||||
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
||||||
|
|
||||||
opus
|
opus
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
|
Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
|
||||||
|
|
||||||
@@ -584,7 +646,7 @@ Encodes into `Ogg Opus <http://www.opus-codec.org/>`_.
|
|||||||
.. _vorbis_plugin:
|
.. _vorbis_plugin:
|
||||||
|
|
||||||
vorbis
|
vorbis
|
||||||
~~~~~~
|
------
|
||||||
|
|
||||||
Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_.
|
Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_.
|
||||||
|
|
||||||
@@ -600,13 +662,13 @@ Encodes into `Ogg Vorbis <http://www.vorbis.com/>`_.
|
|||||||
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
- Sets the bit rate in kilobit per second. Cannot be used with quality.
|
||||||
|
|
||||||
wave
|
wave
|
||||||
~~~~
|
----
|
||||||
Encodes into WAV (lossless).
|
Encodes into WAV (lossless).
|
||||||
|
|
||||||
.. _resampler_plugins:
|
.. _resampler_plugins:
|
||||||
|
|
||||||
Resampler plugins
|
Resampler plugins
|
||||||
-----------------
|
=================
|
||||||
|
|
||||||
The resampler can be configured in a block named resampler, for example:
|
The resampler can be configured in a block named resampler, for example:
|
||||||
|
|
||||||
@@ -629,12 +691,12 @@ The following table lists the resampler options valid for all plugins:
|
|||||||
- The name of the plugin.
|
- The name of the plugin.
|
||||||
|
|
||||||
internal
|
internal
|
||||||
~~~~~~~~
|
--------
|
||||||
|
|
||||||
A resampler built into :program:`MPD`. Its quality is very poor, but its CPU usage is low. This is the fallback if :program:`MPD` was compiled without an external resampler.
|
A resampler built into :program:`MPD`. Its quality is very poor, but its CPU usage is low. This is the fallback if :program:`MPD` was compiled without an external resampler.
|
||||||
|
|
||||||
libsamplerate
|
libsamplerate
|
||||||
~~~~~~~~~~~~~
|
-------------
|
||||||
|
|
||||||
A resampler using `libsamplerate <http://www.mega-nerd.com/SRC/>`_ a.k.a. Secret Rabbit Code (SRC).
|
A resampler using `libsamplerate <http://www.mega-nerd.com/SRC/>`_ a.k.a. Secret Rabbit Code (SRC).
|
||||||
|
|
||||||
@@ -667,7 +729,7 @@ The following converter types are provided by libsamplerate:
|
|||||||
- Linear interpolator, very fast, poor quality.
|
- Linear interpolator, very fast, poor quality.
|
||||||
|
|
||||||
soxr
|
soxr
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
A resampler using `libsoxr <http://sourceforge.net/projects/soxr/>`_, the SoX Resampler library
|
A resampler using `libsoxr <http://sourceforge.net/projects/soxr/>`_, the SoX Resampler library
|
||||||
|
|
||||||
@@ -689,14 +751,35 @@ Valid quality values for libsoxr:
|
|||||||
* "medium"
|
* "medium"
|
||||||
* "low"
|
* "low"
|
||||||
* "quick"
|
* "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:
|
||||||
|
|
||||||
Output plugins
|
Output plugins
|
||||||
--------------
|
==============
|
||||||
|
|
||||||
.. _alsa_plugin:
|
.. _alsa_plugin:
|
||||||
|
|
||||||
alsa
|
alsa
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ plugin uses libasound. It is recommended if you are using Linux.
|
The `Advanced Linux Sound Architecture (ALSA) <http://www.alsa-project.org/>`_ plugin uses libasound. It is recommended if you are using Linux.
|
||||||
|
|
||||||
@@ -755,7 +838,7 @@ The following attributes can be configured at runtime using the outputset comman
|
|||||||
|
|
||||||
|
|
||||||
ao
|
ao
|
||||||
~~
|
--
|
||||||
The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use only if there is no native plugin for your operating system.
|
The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use only if there is no native plugin for your operating system.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -772,7 +855,8 @@ The ao plugin uses the portable `libao <https://www.xiph.org/ao/>`_ library. Use
|
|||||||
- This specifies how many bytes to write to the audio device at once. This parameter is to work around a bug in older versions of libao on sound cards with very small buffers. The default is 1024.
|
- This specifies how many bytes to write to the audio device at once. This parameter is to work around a bug in older versions of libao on sound cards with very small buffers. The default is 1024.
|
||||||
|
|
||||||
sndio
|
sndio
|
||||||
~~~~~
|
-----
|
||||||
|
|
||||||
The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should normally be used on OpenBSD.
|
The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should normally be used on OpenBSD.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -787,7 +871,7 @@ The sndio plugin uses the `sndio <http://www.sndio.org/>`_ library. It should no
|
|||||||
- Set the application buffer time in milliseconds.
|
- Set the application buffer time in milliseconds.
|
||||||
|
|
||||||
fifo
|
fifo
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The data can be read by another program.
|
The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The data can be read by another program.
|
||||||
|
|
||||||
@@ -800,8 +884,18 @@ The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The da
|
|||||||
* - **path P**
|
* - **path P**
|
||||||
- This specifies the path of the FIFO to write to. Must be an absolute path. If the path does not exist, it will be created when MPD is started, and removed when MPD is stopped. The FIFO will be created with the same user and group as MPD is running as. Default permissions can be modified by using the builtin shell command umask. If a FIFO already exists at the specified path it will be reused, and will not be removed when MPD is stopped. You can use the "mkfifo" command to create this, and then you may modify the permissions to your liking.
|
- This specifies the path of the FIFO to write to. Must be an absolute path. If the path does not exist, it will be created when MPD is started, and removed when MPD is stopped. The FIFO will be created with the same user and group as MPD is running as. Default permissions can be modified by using the builtin shell command umask. If a FIFO already exists at the specified path it will be reused, and will not be removed when MPD is stopped. You can use the "mkfifo" command to create this, and then you may modify the permissions to your liking.
|
||||||
|
|
||||||
|
haiku
|
||||||
|
-----
|
||||||
|
|
||||||
|
Use the SoundPlayer API on the Haiku operating system.
|
||||||
|
|
||||||
|
This plugin is unmaintained and contains known bugs. It will be
|
||||||
|
removed soon, unless there is a new maintainer.
|
||||||
|
|
||||||
|
|
||||||
jack
|
jack
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
The jack plugin connects to a `JACK server <http://jackaudio.org/>`_.
|
The jack plugin connects to a `JACK server <http://jackaudio.org/>`_.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -820,11 +914,16 @@ 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.
|
- 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**
|
* - **destination_ports A,B**
|
||||||
- The names of the JACK destination ports to connect to.
|
- 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**
|
* - **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.
|
- Sets the size of the ring buffer for each channel. Do not configure this value unless you know what you're doing.
|
||||||
|
|
||||||
httpd
|
httpd
|
||||||
~~~~~
|
-----
|
||||||
|
|
||||||
The httpd plugin creates a HTTP server, similar to `ShoutCast <http://www.shoutcast.com/>`_ / `IceCast <http://icecast.org/>`_. HTTP streaming clients like mplayer, VLC, and mpv can connect to it.
|
The httpd plugin creates a HTTP server, similar to `ShoutCast <http://www.shoutcast.com/>`_ / `IceCast <http://icecast.org/>`_. HTTP streaming clients like mplayer, VLC, and mpv can connect to it.
|
||||||
|
|
||||||
It is highly recommended to configure a fixed format, because a stream cannot switch its audio format on-the-fly when the song changes.
|
It is highly recommended to configure a fixed format, because a stream cannot switch its audio format on-the-fly when the song changes.
|
||||||
@@ -838,14 +937,15 @@ It is highly recommended to configure a fixed format, because a stream cannot sw
|
|||||||
* - **port P**
|
* - **port P**
|
||||||
- Binds the HTTP server to the specified port.
|
- Binds the HTTP server to the specified port.
|
||||||
* - **bind_to_address ADDR**
|
* - **bind_to_address ADDR**
|
||||||
- Binds the HTTP server to the specified address (IPv4, IPv6 or UNIX socket). Multiple addresses in parallel are not supported.
|
- Binds the HTTP server to the specified address (IPv4, IPv6 or local socket). Multiple addresses in parallel are not supported.
|
||||||
* - **encoder NAME**
|
* - **encoder NAME**
|
||||||
- Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`.
|
- Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`.
|
||||||
* - **max_clients MC**
|
* - **max_clients MC**
|
||||||
- Sets a limit, number of concurrent clients. When set to 0 no limit will apply.
|
- Sets a limit, number of concurrent clients. When set to 0 no limit will apply.
|
||||||
|
|
||||||
null
|
null
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
The null plugin does nothing. It discards everything sent to it.
|
The null plugin does nothing. It discards everything sent to it.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -860,7 +960,8 @@ The null plugin does nothing. It discards everything sent to it.
|
|||||||
.. _oss_plugin:
|
.. _oss_plugin:
|
||||||
|
|
||||||
oss
|
oss
|
||||||
~~~
|
---
|
||||||
|
|
||||||
The "Open Sound System" plugin is supported on most Unix platforms.
|
The "Open Sound System" plugin is supported on most Unix platforms.
|
||||||
|
|
||||||
On Linux, OSS has been superseded by ALSA. Use the ALSA output plugin :ref:`alsa_plugin` instead of this one on Linux.
|
On Linux, OSS has been superseded by ALSA. Use the ALSA output plugin :ref:`alsa_plugin` instead of this one on Linux.
|
||||||
@@ -888,7 +989,7 @@ The according hardware mixer plugin understands the following settings:
|
|||||||
- Choose a mixer control, defaulting to PCM.
|
- Choose a mixer control, defaulting to PCM.
|
||||||
|
|
||||||
openal
|
openal
|
||||||
~~~~~~
|
------
|
||||||
The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_. It is supported on many platforms. Use only if there is no native plugin for your operating system.
|
The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_. It is supported on many platforms. Use only if there is no native plugin for your operating system.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -901,7 +1002,7 @@ The "OpenAL" plugin uses `libopenal <http://kcat.strangesoft.net/openal.html>`_.
|
|||||||
- Sets the device which should be used. This can be any valid OpenAL device name. If not specified, then libopenal will choose a default device.
|
- Sets the device which should be used. This can be any valid OpenAL device name. If not specified, then libopenal will choose a default device.
|
||||||
|
|
||||||
osx
|
osx
|
||||||
~~~
|
---
|
||||||
The "Mac OS X" plugin uses Apple's CoreAudio API.
|
The "Mac OS X" plugin uses Apple's CoreAudio API.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -922,7 +1023,7 @@ The "Mac OS X" plugin uses Apple's CoreAudio API.
|
|||||||
The channel map may not refer to outputs that do not exist according to the format. If the format is "*:*:1" (mono) and you have a four-channel sound card then "-1,-1,0,0" (dual mono output on the second pair of sound card outputs) is a valid channel map but "-1,-1,0,1" is not because the second channel ('1') does not exist when the output is mono.
|
The channel map may not refer to outputs that do not exist according to the format. If the format is "*:*:1" (mono) and you have a four-channel sound card then "-1,-1,0,0" (dual mono output on the second pair of sound card outputs) is a valid channel map but "-1,-1,0,1" is not because the second channel ('1') does not exist when the output is mono.
|
||||||
|
|
||||||
pipe
|
pipe
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
The pipe plugin starts a program and writes raw PCM data into its standard input.
|
The pipe plugin starts a program and writes raw PCM data into its standard input.
|
||||||
|
|
||||||
@@ -938,7 +1039,7 @@ The pipe plugin starts a program and writes raw PCM data into its standard input
|
|||||||
.. _pulse_plugin:
|
.. _pulse_plugin:
|
||||||
|
|
||||||
pulse
|
pulse
|
||||||
~~~~~
|
-----
|
||||||
The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Software/PulseAudio/>`_ server. Requires libpulse.
|
The pulse plugin connects to a `PulseAudio <http://www.freedesktop.org/wiki/Software/PulseAudio/>`_ server. Requires libpulse.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -951,11 +1052,13 @@ 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.
|
- Sets the host name of the PulseAudio server. By default, :program:`MPD` connects to the local PulseAudio server.
|
||||||
* - **sink NAME**
|
* - **sink NAME**
|
||||||
- Specifies the name of the PulseAudio sink :program:`MPD` should play on.
|
- 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**
|
* - **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.
|
- 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.
|
||||||
|
|
||||||
recorder
|
recorder
|
||||||
~~~~~~~~
|
--------
|
||||||
The recorder plugin writes the audio played by :program:`MPD` to a file. This may be useful for recording radio streams.
|
The recorder plugin writes the audio played by :program:`MPD` to a file. This may be useful for recording radio streams.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -967,13 +1070,13 @@ The recorder plugin writes the audio played by :program:`MPD` to a file. This ma
|
|||||||
* - **path P**
|
* - **path P**
|
||||||
- Write to this file.
|
- Write to this file.
|
||||||
* - **format_path P**
|
* - **format_path P**
|
||||||
- An alternative to path which provides a format string referring to tag values. The special tag iso8601 emits the current date and time in `ISO8601 <https://en.wikipedia.org/wiki/ISO_8601>`_ format (UTC). Every time a new song starts or a new tag gets received from a radio station, a new file is opened. If the format does not render a file name, nothing is recorded. A tag name enclosed in percent signs ('%') is replaced with the tag value. Example: :file:`~/.mpd/recorder/%artist% - %title%.ogg`. Square brackets can be used to group a substring. If none of the tags referred in the group can be found, the whole group is omitted. Example: [~/.mpd/recorder/[%artist% - ]%title%.ogg] (this omits the dash when no artist tag exists; if title also doesn't exist, no file is written). The operators "|" (logical "or") and "&" (logical "and") can be used to select portions of the format string depending on the existing tag values. Example: ~/.mpd/recorder/[%title%|%name%].ogg (use the "name" tag if no title exists)
|
- An alternative to path which provides a format string referring to tag values. The special tag iso8601 emits the current date and time in `ISO8601 <https://en.wikipedia.org/wiki/ISO_8601>`_ format (UTC). Every time a new song starts or a new tag gets received from a radio station, a new file is opened. If the format does not render a file name, nothing is recorded. A tag name enclosed in percent signs ('%') is replaced with the tag value. Example: :file:`-/.mpd/recorder/%artist% - %title%.ogg`. Square brackets can be used to group a substring. If none of the tags referred in the group can be found, the whole group is omitted. Example: [-/.mpd/recorder/[%artist% - ]%title%.ogg] (this omits the dash when no artist tag exists; if title also doesn't exist, no file is written). The operators "|" (logical "or") and "&" (logical "and") can be used to select portions of the format string depending on the existing tag values. Example: -/.mpd/recorder/[%title%|%name%].ogg (use the "name" tag if no title exists)
|
||||||
* - **encoder NAME**
|
* - **encoder NAME**
|
||||||
- Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`.
|
- Chooses an encoder plugin. A list of encoder plugins can be found in the encoder plugin reference :ref:`encoder_plugins`.
|
||||||
|
|
||||||
|
|
||||||
shout
|
shout
|
||||||
~~~~~
|
-----
|
||||||
The shout plugin connects to a ShoutCast or IceCast server using libshout. It forwards tags to this server.
|
The shout plugin connects to a ShoutCast or IceCast server using libshout. It forwards tags to this server.
|
||||||
|
|
||||||
You must set a format.
|
You must set a format.
|
||||||
@@ -1017,15 +1120,16 @@ You must set a format.
|
|||||||
.. _sles_output:
|
.. _sles_output:
|
||||||
|
|
||||||
sles
|
sles
|
||||||
~~~~
|
----
|
||||||
|
|
||||||
Plugin using the `OpenSL ES <https://www.khronos.org/opensles/>`__
|
Plugin using the `OpenSL ES <https://www.khronos.org/opensles/>`__
|
||||||
audio API. Its primary use is local playback on Android, where
|
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
|
solaris
|
||||||
~~~~~~~
|
-------
|
||||||
The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
|
The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -1037,46 +1141,129 @@ The "Solaris" plugin runs only on SUN Solaris, and plays via /dev/audio.
|
|||||||
* - **device PATH**
|
* - **device PATH**
|
||||||
- Sets the path of the audio device, defaults to /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
|
||||||
|
---------
|
||||||
|
|
||||||
|
Normalize the volume during playback (at the expense of quality).
|
||||||
|
|
||||||
|
|
||||||
|
null
|
||||||
|
----
|
||||||
|
|
||||||
|
A no-op filter. Audio data is returned as-is.
|
||||||
|
|
||||||
|
|
||||||
|
route
|
||||||
|
-----
|
||||||
|
|
||||||
|
Reroute channels.
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:widths: 20 80
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - Setting
|
||||||
|
- Description
|
||||||
|
* - **routes "0>0, 1>1, ..."**
|
||||||
|
- Specifies the channel mapping.
|
||||||
|
|
||||||
|
|
||||||
.. _playlist_plugins:
|
.. _playlist_plugins:
|
||||||
|
|
||||||
Playlist plugins
|
Playlist plugins
|
||||||
----------------
|
================
|
||||||
|
|
||||||
asx
|
asx
|
||||||
~~~
|
---
|
||||||
|
|
||||||
Reads .asx playlist files.
|
Reads :file:`.asx` playlist files.
|
||||||
|
|
||||||
|
.. _cue_playlist:
|
||||||
|
|
||||||
cue
|
cue
|
||||||
~~~
|
---
|
||||||
Reads .cue files.
|
Reads :file:`.cue` files.
|
||||||
|
|
||||||
embcue
|
embcue
|
||||||
~~~~~~
|
------
|
||||||
Reads CUE sheets from the "CUESHEET" tag of song files.
|
Reads CUE sheets from the ``CUESHEET`` tag of song files.
|
||||||
|
|
||||||
m3u
|
m3u
|
||||||
~~~
|
---
|
||||||
Reads .m3u playlist files.
|
Reads :file:`.m3u` playlist files.
|
||||||
|
|
||||||
extm3u
|
extm3u
|
||||||
~~~~~~
|
------
|
||||||
Reads extended .m3u playlist files.
|
Reads extended :file:`.m3u` playlist files.
|
||||||
|
|
||||||
flac
|
flac
|
||||||
~~~~
|
----
|
||||||
Reads the cuesheet metablock from a FLAC file.
|
Reads the cuesheet metablock from a FLAC file.
|
||||||
|
|
||||||
pls
|
pls
|
||||||
~~~
|
---
|
||||||
Reads .pls playlist files.
|
Reads :file:`.pls` playlist files.
|
||||||
|
|
||||||
rss
|
rss
|
||||||
~~~
|
---
|
||||||
Reads music links from .rss files.
|
Reads music links from :file:`.rss` files.
|
||||||
|
|
||||||
soundcloud
|
soundcloud
|
||||||
~~~~~~~~~~
|
----------
|
||||||
|
|
||||||
Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
|
Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -1089,5 +1276,21 @@ Download playlist from SoundCloud. It accepts URIs starting with soundcloud://.
|
|||||||
- An API key to access the SoundCloud servers.
|
- An API key to access the SoundCloud servers.
|
||||||
|
|
||||||
xspf
|
xspf
|
||||||
~~~~
|
----
|
||||||
Reads XSPF playlist files.
|
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/>`_.
|
||||||
|
|||||||
188
doc/protocol.rst
188
doc/protocol.rst
@@ -14,6 +14,9 @@ Once the client is connected to the server, they conduct a
|
|||||||
conversation until the client closes the connection. The
|
conversation until the client closes the connection. The
|
||||||
conversation flow is always initiated by the client.
|
conversation flow is always initiated by the client.
|
||||||
|
|
||||||
|
All data between the client and the server is encoded in
|
||||||
|
UTF-8.
|
||||||
|
|
||||||
The client transmits a command sequence, terminated by the
|
The client transmits a command sequence, terminated by the
|
||||||
newline character ``\n``. The server will
|
newline character ``\n``. The server will
|
||||||
respond with one or more lines, the last of which will be a
|
respond with one or more lines, the last of which will be a
|
||||||
@@ -42,9 +45,6 @@ quotation marks.
|
|||||||
Argument strings are separated from the command and any other
|
Argument strings are separated from the command and any other
|
||||||
arguments by linear white-space (' ' or '\\t').
|
arguments by linear white-space (' ' or '\\t').
|
||||||
|
|
||||||
All data between the client and the server is encoded in
|
|
||||||
UTF-8.
|
|
||||||
|
|
||||||
Responses
|
Responses
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@@ -52,6 +52,37 @@ A command returns ``OK`` on completion or
|
|||||||
``ACK some error`` on failure. These
|
``ACK some error`` on failure. These
|
||||||
denote the end of command execution.
|
denote the end of command execution.
|
||||||
|
|
||||||
|
Some commands return more data before the response ends with ``OK``.
|
||||||
|
Each line is usually in the form ``NAME: VALUE``. Example::
|
||||||
|
|
||||||
|
foo: bar
|
||||||
|
OK
|
||||||
|
|
||||||
|
.. _binary:
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
<42 bytes>
|
||||||
|
OK
|
||||||
|
|
||||||
|
|
||||||
Failure responses
|
Failure responses
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@@ -112,9 +143,9 @@ list begins with `command_list_begin` or
|
|||||||
`command_list_ok_begin` and ends with
|
`command_list_ok_begin` and ends with
|
||||||
`command_list_end`.
|
`command_list_end`.
|
||||||
|
|
||||||
It does not execute any commands until the list has ended.
|
It does not execute any commands until the list has ended. The
|
||||||
The return value is whatever the return for a list of commands
|
response is a concatentation of all individual responses.
|
||||||
is. On success for all commands,
|
On success for all commands,
|
||||||
``OK`` is returned. If a command
|
``OK`` is returned. If a command
|
||||||
fails, no more commands are executed and the appropriate
|
fails, no more commands are executed and the appropriate
|
||||||
``ACK`` error is returned. If
|
``ACK`` error is returned. If
|
||||||
@@ -141,7 +172,7 @@ syntax::
|
|||||||
|
|
||||||
find EXPRESSION
|
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:
|
of:
|
||||||
|
|
||||||
- ``(TAG == 'VALUE')``: match a tag value; if there are multiple
|
- ``(TAG == 'VALUE')``: match a tag value; if there are multiple
|
||||||
@@ -178,23 +209,24 @@ of:
|
|||||||
file's time stamp with the given value (ISO 8601 or UNIX
|
file's time stamp with the given value (ISO 8601 or UNIX
|
||||||
time stamp).
|
time stamp).
|
||||||
|
|
||||||
- ``(AudioFormat == 'SAMPLERATE:BITS:CHANNELS')``:
|
- ``(AudioFormat == 'SAMPLERATE:BITS:CHANNELS')``: compares the audio
|
||||||
compares the audio format with the given value.
|
format with the given value. See :ref:`audio_output_format` for a
|
||||||
|
detailed explanation.
|
||||||
|
|
||||||
- ``(AudioFormat =~ 'SAMPLERATE:BITS:CHANNELS')``:
|
- ``(AudioFormat =~ 'SAMPLERATE:BITS:CHANNELS')``:
|
||||||
matches the audio format with the given mask (i.e. one
|
matches the audio format with the given mask (i.e. one
|
||||||
or more attributes may be ``*``).
|
or more attributes may be ``*``).
|
||||||
|
|
||||||
- ``(!EXPRESSION)``: negate an expression. Note that each expression
|
- ``(!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')`)
|
(which is equivalent to :code:`(artist != 'VALUE')`)
|
||||||
|
|
||||||
- ``(EXPRESSION1 AND EXPRESSION2 ...)``: combine two or
|
- ``(EXPRESSION1 AND EXPRESSION2 ...)``: combine two or
|
||||||
more expressions with logical "and". Note that each expression must
|
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'))`
|
(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.
|
:command:`search` and related commands ignore case.
|
||||||
|
|
||||||
Prior to MPD 0.21, the syntax looked like this::
|
Prior to MPD 0.21, the syntax looked like this::
|
||||||
@@ -251,6 +283,12 @@ The following tags are supported by :program:`MPD`:
|
|||||||
* **date**: the song's release date. This is usually a 4-digit year.
|
* **date**: the song's release date. This is usually a 4-digit year.
|
||||||
* **composer**: the artist who composed the song.
|
* **composer**: the artist who composed the song.
|
||||||
* **performer**: the artist who performed 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.
|
* **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.
|
* **disc**: the decimal disc number in a multi-disc album.
|
||||||
* **label**: the name of the label or publisher.
|
* **label**: the name of the label or publisher.
|
||||||
@@ -351,7 +389,9 @@ Querying :program:`MPD`'s status
|
|||||||
|
|
||||||
:command:`currentsong`
|
:command:`currentsong`
|
||||||
Displays the song info of the current song (same song that
|
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:
|
.. _command_idle:
|
||||||
|
|
||||||
@@ -375,9 +415,11 @@ Querying :program:`MPD`'s status
|
|||||||
- ``sticker``: the sticker database has been modified.
|
- ``sticker``: the sticker database has been modified.
|
||||||
- ``subscription``: a client has subscribed or unsubscribed to a channel
|
- ``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
|
- ``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
|
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
|
something else with the connection. If an event had already
|
||||||
occurred since the last call, the new :ref:`idle <command_idle>`
|
occurred since the last call, the new :ref:`idle <command_idle>`
|
||||||
command will return immediately.
|
command will return immediately.
|
||||||
@@ -401,6 +443,8 @@ Querying :program:`MPD`'s status
|
|||||||
Reports the current status of the player and the volume
|
Reports the current status of the player and the volume
|
||||||
level.
|
level.
|
||||||
|
|
||||||
|
- ``partition``: the name of the current partition (see
|
||||||
|
:ref:`partition_commands`)
|
||||||
- ``volume``: ``0-100`` (deprecated: ``-1`` if the volume cannot
|
- ``volume``: ``0-100`` (deprecated: ``-1`` if the volume cannot
|
||||||
be determined)
|
be determined)
|
||||||
- ``repeat``: ``0`` or ``1``
|
- ``repeat``: ``0`` or ``1``
|
||||||
@@ -414,15 +458,18 @@ Querying :program:`MPD`'s status
|
|||||||
- ``songid``: playlist songid of the current song stopped on or playing
|
- ``songid``: playlist songid of the current song stopped on or playing
|
||||||
- ``nextsong`` [#since_0_15]_: playlist song number of the next song to be played
|
- ``nextsong`` [#since_0_15]_: playlist song number of the next song to be played
|
||||||
- ``nextsongid`` [#since_0_15]_: playlist songid of the next song to be played
|
- ``nextsongid`` [#since_0_15]_: playlist songid of the next song to be played
|
||||||
- ``time``: total time elapsed (of current playing/paused song)
|
- ``time``: total time elapsed (of current playing/paused song) in seconds
|
||||||
(deprecated, use ``elapsed`` instead)
|
(deprecated, use ``elapsed`` instead)
|
||||||
- ``elapsed`` [#since_0_16]_: Total time elapsed within the current song, but with higher resolution.
|
- ``elapsed`` [#since_0_16]_: Total time elapsed within the
|
||||||
|
current song in seconds, but with higher resolution.
|
||||||
- ``duration`` [#since_0_20]_: Duration of the current song in seconds.
|
- ``duration`` [#since_0_20]_: Duration of the current song in seconds.
|
||||||
- ``bitrate``: instantaneous bitrate in kbps
|
- ``bitrate``: instantaneous bitrate in kbps
|
||||||
- ``xfade``: ``crossfade`` in seconds
|
- ``xfade``: ``crossfade`` in seconds
|
||||||
- ``mixrampdb``: ``mixramp`` threshold in dB
|
- ``mixrampdb``: ``mixramp`` threshold in dB
|
||||||
- ``mixrampdelay``: ``mixrampdelay`` in seconds
|
- ``mixrampdelay``: ``mixrampdelay`` in seconds
|
||||||
- ``audio``: The format emitted by the decoder plugin during playback, format: ``*samplerate:bits:channels*``. Check the user manual for a detailed explanation.
|
- ``audio``: The format emitted by the decoder plugin during
|
||||||
|
playback, format: ``samplerate:bits:channels``. See
|
||||||
|
:ref:`audio_output_format` for a detailed explanation.
|
||||||
- ``updating_db``: ``job id``
|
- ``updating_db``: ``job id``
|
||||||
- ``error``: if there is an error, returns message here
|
- ``error``: if there is an error, returns message here
|
||||||
|
|
||||||
@@ -437,8 +484,9 @@ Querying :program:`MPD`'s status
|
|||||||
- ``albums``: number of albums
|
- ``albums``: number of albums
|
||||||
- ``songs``: number of songs
|
- ``songs``: number of songs
|
||||||
- ``uptime``: daemon uptime in seconds
|
- ``uptime``: daemon uptime in seconds
|
||||||
- ``db_playtime``: sum of all song times in the db
|
- ``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
|
- ``playtime``: time length of music played
|
||||||
|
|
||||||
Playback options
|
Playback options
|
||||||
@@ -488,7 +536,7 @@ Playback options
|
|||||||
``auto``
|
``auto``
|
||||||
.
|
.
|
||||||
Changing the mode during playback may take several
|
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.
|
buffered data.
|
||||||
This command triggers the
|
This command triggers the
|
||||||
``options`` idle event.
|
``options`` idle event.
|
||||||
@@ -508,10 +556,10 @@ Controlling playback
|
|||||||
:command:`next`
|
:command:`next`
|
||||||
Plays next song in the playlist.
|
Plays next song in the playlist.
|
||||||
|
|
||||||
:command:`pause {PAUSE}`
|
:command:`pause {STATE}`
|
||||||
Toggles pause/resumes playing, ``PAUSE`` is 0 or 1.
|
Pause or resume playback. Pass :samp:`1` to pause playback or
|
||||||
|
:samp:`0` to resume playback. Without the parameter, the pause
|
||||||
The use of pause command without the PAUSE argument is deprecated.
|
state is toggled.
|
||||||
|
|
||||||
:command:`play [SONGPOS]`
|
:command:`play [SONGPOS]`
|
||||||
Begins playing the playlist at song number
|
Begins playing the playlist at song number
|
||||||
@@ -599,7 +647,7 @@ Whenever possible, ids should be used.
|
|||||||
Deletes the song ``SONGID`` from the
|
Deletes the song ``SONGID`` from the
|
||||||
playlist
|
playlist
|
||||||
|
|
||||||
:command:`move {FROM} [{START:END} | {TO}]`
|
:command:`move [{FROM} | {START:END}] {TO}`
|
||||||
Moves the song at ``FROM`` or range of songs
|
Moves the song at ``FROM`` or range of songs
|
||||||
at ``START:END`` [#since_0_15]_ to ``TO``
|
at ``START:END`` [#since_0_15]_ to ``TO``
|
||||||
in the playlist.
|
in the playlist.
|
||||||
@@ -721,7 +769,7 @@ run playlist plugins instead of the hard-coded simple
|
|||||||
`m3u` parser. They can access playlists in
|
`m3u` parser. They can access playlists in
|
||||||
the music directory (relative path including the suffix),
|
the music directory (relative path including the suffix),
|
||||||
playlists in arbitrary location (absolute path including the suffix;
|
playlists in arbitrary location (absolute path including the suffix;
|
||||||
allowed only for clients that are connected via UNIX domain socket), or
|
allowed only for clients that are connected via local socket), or
|
||||||
remote playlists (absolute URI with a supported scheme).
|
remote playlists (absolute URI with a supported scheme).
|
||||||
|
|
||||||
:command:`listplaylist {NAME}`
|
:command:`listplaylist {NAME}`
|
||||||
@@ -782,20 +830,21 @@ The music database
|
|||||||
==================
|
==================
|
||||||
|
|
||||||
:command:`albumart {URI} {OFFSET}`
|
:command:`albumart {URI} {OFFSET}`
|
||||||
Searches the directory the file ``URI``
|
Locate album art for the given song and return a chunk of an album
|
||||||
resides in and attempts to return a chunk of an album
|
|
||||||
art image file at offset ``OFFSET``.
|
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
|
Returns the file size and actual number
|
||||||
of bytes read at the requested offset, followed
|
of bytes read at the requested offset, followed
|
||||||
by the chunk requested as raw bytes, then a
|
by the chunk requested as raw bytes (see :ref:`binary`), then a
|
||||||
newline and the completion code.
|
newline and the completion code.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
albumart
|
albumart foo/bar.ogg 0
|
||||||
size: 1024768
|
size: 1024768
|
||||||
binary: 8192
|
binary: 8192
|
||||||
<8192 bytes>
|
<8192 bytes>
|
||||||
@@ -819,10 +868,21 @@ The music database
|
|||||||
count group artist
|
count group artist
|
||||||
count title Echoes group artist
|
count title Echoes group artist
|
||||||
|
|
||||||
A group with an empty value contains counts of matching song which
|
A group with an empty value contains counts of matching songs which
|
||||||
don't this group tag. It exists only if at least one such song is
|
don't have this group tag. It exists only if at least one such song is
|
||||||
found.
|
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:
|
||||||
|
|
||||||
:command:`find {FILTER} [sort {TYPE}] [window {START:END}]`
|
:command:`find {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||||
@@ -849,7 +909,7 @@ The music database
|
|||||||
|
|
||||||
.. _command_findadd:
|
.. _command_findadd:
|
||||||
|
|
||||||
:command:`findadd {FILTER}`
|
:command:`findadd {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||||
Search the database for songs matching
|
Search the database for songs matching
|
||||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||||
the queue. Parameters have the same meaning as for
|
the queue. Parameters have the same meaning as for
|
||||||
@@ -860,8 +920,7 @@ The music database
|
|||||||
:command:`list {TYPE} {FILTER} [group {GROUPTYPE}]`
|
:command:`list {TYPE} {FILTER} [group {GROUPTYPE}]`
|
||||||
Lists unique tags values of the specified type.
|
Lists unique tags values of the specified type.
|
||||||
``TYPE`` can be any tag supported by
|
``TYPE`` can be any tag supported by
|
||||||
:program:`MPD` or
|
:program:`MPD`.
|
||||||
*file*.
|
|
||||||
|
|
||||||
Additional arguments may specify a :ref:`filter <filter_syntax>`.
|
Additional arguments may specify a :ref:`filter <filter_syntax>`.
|
||||||
The *group* keyword may be used
|
The *group* keyword may be used
|
||||||
@@ -872,6 +931,10 @@ The music database
|
|||||||
|
|
||||||
list album group albumartist
|
list album group albumartist
|
||||||
|
|
||||||
|
``list file`` was implemented in an early :program:`MPD` version,
|
||||||
|
but does not appear to make a lot of sense. It still works (to
|
||||||
|
avoid breaking compatibility), but is deprecated.
|
||||||
|
|
||||||
.. _command_listall:
|
.. _command_listall:
|
||||||
|
|
||||||
:command:`listall [URI]`
|
:command:`listall [URI]`
|
||||||
@@ -931,7 +994,7 @@ The music database
|
|||||||
This command may be used to list metadata of remote
|
This command may be used to list metadata of remote
|
||||||
files (e.g. URI beginning with "http://" or "smb://").
|
files (e.g. URI beginning with "http://" or "smb://").
|
||||||
|
|
||||||
Clients that are connected via UNIX domain socket may
|
Clients that are connected via local socket may
|
||||||
use this command to read the tags of an arbitrary local
|
use this command to read the tags of an arbitrary local
|
||||||
file (URI is an absolute path).
|
file (URI is an absolute path).
|
||||||
|
|
||||||
@@ -951,6 +1014,30 @@ The music database
|
|||||||
decoder plugins support it. For example, on Ogg files,
|
decoder plugins support it. For example, on Ogg files,
|
||||||
this lists the Vorbis comments.
|
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:
|
||||||
|
|
||||||
:command:`search {FILTER} [sort {TYPE}] [window {START:END}]`
|
:command:`search {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||||
@@ -961,14 +1048,14 @@ The music database
|
|||||||
|
|
||||||
.. _command_searchadd:
|
.. _command_searchadd:
|
||||||
|
|
||||||
:command:`searchadd {FILTER}`
|
:command:`searchadd {FILTER} [sort {TYPE}] [window {START:END}]`
|
||||||
Search the database for songs matching
|
Search the database for songs matching
|
||||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||||
the queue.
|
the queue.
|
||||||
|
|
||||||
Parameters have the same meaning as for :ref:`search <command_search>`.
|
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
|
Search the database for songs matching
|
||||||
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
``FILTER`` (see :ref:`Filters <filter_syntax>`) and add them to
|
||||||
the playlist named ``NAME``.
|
the playlist named ``NAME``.
|
||||||
@@ -1008,8 +1095,8 @@ access NFS and SMB servers.
|
|||||||
Multiple storages can be "mounted" together, similar to the
|
Multiple storages can be "mounted" together, similar to the
|
||||||
`mount` command on many operating
|
`mount` command on many operating
|
||||||
systems, but without cooperation from the kernel. No
|
systems, but without cooperation from the kernel. No
|
||||||
superuser privileges are necessary, beause this mapping exists
|
superuser privileges are necessary, because this mapping exists
|
||||||
only inside the :program:`MPD` process
|
only inside the :program:`MPD` process.
|
||||||
|
|
||||||
.. _command_mount:
|
.. _command_mount:
|
||||||
|
|
||||||
@@ -1053,7 +1140,8 @@ Stickers
|
|||||||
"Stickers" [#since_0_15]_ are pieces of
|
"Stickers" [#since_0_15]_ are pieces of
|
||||||
information attached to existing
|
information attached to existing
|
||||||
:program:`MPD` objects (e.g. song files,
|
:program:`MPD` objects (e.g. song files,
|
||||||
directories, albums). Clients can create arbitrary name/value
|
directories, albums; but currently, they are only implemented for
|
||||||
|
song). Clients can create arbitrary name/value
|
||||||
pairs. :program:`MPD` itself does not assume
|
pairs. :program:`MPD` itself does not assume
|
||||||
any special meaning in them.
|
any special meaning in them.
|
||||||
|
|
||||||
@@ -1157,6 +1245,8 @@ Connection settings
|
|||||||
Announce that this client is interested in all tag
|
Announce that this client is interested in all tag
|
||||||
types. This is the default setting for new clients.
|
types. This is the default setting for new clients.
|
||||||
|
|
||||||
|
.. _partition_commands:
|
||||||
|
|
||||||
Partition commands
|
Partition commands
|
||||||
==================
|
==================
|
||||||
|
|
||||||
@@ -1177,6 +1267,13 @@ client is assigned to one partition at a time.
|
|||||||
:command:`newpartition {NAME}`
|
:command:`newpartition {NAME}`
|
||||||
Create a new partition.
|
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
|
Audio output devices
|
||||||
====================
|
====================
|
||||||
|
|
||||||
@@ -1222,7 +1319,7 @@ Reflection
|
|||||||
:command:`config`
|
:command:`config`
|
||||||
Dumps configuration values that may be interesting for
|
Dumps configuration values that may be interesting for
|
||||||
the client. This command is only permitted to "local"
|
the client. This command is only permitted to "local"
|
||||||
clients (connected via UNIX domain socket).
|
clients (connected via local socket).
|
||||||
|
|
||||||
The following response attributes are available:
|
The following response attributes are available:
|
||||||
|
|
||||||
@@ -1266,6 +1363,9 @@ additional services.
|
|||||||
New messages are indicated by the ``message``
|
New messages are indicated by the ``message``
|
||||||
idle event.
|
idle event.
|
||||||
|
|
||||||
|
If your MPD instance has multiple partitions, note that
|
||||||
|
client-to-client messages are local to the current partition.
|
||||||
|
|
||||||
:command:`subscribe {NAME}`
|
:command:`subscribe {NAME}`
|
||||||
Subscribe to a channel. The channel is created if it
|
Subscribe to a channel. The channel is created if it
|
||||||
does not exist already. The name may consist of
|
does not exist already. The name may consist of
|
||||||
|
|||||||
390
doc/user.rst
390
doc/user.rst
@@ -44,7 +44,9 @@ ALSA is not available on Android; only the :ref:`OpenSL ES
|
|||||||
Compiling from source
|
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
|
.. code-block:: none
|
||||||
|
|
||||||
@@ -53,8 +55,8 @@ Download the source tarball from the `MPD home page <https://musicpd.org>`_ and
|
|||||||
|
|
||||||
In any case, you need:
|
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.47.2 <http://mesonbuild.com/>`__ and `Ninja
|
* `Meson 0.49.0 <http://mesonbuild.com/>`__ and `Ninja
|
||||||
<https://ninja-build.org/>`__
|
<https://ninja-build.org/>`__
|
||||||
* Boost 1.58
|
* Boost 1.58
|
||||||
* pkg-config
|
* pkg-config
|
||||||
@@ -62,16 +64,16 @@ In any case, you need:
|
|||||||
Each plugin usually needs a codec library, which you also need to
|
Each plugin usually needs a codec library, which you also need to
|
||||||
install. Check the :doc:`plugins` for details about required libraries
|
install. Check the :doc:`plugins` for details about required libraries
|
||||||
|
|
||||||
For example, the following installs a fairly complete list of build dependencies on Debian Jessie:
|
For example, the following installs a fairly complete list of build dependencies on Debian Buster:
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
apt install g++ \
|
apt install meson g++ \
|
||||||
libpcre3-dev \
|
libpcre3-dev \
|
||||||
libmad0-dev libmpg123-dev libid3tag0-dev \
|
libmad0-dev libmpg123-dev libid3tag0-dev \
|
||||||
libflac-dev libvorbis-dev libopus-dev \
|
libflac-dev libvorbis-dev libopus-dev libogg-dev \
|
||||||
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
|
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
|
||||||
libfluidsynth-dev libgme-dev libmikmod2-dev libmodplug-dev \
|
libfluidsynth-dev libgme-dev libmikmod-dev libmodplug-dev \
|
||||||
libmpcdec-dev libwavpack-dev libwildmidi-dev \
|
libmpcdec-dev libwavpack-dev libwildmidi-dev \
|
||||||
libsidplay2-dev libsidutils-dev libresid-builder-dev \
|
libsidplay2-dev libsidutils-dev libresid-builder-dev \
|
||||||
libavcodec-dev libavformat-dev \
|
libavcodec-dev libavformat-dev \
|
||||||
@@ -84,14 +86,16 @@ For example, the following installs a fairly complete list of build dependencies
|
|||||||
libpulse-dev libshout3-dev \
|
libpulse-dev libshout3-dev \
|
||||||
libsndio-dev \
|
libsndio-dev \
|
||||||
libmpdclient-dev \
|
libmpdclient-dev \
|
||||||
libnfs-dev libsmbclient-dev \
|
libnfs-dev \
|
||||||
libupnp-dev \
|
libupnp-dev \
|
||||||
libavahi-client-dev \
|
libavahi-client-dev \
|
||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
libsystemd-dev \
|
libsystemd-dev \
|
||||||
libgtest-dev \
|
libgtest-dev \
|
||||||
libboost-dev \
|
libboost-dev \
|
||||||
libicu-dev
|
libicu-dev \
|
||||||
|
libchromaprint-dev \
|
||||||
|
libgcrypt20-dev
|
||||||
|
|
||||||
|
|
||||||
Now configure the source tree:
|
Now configure the source tree:
|
||||||
@@ -183,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`.
|
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
|
Configuration
|
||||||
*************
|
*************
|
||||||
|
|
||||||
@@ -258,6 +221,13 @@ another file; the given file name is relative to the current file:
|
|||||||
|
|
||||||
include "other.conf"
|
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
|
Configuring the music directory
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
@@ -334,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.
|
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
|
Configuring decoder plugins
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
@@ -365,10 +373,14 @@ More information can be found in the :ref:`decoder_plugins` reference.
|
|||||||
Configuring encoder plugins
|
Configuring encoder plugins
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
Encoders are used by some of the output plugins (such as shout). The encoder settings are included in the audio_output section.
|
Encoders are used by some of the output plugins (such as shout). The
|
||||||
|
encoder settings are included in the ``audio_output`` section, see :ref:`config_audio_output`.
|
||||||
|
|
||||||
More information can be found in the :ref:`encoder_plugins` reference.
|
More information can be found in the :ref:`encoder_plugins` reference.
|
||||||
|
|
||||||
|
|
||||||
|
.. _config_audio_output:
|
||||||
|
|
||||||
Configuring audio outputs
|
Configuring audio outputs
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
@@ -398,15 +410,10 @@ The following table lists the audio_output options valid for all plugins:
|
|||||||
- The name of the plugin
|
- The name of the plugin
|
||||||
* - **name**
|
* - **name**
|
||||||
- The name of the audio output. It is visible to the client. Some plugins also use it internally, e.g. as a name registered in the PULSE server.
|
- The name of the audio output. It is visible to the client. Some plugins also use it internally, e.g. as a name registered in the PULSE server.
|
||||||
* - **format**
|
* - **format samplerate:bits:channels**
|
||||||
- Always open the audio output with the specified audio format samplerate:bits:channels), regardless of the format of the input file. This is optional for most plugins.
|
- Always open the audio output with the specified audio format, regardless of the format of the input file. This is optional for most plugins.
|
||||||
|
See :ref:`audio_output_format` for a detailed description of the value.
|
||||||
Any of the three attributes may be an asterisk to specify that this attribute should not be enforced, example: 48000:16:*. *:*:* is equal to not having a format specification.
|
* - **enabled yes|no**
|
||||||
|
|
||||||
The following values are valid for bits: 8 (signed 8 bit integer samples), 16, 24 (signed 24 bit integer samples padded to 32 bit), 32 (signed 32 bit integer samples), f (32 bit floating point, -1.0 to 1.0), "dsd" means DSD (Direct Stream Digital). For DSD, there are special cases such as "dsd64", which allows you to omit the sample rate (e.g. dsd512:2 for stereo DSD512, i.e. 22.5792 MHz).
|
|
||||||
|
|
||||||
The sample rate is special for DSD: :program:`MPD` counts the number of bytes, not bits. Thus, a DSD "bit" rate of 22.5792 MHz (DSD512) is 2822400 from :program:`MPD`'s point of view (44100*512/8).
|
|
||||||
* - **enabed yes|no**
|
|
||||||
- Specifies whether this audio output is enabled when :program:`MPD` is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.
|
- Specifies whether this audio output is enabled when :program:`MPD` is started. By default, all audio outputs are enabled. This is just the default setting when there is no state file; with a state file, the previous state is restored.
|
||||||
* - **tags yes|no**
|
* - **tags yes|no**
|
||||||
- If set to no, then :program:`MPD` will not send tags to this output. This is only useful for output plugins that can receive tags, for example the httpd output plugin.
|
- If set to no, then :program:`MPD` will not send tags to this output. This is only useful for output plugins that can receive tags, for example the httpd output plugin.
|
||||||
@@ -418,9 +425,18 @@ The following table lists the audio_output options valid for all plugins:
|
|||||||
:ref:`oss_plugin` and PulseAudio :ref:`pulse_plugin`), the
|
:ref:`oss_plugin` and PulseAudio :ref:`pulse_plugin`), the
|
||||||
software mixer, the ":samp:`null`" mixer (allows setting the
|
software mixer, the ":samp:`null`" mixer (allows setting the
|
||||||
volume, but with no effect; this can be used as a trick to
|
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
|
(:samp:`none`). By default, the hardware mixer is used for
|
||||||
devices which support it, and none for the others.
|
devices which support it, and none for the others.
|
||||||
|
* - **filters "name,...**"
|
||||||
|
- The specified configured filters are instantiated in the given
|
||||||
|
order. Each filter name refers to a ``filter`` block, see
|
||||||
|
:ref:`config_filter`.
|
||||||
|
|
||||||
|
More information can be found in the :ref:`output_plugins` reference.
|
||||||
|
|
||||||
|
|
||||||
|
.. _config_filter:
|
||||||
|
|
||||||
Configuring filters
|
Configuring filters
|
||||||
-------------------
|
-------------------
|
||||||
@@ -436,6 +452,9 @@ To configure a filter, add a :code:`filter` block to :file:`mpd.conf`:
|
|||||||
name "software volume"
|
name "software volume"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Configured filters may then be added to the ``filters`` setting of an
|
||||||
|
``audio_output`` section, see :ref:`config_audio_output`.
|
||||||
|
|
||||||
The following table lists the filter options valid for all plugins:
|
The following table lists the filter options valid for all plugins:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
@@ -449,6 +468,9 @@ The following table lists the filter options valid for all plugins:
|
|||||||
* - **name**
|
* - **name**
|
||||||
- The name of the filter
|
- The name of the filter
|
||||||
|
|
||||||
|
More information can be found in the :ref:`filter_plugins` reference.
|
||||||
|
|
||||||
|
|
||||||
Configuring playlist plugins
|
Configuring playlist plugins
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
@@ -478,6 +500,11 @@ The following table lists the playlist_plugin options valid for all plugins:
|
|||||||
- The name of the plugin
|
- The name of the plugin
|
||||||
* - **enabled yes|no**
|
* - **enabled yes|no**
|
||||||
- Allows you to disable a playlist plugin without recompiling. By default, all plugins are enabled.
|
- Allows you to disable a playlist plugin without recompiling. By default, all plugins are enabled.
|
||||||
|
* - **as_directory yes|no**
|
||||||
|
- With this option, a playlist file of this type is parsed during
|
||||||
|
database update and converted to a virtual directory, allowing
|
||||||
|
MPD clients to access individual entries. By default, this is
|
||||||
|
only enabled for the :ref:`cue plugin <cue_playlist>`.
|
||||||
|
|
||||||
More information can be found in the :ref:`playlist_plugins`
|
More information can be found in the :ref:`playlist_plugins`
|
||||||
reference.
|
reference.
|
||||||
@@ -485,13 +512,34 @@ reference.
|
|||||||
Audio Format Settings
|
Audio Format Settings
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Global Audio Format
|
.. _audio_output_format:
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
The setting audio_output_format forces :program:`MPD` to use one audio format for all outputs. Doing that is usually not a good idea. The values are the same as in format in the audio_output section.
|
Global Audio Format
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The setting ``audio_output_format`` forces :program:`MPD` to use one
|
||||||
|
audio format for all outputs. Doing that is usually not a good idea.
|
||||||
|
|
||||||
|
The value is specified as ``samplerate:bits:channels``.
|
||||||
|
|
||||||
|
Any of the three attributes may be an asterisk to specify that this
|
||||||
|
attribute should not be enforced, example: ``48000:16:*``.
|
||||||
|
``*:*:*`` is equal to not having a format specification.
|
||||||
|
|
||||||
|
The following values are valid for bits: ``8`` (signed 8 bit integer
|
||||||
|
samples), ``16``, ``24`` (signed 24 bit integer samples padded to 32
|
||||||
|
bit), ``32`` (signed 32 bit integer samples), ``f`` (32 bit floating
|
||||||
|
point, -1.0 to 1.0), ``dsd`` means DSD (Direct Stream Digital). For
|
||||||
|
DSD, there are special cases such as ``dsd64``, which allows you to
|
||||||
|
omit the sample rate (e.g. ``dsd512:2`` for stereo DSD512,
|
||||||
|
i.e. 22.5792 MHz).
|
||||||
|
|
||||||
|
The sample rate is special for DSD: :program:`MPD` counts the number
|
||||||
|
of bytes, not bits. Thus, a DSD "bit" rate of 22.5792 MHz (DSD512) is
|
||||||
|
2822400 from :program:`MPD`'s point of view (44100*512/8).
|
||||||
|
|
||||||
Resampler
|
Resampler
|
||||||
~~~~~~~~~
|
^^^^^^^^^
|
||||||
|
|
||||||
Sometimes, music needs to be resampled before it can be played; for example, CDs use a sample rate of 44,100 Hz while many cheap audio chips can only handle 48,000 Hz. Resampling reduces the quality and consumes a lot of CPU. There are different options, some of them optimized for high quality and others for low CPU usage, but you can't have both at the same time. Often, the resampler is the component that is responsible for most of :program:`MPD`'s CPU usage. Since :program:`MPD` comes with high quality defaults, it may appear that :program:`MPD` consumes more CPU than other software.
|
Sometimes, music needs to be resampled before it can be played; for example, CDs use a sample rate of 44,100 Hz while many cheap audio chips can only handle 48,000 Hz. Resampling reduces the quality and consumes a lot of CPU. There are different options, some of them optimized for high quality and others for low CPU usage, but you can't have both at the same time. Often, the resampler is the component that is responsible for most of :program:`MPD`'s CPU usage. Since :program:`MPD` comes with high quality defaults, it may appear that :program:`MPD` consumes more CPU than other software.
|
||||||
|
|
||||||
@@ -504,7 +552,7 @@ Client Connections
|
|||||||
.. _listeners:
|
.. _listeners:
|
||||||
|
|
||||||
Listeners
|
Listeners
|
||||||
~~~~~~~~~
|
^^^^^^^^^
|
||||||
|
|
||||||
The setting :code:`bind_to_address` specifies which addresses
|
The setting :code:`bind_to_address` specifies which addresses
|
||||||
:program:`MPD` listens on for connections from clients. It can be
|
:program:`MPD` listens on for connections from clients. It can be
|
||||||
@@ -547,7 +595,7 @@ used.
|
|||||||
|
|
||||||
|
|
||||||
Permissions and Passwords
|
Permissions and Passwords
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
By default, all clients are unauthenticated and have a full set of permissions. This can be restricted with the settings :code:`default_permissions` and :code:`password`.
|
By default, all clients are unauthenticated and have a full set of permissions. This can be restricted with the settings :code:`default_permissions` and :code:`password`.
|
||||||
|
|
||||||
@@ -610,7 +658,7 @@ Other Settings
|
|||||||
Section :ref:`tags` contains a list of supported tags.
|
Section :ref:`tags` contains a list of supported tags.
|
||||||
|
|
||||||
The State File
|
The State File
|
||||||
~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
The state file is a file where :program:`MPD` saves and restores its state (play queue, playback position etc.) to keep it persistent across restarts and reboots. It is an optional setting.
|
The state file is a file where :program:`MPD` saves and restores its state (play queue, playback position etc.) to keep it persistent across restarts and reboots. It is an optional setting.
|
||||||
|
|
||||||
@@ -628,7 +676,7 @@ The State File
|
|||||||
- Auto-save the state file this number of seconds after each state change. Defaults to 120 (2 minutes).
|
- Auto-save the state file this number of seconds after each state change. Defaults to 120 (2 minutes).
|
||||||
|
|
||||||
The Sticker Database
|
The Sticker Database
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
"Stickers" are pieces of information attached to songs. Some clients
|
"Stickers" are pieces of information attached to songs. Some clients
|
||||||
use them to store ratings and other volatile data. This feature
|
use them to store ratings and other volatile data. This feature
|
||||||
@@ -645,7 +693,7 @@ requires :program:`SQLite`, compile-time configure option
|
|||||||
- The location of the sticker database.
|
- The location of the sticker database.
|
||||||
|
|
||||||
Resource Limitations
|
Resource Limitations
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
These settings are various limitations to prevent :program:`MPD` from using too many resources (denial of service).
|
These settings are various limitations to prevent :program:`MPD` from using too many resources (denial of service).
|
||||||
|
|
||||||
@@ -658,7 +706,7 @@ These settings are various limitations to prevent :program:`MPD` from using too
|
|||||||
* - **connection_timeout SECONDS**
|
* - **connection_timeout SECONDS**
|
||||||
- If a client does not send any new data in this time period, the connection is closed. Clients waiting in "idle" mode are excluded from this. Default is 60.
|
- If a client does not send any new data in this time period, the connection is closed. Clients waiting in "idle" mode are excluded from this. Default is 60.
|
||||||
* - **max_connections NUMBER**
|
* - **max_connections NUMBER**
|
||||||
- This specifies the maximum number of clients that can be connected to :program:`MPD` at the same time. Default is 5.
|
- This specifies the maximum number of clients that can be connected to :program:`MPD` at the same time. Default is 100.
|
||||||
* - **max_playlist_length NUMBER**
|
* - **max_playlist_length NUMBER**
|
||||||
- The maximum number of songs that can be in the playlist. Default is 16384.
|
- The maximum number of songs that can be in the playlist. Default is 16384.
|
||||||
* - **max_command_list_size KBYTES**
|
* - **max_command_list_size KBYTES**
|
||||||
@@ -667,7 +715,7 @@ These settings are various limitations to prevent :program:`MPD` from using too
|
|||||||
- The maximum size of the output buffer to a client (maximum response size). Default is 8192 (8 MiB).
|
- The maximum size of the output buffer to a client (maximum response size). Default is 8192 (8 MiB).
|
||||||
|
|
||||||
Buffer Settings
|
Buffer Settings
|
||||||
~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Do not change these unless you know what you are doing.
|
Do not change these unless you know what you are doing.
|
||||||
|
|
||||||
@@ -677,11 +725,12 @@ Do not change these unless you know what you are doing.
|
|||||||
|
|
||||||
* - Setting
|
* - Setting
|
||||||
- Description
|
- Description
|
||||||
* - **audio_buffer_size KBYTES**
|
* - **audio_buffer_size SIZE**
|
||||||
- Adjust the size of the internal audio buffer. Default is 4096 (4 MiB).
|
- Adjust the size of the internal audio buffer. Default is
|
||||||
|
:samp:`4 MB` (4 MiB).
|
||||||
|
|
||||||
Zeroconf
|
Zeroconf
|
||||||
~~~~~~~~
|
^^^^^^^^
|
||||||
|
|
||||||
If Zeroconf support (`Avahi <http://avahi.org/>`_ or Apple's Bonjour)
|
If Zeroconf support (`Avahi <http://avahi.org/>`_ or Apple's Bonjour)
|
||||||
was enabled at compile time with :code:`-Dzeroconf=...`,
|
was enabled at compile time with :code:`-Dzeroconf=...`,
|
||||||
@@ -726,22 +775,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).
|
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
|
Real-Time Scheduling
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
On Linux, :program:`MPD` attempts to configure real-time scheduling for some threads that benefit from it.
|
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
|
.. 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:
|
Or you can use the :command:`prlimit` program from the util-linux package:
|
||||||
|
|
||||||
.. code-block:: none
|
.. 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.
|
The systemd service file shipped with :program:`MPD` comes with this setting.
|
||||||
|
|
||||||
@@ -759,22 +810,107 @@ You can verify whether the real-time scheduler is active with the ps command:
|
|||||||
PID TID CLS RTPRIO COMMAND
|
PID TID CLS RTPRIO COMMAND
|
||||||
16257 16257 TS - mpd
|
16257 16257 TS - mpd
|
||||||
16257 16258 TS - io
|
16257 16258 TS - io
|
||||||
16257 16259 FF 50 rtio
|
16257 16259 FF 40 rtio
|
||||||
16257 16260 TS - player
|
16257 16260 TS - player
|
||||||
16257 16261 TS - decoder
|
16257 16261 TS - decoder
|
||||||
16257 16262 FF 50 output:ALSA
|
16257 16262 FF 40 output:ALSA
|
||||||
16257 16263 IDL 0 update
|
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.
|
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.
|
||||||
|
|
||||||
Note
|
.. note::
|
||||||
~~~~
|
|
||||||
|
|
||||||
There is a rumor that real-time scheduling improves audio quality. That is not true. All it does is reduce the probability of skipping (audio buffer xruns) when the computer is under heavy load.
|
There is a rumor that real-time scheduling improves audio
|
||||||
|
quality. That is not true. All it does is reduce the probability of
|
||||||
|
skipping (audio buffer xruns) when the computer is under heavy
|
||||||
|
load.
|
||||||
|
|
||||||
Using MPD
|
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
|
The client
|
||||||
----------
|
----------
|
||||||
|
|
||||||
@@ -798,7 +934,7 @@ Depending on the size of your music collection and the speed of the storage, thi
|
|||||||
To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded.
|
To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded.
|
||||||
|
|
||||||
Mounting other storages into the music directory
|
Mounting other storages into the music directory
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
:program:`MPD` has various storage plugins of which multiple instances can be "mounted" into the music directory. This way, you can use local music, file servers and USB sticks at the same time. Example:
|
:program:`MPD` has various storage plugins of which multiple instances can be "mounted" into the music directory. This way, you can use local music, file servers and USB sticks at the same time. Example:
|
||||||
|
|
||||||
@@ -866,7 +1002,7 @@ To verify if :program:`MPD` converts the audio format, enable verbose logging, a
|
|||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
decoder: audio_format=44100:24:2, seekable=true
|
decoder: audio_format=44100:24:2, seekable=true
|
||||||
output: opened plugin=alsa name="An ALSA output"audio_format=44100:16:2
|
output: opened plugin=alsa name="An ALSA output" audio_format=44100:16:2
|
||||||
output: converting from 44100:24:2
|
output: converting from 44100:24:2
|
||||||
|
|
||||||
This example shows that a 24 bit file is being played, but the sound chip cannot play 24 bit. It falls back to 16 bit, discarding 8 bit.
|
This example shows that a 24 bit file is being played, but the sound chip cannot play 24 bit. It falls back to 16 bit, discarding 8 bit.
|
||||||
@@ -893,7 +1029,7 @@ Check list for bit-perfect playback:
|
|||||||
device (:samp:`hw:0,0` or similar).
|
device (:samp:`hw:0,0` or similar).
|
||||||
* Don't use software volume (setting :code:`mixer_type`).
|
* Don't use software volume (setting :code:`mixer_type`).
|
||||||
* Don't force :program:`MPD` to use a specific audio format (settings
|
* Don't force :program:`MPD` to use a specific audio format (settings
|
||||||
:code:`format`, :code:`audio_output_format`).
|
:code:`format`, :ref:`audio_output_format <audio_output_format>`).
|
||||||
* Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format.
|
* Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format.
|
||||||
|
|
||||||
Direct Stream Digital (DSD)
|
Direct Stream Digital (DSD)
|
||||||
@@ -914,6 +1050,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
|
it. DSD to PCM conversion is the fallback if DSD cannot be used
|
||||||
directly.
|
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
|
Client Hacks
|
||||||
************
|
************
|
||||||
|
|
||||||
@@ -938,47 +1090,79 @@ Sometimes, it is helpful to run :program:`MPD` in a terminal and follow what hap
|
|||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
mpd --stdout --no-daemon --verbose
|
mpd --stderr --no-daemon --verbose
|
||||||
|
|
||||||
Support
|
Support
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Getting Help
|
Getting Help
|
||||||
~~~~~~~~~~~~
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Freenode) for requesting help. Visit the MPD help page for details on how to get help.
|
The :program:`MPD` project runs a `forum <https://forum.musicpd.org/>`_ and an IRC channel (#mpd on Freenode) for requesting help. Visit the MPD help page for details on how to get help.
|
||||||
|
|
||||||
Common Problems
|
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.
|
* 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)?
|
* 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 update the database? (mpc update)
|
||||||
* Did you enable all relevant decoder plugins at compile time? :command:`mpd --version` will tell you.
|
* 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.
|
* 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.
|
* 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.
|
: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.
|
* This ALSA error means that another program uses your sound hardware exclusively. You can stop that program to allow :program:`MPD` to use it.
|
||||||
|
|
||||||
@@ -997,7 +1181,7 @@ Your bug report should contain:
|
|||||||
* be clear about what you expect MPD to do, and what is actually happening
|
* be clear about what you expect MPD to do, and what is actually happening
|
||||||
|
|
||||||
MPD crashes
|
MPD crashes
|
||||||
~~~~~~~~~~~
|
^^^^^^^^^^^
|
||||||
|
|
||||||
All :program:`MPD` crashes are bugs which must be fixed by a developer, and you should write a bug report. (Many crash bugs are caused by codec libraries used by :program:`MPD`, and then that library must be fixed; but in any case, the :program:`MPD` `bug tracker <https://github.com/MusicPlayerDaemon/MPD/issues>`_ is a good place to report it first if you don't know.)
|
All :program:`MPD` crashes are bugs which must be fixed by a developer, and you should write a bug report. (Many crash bugs are caused by codec libraries used by :program:`MPD`, and then that library must be fixed; but in any case, the :program:`MPD` `bug tracker <https://github.com/MusicPlayerDaemon/MPD/issues>`_ is a good place to report it first if you don't know.)
|
||||||
|
|
||||||
@@ -1018,7 +1202,7 @@ You can extract the backtrace from a core dump, or by running :program:`MPD` in
|
|||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: none
|
||||||
|
|
||||||
gdb --args mpd --stdout --no-daemon --verbose
|
gdb --args mpd --stderr --no-daemon --verbose
|
||||||
run
|
run
|
||||||
|
|
||||||
As soon as you have reproduced the crash, type ":command:`bt`" on the
|
As soon as you have reproduced the crash, type ":command:`bt`" on the
|
||||||
|
|||||||
176
meson.build
176
meson.build
@@ -1,11 +1,18 @@
|
|||||||
project(
|
project(
|
||||||
'mpd',
|
'mpd',
|
||||||
['c', 'cpp'],
|
['c', 'cpp'],
|
||||||
version: '0.21.6',
|
version: '0.22.3',
|
||||||
meson_version: '>= 0.47.2',
|
meson_version: '>= 0.49.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c99',
|
'c_std=c11',
|
||||||
'cpp_std=c++14'
|
'build.c_std=c11',
|
||||||
|
'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+',
|
license: 'GPLv2+',
|
||||||
)
|
)
|
||||||
@@ -15,12 +22,20 @@ version_cxx = vcs_tag(input: 'src/GitVersion.cxx', output: 'GitVersion.cxx')
|
|||||||
compiler = meson.get_compiler('cpp')
|
compiler = meson.get_compiler('cpp')
|
||||||
c_compiler = meson.get_compiler('c')
|
c_compiler = meson.get_compiler('c')
|
||||||
|
|
||||||
|
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 = 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.6')
|
|
||||||
conf.set_quoted('SYSTEM_CONFIG_FILE_LOCATION', join_paths(get_option('prefix'), get_option('sysconfdir'), 'mpd.conf'))
|
conf.set_quoted('SYSTEM_CONFIG_FILE_LOCATION', join_paths(get_option('prefix'), get_option('sysconfdir'), 'mpd.conf'))
|
||||||
|
|
||||||
common_cppflags = [
|
common_cppflags = [
|
||||||
@@ -34,8 +49,8 @@ common_cxxflags = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
test_common_flags = [
|
test_common_flags = [
|
||||||
'-Wall',
|
'-Wvla',
|
||||||
'-Wextra',
|
'-Wdouble-promotion',
|
||||||
|
|
||||||
'-fvisibility=hidden',
|
'-fvisibility=hidden',
|
||||||
|
|
||||||
@@ -53,13 +68,15 @@ test_cxxflags = test_common_flags + [
|
|||||||
'-Wcast-qual',
|
'-Wcast-qual',
|
||||||
'-Wwrite-strings',
|
'-Wwrite-strings',
|
||||||
'-Wsign-compare',
|
'-Wsign-compare',
|
||||||
|
'-Wcomma',
|
||||||
|
'-Wextra-semi',
|
||||||
|
'-Wheader-hygiene',
|
||||||
|
'-Winconsistent-missing-destructor-override',
|
||||||
|
'-Wunreachable-code-break',
|
||||||
|
'-Wunused',
|
||||||
|
'-Wused-but-marked-unused',
|
||||||
|
|
||||||
'-Wno-non-virtual-dtor',
|
'-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'
|
if compiler.get_id() == 'clang'
|
||||||
@@ -79,9 +96,18 @@ test_cflags = test_common_flags + [
|
|||||||
]
|
]
|
||||||
|
|
||||||
test_ldflags = [
|
test_ldflags = [
|
||||||
|
# make relocations read-only (hardening)
|
||||||
|
'-Wl,-z,relro',
|
||||||
|
|
||||||
|
# no lazy binding, please - not worth it for a daemon
|
||||||
|
'-Wl,-z,now',
|
||||||
]
|
]
|
||||||
|
|
||||||
if get_option('buildtype') != 'debug'
|
if get_option('buildtype') != 'debug'
|
||||||
|
test_cxxflags += [
|
||||||
|
'-ffunction-sections',
|
||||||
|
'-fdata-sections',
|
||||||
|
]
|
||||||
test_cflags += [
|
test_cflags += [
|
||||||
'-ffunction-sections',
|
'-ffunction-sections',
|
||||||
'-fdata-sections',
|
'-fdata-sections',
|
||||||
@@ -91,6 +117,13 @@ if get_option('buildtype') != 'debug'
|
|||||||
]
|
]
|
||||||
endif
|
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_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_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')
|
add_global_link_arguments(compiler.get_supported_link_arguments(test_ldflags), language: 'cpp')
|
||||||
@@ -126,13 +159,17 @@ add_global_arguments(common_cppflags, language: 'cpp')
|
|||||||
enable_daemon = not is_windows and not is_android and get_option('daemon')
|
enable_daemon = not is_windows and not is_android and get_option('daemon')
|
||||||
conf.set('ENABLE_DAEMON', enable_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_GETPWNAM_R', compiler.has_function('getpwnam_r'))
|
||||||
conf.set('HAVE_GETPWUID_R', compiler.has_function('getpwuid_r'))
|
conf.set('HAVE_GETPWUID_R', compiler.has_function('getpwuid_r'))
|
||||||
conf.set('HAVE_INITGROUPS', compiler.has_function('initgroups'))
|
conf.set('HAVE_INITGROUPS', compiler.has_function('initgroups'))
|
||||||
conf.set('HAVE_FNMATCH', compiler.has_function('fnmatch'))
|
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_STRCASESTR', compiler.has_function('strcasestr'))
|
||||||
|
|
||||||
conf.set('HAVE_PRCTL', is_linux)
|
conf.set('HAVE_PRCTL', is_linux)
|
||||||
@@ -178,10 +215,20 @@ 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.')
|
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
|
endif
|
||||||
|
|
||||||
|
log = static_library(
|
||||||
|
'log',
|
||||||
|
'src/Log.cxx',
|
||||||
|
'src/LogBackend.cxx',
|
||||||
|
include_directories: inc,
|
||||||
|
)
|
||||||
|
|
||||||
|
log_dep = declare_dependency(
|
||||||
|
link_with: log,
|
||||||
|
)
|
||||||
|
|
||||||
sources = [
|
sources = [
|
||||||
version_cxx,
|
version_cxx,
|
||||||
'src/Main.cxx',
|
'src/Main.cxx',
|
||||||
'src/protocol/Ack.cxx',
|
|
||||||
'src/protocol/ArgParser.cxx',
|
'src/protocol/ArgParser.cxx',
|
||||||
'src/protocol/Result.cxx',
|
'src/protocol/Result.cxx',
|
||||||
'src/command/CommandError.cxx',
|
'src/command/CommandError.cxx',
|
||||||
@@ -206,23 +253,23 @@ sources = [
|
|||||||
'src/decoder/DecoderPrint.cxx',
|
'src/decoder/DecoderPrint.cxx',
|
||||||
'src/client/Listener.cxx',
|
'src/client/Listener.cxx',
|
||||||
'src/client/Client.cxx',
|
'src/client/Client.cxx',
|
||||||
'src/client/ClientEvent.cxx',
|
'src/client/Config.cxx',
|
||||||
'src/client/ClientExpire.cxx',
|
'src/client/Domain.cxx',
|
||||||
'src/client/ClientGlobal.cxx',
|
'src/client/Event.cxx',
|
||||||
'src/client/ClientIdle.cxx',
|
'src/client/Expire.cxx',
|
||||||
'src/client/ClientList.cxx',
|
'src/client/Idle.cxx',
|
||||||
'src/client/ClientNew.cxx',
|
'src/client/List.cxx',
|
||||||
'src/client/ClientProcess.cxx',
|
'src/client/New.cxx',
|
||||||
'src/client/ClientRead.cxx',
|
'src/client/Process.cxx',
|
||||||
'src/client/ClientWrite.cxx',
|
'src/client/Read.cxx',
|
||||||
'src/client/ClientMessage.cxx',
|
'src/client/Write.cxx',
|
||||||
'src/client/ClientSubscribe.cxx',
|
'src/client/Message.cxx',
|
||||||
'src/client/ClientFile.cxx',
|
'src/client/Subscribe.cxx',
|
||||||
|
'src/client/File.cxx',
|
||||||
'src/client/Response.cxx',
|
'src/client/Response.cxx',
|
||||||
|
'src/client/ThreadBackgroundCommand.cxx',
|
||||||
'src/Listen.cxx',
|
'src/Listen.cxx',
|
||||||
'src/LogInit.cxx',
|
'src/LogInit.cxx',
|
||||||
'src/LogBackend.cxx',
|
|
||||||
'src/Log.cxx',
|
|
||||||
'src/ls.cxx',
|
'src/ls.cxx',
|
||||||
'src/Instance.cxx',
|
'src/Instance.cxx',
|
||||||
'src/win32/Win32Main.cxx',
|
'src/win32/Win32Main.cxx',
|
||||||
@@ -267,6 +314,7 @@ sources = [
|
|||||||
'src/TagSave.cxx',
|
'src/TagSave.cxx',
|
||||||
'src/TagFile.cxx',
|
'src/TagFile.cxx',
|
||||||
'src/TagStream.cxx',
|
'src/TagStream.cxx',
|
||||||
|
'src/TagAny.cxx',
|
||||||
'src/TimePrint.cxx',
|
'src/TimePrint.cxx',
|
||||||
'src/mixer/Volume.cxx',
|
'src/mixer/Volume.cxx',
|
||||||
'src/PlaylistFile.cxx',
|
'src/PlaylistFile.cxx',
|
||||||
@@ -280,6 +328,7 @@ if not is_android
|
|||||||
else
|
else
|
||||||
sources += [
|
sources += [
|
||||||
'src/android/Context.cxx',
|
'src/android/Context.cxx',
|
||||||
|
'src/android/AudioManager.cxx',
|
||||||
'src/android/Environment.cxx',
|
'src/android/Environment.cxx',
|
||||||
'src/android/LogListener.cxx',
|
'src/android/LogListener.cxx',
|
||||||
]
|
]
|
||||||
@@ -298,16 +347,23 @@ if enable_database
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
subdir('src/util')
|
subdir('src/util')
|
||||||
|
subdir('src/time')
|
||||||
|
subdir('src/io')
|
||||||
|
subdir('src/io/uring')
|
||||||
subdir('src/system')
|
subdir('src/system')
|
||||||
subdir('src/thread')
|
subdir('src/thread')
|
||||||
|
subdir('src/net')
|
||||||
subdir('src/event')
|
subdir('src/event')
|
||||||
|
|
||||||
|
subdir('src/apple')
|
||||||
|
|
||||||
subdir('src/lib/dbus')
|
subdir('src/lib/dbus')
|
||||||
subdir('src/lib/icu')
|
subdir('src/lib/icu')
|
||||||
subdir('src/lib/smbclient')
|
subdir('src/lib/smbclient')
|
||||||
subdir('src/lib/zlib')
|
subdir('src/lib/zlib')
|
||||||
|
|
||||||
subdir('src/lib/alsa')
|
subdir('src/lib/alsa')
|
||||||
|
subdir('src/lib/chromaprint')
|
||||||
subdir('src/lib/curl')
|
subdir('src/lib/curl')
|
||||||
subdir('src/lib/expat')
|
subdir('src/lib/expat')
|
||||||
subdir('src/lib/ffmpeg')
|
subdir('src/lib/ffmpeg')
|
||||||
@@ -322,9 +378,10 @@ subdir('src/lib/systemd')
|
|||||||
subdir('src/lib/upnp')
|
subdir('src/lib/upnp')
|
||||||
subdir('src/lib/yajl')
|
subdir('src/lib/yajl')
|
||||||
|
|
||||||
|
subdir('src/lib/crypto')
|
||||||
|
|
||||||
subdir('src/fs')
|
subdir('src/fs')
|
||||||
subdir('src/config')
|
subdir('src/config')
|
||||||
subdir('src/net')
|
|
||||||
subdir('src/tag')
|
subdir('src/tag')
|
||||||
subdir('src/pcm')
|
subdir('src/pcm')
|
||||||
subdir('src/neighbor')
|
subdir('src/neighbor')
|
||||||
@@ -347,12 +404,19 @@ endif
|
|||||||
if sqlite_dep.found()
|
if sqlite_dep.found()
|
||||||
sources += [
|
sources += [
|
||||||
'src/command/StickerCommands.cxx',
|
'src/command/StickerCommands.cxx',
|
||||||
'src/sticker/StickerDatabase.cxx',
|
'src/sticker/Database.cxx',
|
||||||
'src/sticker/StickerPrint.cxx',
|
'src/sticker/Print.cxx',
|
||||||
'src/sticker/SongSticker.cxx',
|
'src/sticker/SongSticker.cxx',
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if chromaprint_dep.found()
|
||||||
|
sources += [
|
||||||
|
'src/command/FingerprintCommands.cxx',
|
||||||
|
'src/lib/chromaprint/DecoderClient.cxx',
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
|
||||||
basic = static_library(
|
basic = static_library(
|
||||||
'basic',
|
'basic',
|
||||||
'src/ReplayGainInfo.cxx',
|
'src/ReplayGainInfo.cxx',
|
||||||
@@ -367,8 +431,10 @@ basic_dep = declare_dependency(
|
|||||||
|
|
||||||
if enable_database
|
if enable_database
|
||||||
subdir('src/storage')
|
subdir('src/storage')
|
||||||
subdir('src/db')
|
else
|
||||||
|
storage_glue_dep = dependency('', required: false)
|
||||||
endif
|
endif
|
||||||
|
subdir('src/db')
|
||||||
|
|
||||||
if neighbor_glue_dep.found()
|
if neighbor_glue_dep.found()
|
||||||
sources += 'src/command/NeighborCommands.cxx'
|
sources += 'src/command/NeighborCommands.cxx'
|
||||||
@@ -377,8 +443,11 @@ endif
|
|||||||
if archive_glue_dep.found()
|
if archive_glue_dep.found()
|
||||||
sources += [
|
sources += [
|
||||||
'src/TagArchive.cxx',
|
'src/TagArchive.cxx',
|
||||||
'src/db/update/Archive.cxx',
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if enable_database
|
||||||
|
sources += ['src/db/update/Archive.cxx']
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if is_windows
|
if is_windows
|
||||||
@@ -390,6 +459,7 @@ more_deps = []
|
|||||||
if is_android
|
if is_android
|
||||||
subdir('src/java')
|
subdir('src/java')
|
||||||
target_type = 'shared_library'
|
target_type = 'shared_library'
|
||||||
|
target_name = 'mpd'
|
||||||
link_args += [
|
link_args += [
|
||||||
'-Wl,--no-undefined,-shared,-Bsymbolic',
|
'-Wl,--no-undefined,-shared,-Bsymbolic',
|
||||||
'-llog',
|
'-llog',
|
||||||
@@ -399,12 +469,20 @@ if is_android
|
|||||||
declare_dependency(sources: [classes_jar]),
|
declare_dependency(sources: [classes_jar]),
|
||||||
java_dep,
|
java_dep,
|
||||||
]
|
]
|
||||||
|
elif is_haiku
|
||||||
|
target_type = 'executable'
|
||||||
|
target_name = 'mpd.nores'
|
||||||
|
link_args += [
|
||||||
|
'-lnetwork',
|
||||||
|
'-lbe',
|
||||||
|
]
|
||||||
else
|
else
|
||||||
target_type = 'executable'
|
target_type = 'executable'
|
||||||
|
target_name = 'mpd'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
mpd = build_target(
|
mpd = build_target(
|
||||||
'mpd',
|
target_name,
|
||||||
sources,
|
sources,
|
||||||
target_type: target_type,
|
target_type: target_type,
|
||||||
include_directories: inc,
|
include_directories: inc,
|
||||||
@@ -432,8 +510,10 @@ mpd = build_target(
|
|||||||
sqlite_dep,
|
sqlite_dep,
|
||||||
zeroconf_dep,
|
zeroconf_dep,
|
||||||
more_deps,
|
more_deps,
|
||||||
|
chromaprint_dep,
|
||||||
],
|
],
|
||||||
link_args: link_args,
|
link_args: link_args,
|
||||||
|
build_by_default: not get_option('fuzzer'),
|
||||||
install: not is_android and not is_haiku,
|
install: not is_android and not is_haiku,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -443,6 +523,14 @@ endif
|
|||||||
|
|
||||||
if is_haiku
|
if is_haiku
|
||||||
subdir('src/haiku')
|
subdir('src/haiku')
|
||||||
|
custom_target(
|
||||||
|
'mpd',
|
||||||
|
output: 'mpd',
|
||||||
|
input: [mpd, rsrc],
|
||||||
|
command: [addres, '@OUTPUT@', '@INPUT0@', '@INPUT1@'],
|
||||||
|
install: true,
|
||||||
|
install_dir: get_option('bindir'),
|
||||||
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
configure_file(output: 'config.h', configuration: conf)
|
configure_file(output: 'config.h', configuration: conf)
|
||||||
@@ -461,10 +549,12 @@ install_data(
|
|||||||
install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()),
|
install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()),
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_option('documentation')
|
subdir('doc')
|
||||||
subdir('doc')
|
|
||||||
endif
|
|
||||||
|
|
||||||
if get_option('test')
|
if get_option('test')
|
||||||
subdir('test')
|
subdir('test')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('fuzzer')
|
||||||
|
subdir('test/fuzzer')
|
||||||
|
endif
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
option('documentation', type: 'boolean', value: false, description: 'Build documentation')
|
option('documentation', type: 'feature', description: 'Build documentation')
|
||||||
|
option('html_manual', type: 'boolean', value: true, description: 'Build the HTML manual')
|
||||||
option('test', type: 'boolean', value: false, description: 'Build the unit tests and debug programs')
|
option('manpages', type: 'boolean', value: true, description: 'Build manual pages')
|
||||||
|
|
||||||
option('syslog', type: 'feature', description: 'syslog support')
|
option('syslog', type: 'feature', description: 'syslog support')
|
||||||
option('inotify', type: 'boolean', value: true, description: 'inotify support (for automatic database update)')
|
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('daemon', type: 'boolean', value: true, description: 'enable daemonization')
|
||||||
option('systemd', type: 'feature', description: 'systemd support')
|
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_system_unit_dir', type: 'string', description: 'systemd system service directory')
|
||||||
option('systemd_user_unit_dir', type: 'string', description: 'systemd user 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
|
# Android
|
||||||
#
|
#
|
||||||
@@ -84,7 +92,11 @@ option('cdio_paranoia', type: 'feature', description: 'libcdio_paranoia input pl
|
|||||||
option('curl', type: 'feature', description: 'HTTP client using CURL')
|
option('curl', type: 'feature', description: 'HTTP client using CURL')
|
||||||
option('mms', type: 'feature', description: 'MMS protocol support using libmms')
|
option('mms', type: 'feature', description: 'MMS protocol support using libmms')
|
||||||
option('nfs', type: 'feature', description: 'NFS protocol support using libnfs')
|
option('nfs', type: 'feature', description: 'NFS protocol support using libnfs')
|
||||||
option('smbclient', type: 'feature', description: 'SMB support using libsmbclient')
|
|
||||||
|
# The "smbclient" plugin is disabled by default because libsmbclient
|
||||||
|
# has a serious bug which crashes MPD very quickly:
|
||||||
|
# https://bugzilla.samba.org/show_bug.cgi?id=11413
|
||||||
|
option('smbclient', type: 'feature', value: 'disabled', description: 'SMB support using libsmbclient')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Commercial services
|
# Commercial services
|
||||||
|
|||||||
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,19 +4,20 @@ from os.path import abspath
|
|||||||
from build.project import Project
|
from build.project import Project
|
||||||
from build.zlib import ZlibProject
|
from build.zlib import ZlibProject
|
||||||
from build.meson import MesonProject
|
from build.meson import MesonProject
|
||||||
|
from build.cmake import CmakeProject
|
||||||
from build.autotools import AutotoolsProject
|
from build.autotools import AutotoolsProject
|
||||||
from build.ffmpeg import FfmpegProject
|
from build.ffmpeg import FfmpegProject
|
||||||
from build.boost import BoostProject
|
from build.boost import BoostProject
|
||||||
|
|
||||||
libmpdclient = MesonProject(
|
libmpdclient = MesonProject(
|
||||||
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.16.tar.xz',
|
'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.19.tar.xz',
|
||||||
'fa6bdab67c0e0490302b38f00c27b4959735c3ec8aef7a88327adb1407654464',
|
'158aad4c2278ab08e76a3f2b0166c99b39fae00ee17231bd225c5a36e977a189',
|
||||||
'lib/libmpdclient.a',
|
'lib/libmpdclient.a',
|
||||||
)
|
)
|
||||||
|
|
||||||
libogg = AutotoolsProject(
|
libogg = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz',
|
'http://downloads.xiph.org/releases/ogg/libogg-1.3.4.tar.xz',
|
||||||
'4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08',
|
'c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe',
|
||||||
'lib/libogg.a',
|
'lib/libogg.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -24,8 +25,8 @@ libogg = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
libvorbis = AutotoolsProject(
|
libvorbis = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.xz',
|
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz',
|
||||||
'af00bb5a784e7c9e69f56823de4637c350643deedaf333d0fa86ecdba6fcb415',
|
'b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b',
|
||||||
'lib/libvorbis.a',
|
'lib/libvorbis.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -38,8 +39,8 @@ libvorbis = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
opus = AutotoolsProject(
|
opus = AutotoolsProject(
|
||||||
'https://archive.mozilla.org/pub/opus/opus-1.3.tar.gz',
|
'https://archive.mozilla.org/pub/opus/opus-1.3.1.tar.gz',
|
||||||
'4f3d69aefdf2dbaf9825408e452a8a414ffc60494c70633560700398820dc550',
|
'65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d',
|
||||||
'lib/libopus.a',
|
'lib/libopus.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -52,8 +53,8 @@ opus = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
flac = AutotoolsProject(
|
flac = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/flac/flac-1.3.2.tar.xz',
|
'http://downloads.xiph.org/releases/flac/flac-1.3.3.tar.xz',
|
||||||
'91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f',
|
'213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748',
|
||||||
'lib/libFLAC.a',
|
'lib/libFLAC.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--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(
|
ffmpeg = FfmpegProject(
|
||||||
'http://ffmpeg.org/releases/ffmpeg-4.1.1.tar.xz',
|
'http://ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz',
|
||||||
'373749824dfd334d84e55dff406729edfd1606575ee44dd485d97d45ea4d2d86',
|
'ad009240d46e307b4e03a213a0f49c11b650e445b1f8be0dda2a9212b34d2ffb',
|
||||||
'lib/libavcodec.a',
|
'lib/libavcodec.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -341,8 +377,8 @@ ffmpeg = FfmpegProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
curl = AutotoolsProject(
|
curl = AutotoolsProject(
|
||||||
'http://curl.haxx.se/download/curl-7.64.0.tar.xz',
|
'http://curl.haxx.se/download/curl-7.73.0.tar.xz',
|
||||||
'2f2f13fa34d44aa29cb444077ad7dc4dc6d189584ad552e0aaeb06e608af6001',
|
'7c4c7ca4ea88abe00fea4740dcf81075c031b1d0bb23aff2d5efde20a3c2408a',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -358,6 +394,11 @@ curl = AutotoolsProject(
|
|||||||
'--disable-manual',
|
'--disable-manual',
|
||||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||||
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
||||||
|
'--disable-doh',
|
||||||
|
'--disable-mime',
|
||||||
|
'--disable-netrc',
|
||||||
|
'--disable-progress-meter',
|
||||||
|
'--disable-alt-svc',
|
||||||
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -365,8 +406,8 @@ curl = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
libexpat = AutotoolsProject(
|
libexpat = AutotoolsProject(
|
||||||
'https://github.com/libexpat/libexpat/releases/download/R_2_2_6/expat-2.2.6.tar.bz2',
|
'https://github.com/libexpat/libexpat/releases/download/R_2_2_9/expat-2.2.9.tar.bz2',
|
||||||
'17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2',
|
'f1063084dc4302a427dabcca499c8312b3a32a29b7d2506653ecc8f950a9a237',
|
||||||
'lib/libexpat.a',
|
'lib/libexpat.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -375,8 +416,8 @@ libexpat = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
libnfs = AutotoolsProject(
|
libnfs = AutotoolsProject(
|
||||||
'https://github.com/sahlberg/libnfs/archive/libnfs-3.0.0.tar.gz',
|
'https://github.com/sahlberg/libnfs/archive/libnfs-4.0.0.tar.gz',
|
||||||
'445d92c5fc55e4a5b115e358e60486cf8f87ee50e0103d46a02e7fb4618566a5',
|
'6ee77e9fe220e2d3e3b1f53cfea04fb319828cc7dbb97dd9df09e46e901d797d',
|
||||||
'lib/libnfs.a',
|
'lib/libnfs.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -387,12 +428,13 @@ libnfs = AutotoolsProject(
|
|||||||
|
|
||||||
'--disable-utils', '--disable-examples',
|
'--disable-utils', '--disable-examples',
|
||||||
],
|
],
|
||||||
base='libnfs-libnfs-3.0.0',
|
base='libnfs-libnfs-4.0.0',
|
||||||
|
patches='src/lib/nfs/patches',
|
||||||
autoreconf=True,
|
autoreconf=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
boost = BoostProject(
|
boost = BoostProject(
|
||||||
'http://downloads.sourceforge.net/project/boost/boost/1.69.0/boost_1_69_0.tar.bz2',
|
'https://dl.bintray.com/boostorg/release/1.74.0/source/boost_1_74_0.tar.bz2',
|
||||||
'8f32d4617390d1c2d16f26a27ab60d97807b35440d45891fa340fc2648b04406',
|
'83bfc1507731a0906e387fc28b7ef5417d591429e51e788417fe9ff025e116b1',
|
||||||
'include/boost/version.hpp',
|
'include/boost/version.hpp',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -91,7 +91,12 @@ def configure(toolchain, src, build, args=()):
|
|||||||
'--cross-file', cross_file,
|
'--cross-file', cross_file,
|
||||||
] + args
|
] + 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):
|
class MesonProject(Project):
|
||||||
def __init__(self, url, md5, installed, configure_args=[],
|
def __init__(self, url, md5, installed, configure_args=[],
|
||||||
|
|||||||
@@ -7,5 +7,11 @@ def untar(tarball_path, parent_path, base):
|
|||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
pass
|
pass
|
||||||
os.makedirs(parent_path, exist_ok=True)
|
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
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -95,7 +95,7 @@ public:
|
|||||||
|
|
||||||
constexpr double ToDoubleS() const {
|
constexpr double ToDoubleS() const {
|
||||||
return double(count()) / 1000.;
|
return double(count()) / 1000.;
|
||||||
};
|
}
|
||||||
|
|
||||||
constexpr bool IsZero() const {
|
constexpr bool IsZero() const {
|
||||||
return count() == 0;
|
return count() == 0;
|
||||||
@@ -199,7 +199,7 @@ public:
|
|||||||
|
|
||||||
constexpr double ToDoubleS() const {
|
constexpr double ToDoubleS() const {
|
||||||
return double(count()) / 1000.;
|
return double(count()) / 1000.;
|
||||||
};
|
}
|
||||||
|
|
||||||
constexpr bool IsZero() const {
|
constexpr bool IsZero() const {
|
||||||
return count() == 0;
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -33,15 +33,19 @@
|
|||||||
#include "playlist/PlaylistRegistry.hxx"
|
#include "playlist/PlaylistRegistry.hxx"
|
||||||
#include "playlist/PlaylistPlugin.hxx"
|
#include "playlist/PlaylistPlugin.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
|
#include "fs/NarrowPath.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/StandardDirectory.hxx"
|
#include "fs/StandardDirectory.hxx"
|
||||||
#include "system/Error.hxx"
|
#include "io/uring/Features.h"
|
||||||
#include "util/Macros.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/OptionDef.hxx"
|
#include "util/OptionDef.hxx"
|
||||||
#include "util/OptionParser.hxx"
|
#include "util/OptionParser.hxx"
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "system/Error.hxx"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
#include "db/Registry.hxx"
|
#include "db/Registry.hxx"
|
||||||
@@ -55,6 +59,7 @@
|
|||||||
#include "neighbor/NeighborPlugin.hxx"
|
#include "neighbor/NeighborPlugin.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "encoder/Features.h"
|
||||||
#ifdef ENABLE_ENCODER
|
#ifdef ENABLE_ENCODER
|
||||||
#include "encoder/EncoderList.hxx"
|
#include "encoder/EncoderList.hxx"
|
||||||
#include "encoder/EncoderPlugin.hxx"
|
#include "encoder/EncoderPlugin.hxx"
|
||||||
@@ -65,9 +70,6 @@
|
|||||||
#include "archive/ArchivePlugin.hxx"
|
#include "archive/ArchivePlugin.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
constexpr auto CONFIG_FILE_LOCATION = Path::FromFS(PATH_LITERAL("mpd\\mpd.conf"));
|
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_LOCATION2 = Path::FromFS(PATH_LITERAL(".mpd/mpd.conf"));
|
||||||
constexpr auto USER_CONFIG_FILE_LOCATION_XDG = Path::FromFS(PATH_LITERAL("mpd/mpd.conf"));
|
constexpr auto USER_CONFIG_FILE_LOCATION_XDG = Path::FromFS(PATH_LITERAL("mpd/mpd.conf"));
|
||||||
#endif
|
#endif
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
enum Option {
|
enum Option {
|
||||||
OPTION_KILL,
|
OPTION_KILL,
|
||||||
@@ -105,20 +107,20 @@ static constexpr OptionDef option_defs[] = {
|
|||||||
|
|
||||||
static constexpr Domain cmdline_domain("cmdline");
|
static constexpr Domain cmdline_domain("cmdline");
|
||||||
|
|
||||||
gcc_noreturn
|
[[noreturn]]
|
||||||
static void version(void)
|
static void version()
|
||||||
{
|
{
|
||||||
printf("Music Player Daemon " VERSION " (%s)\n"
|
printf("Music Player Daemon " VERSION " (%s)"
|
||||||
"\n"
|
"\n"
|
||||||
"Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
"Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||||
"Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com>\n"
|
"Copyright 2008-2018 Max Kellermann <max.kellermann@gmail.com>\n"
|
||||||
"This is free software; see the source for copying conditions. There is NO\n"
|
"This is free software; see the source for copying conditions. There is NO\n"
|
||||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
|
||||||
|
GIT_VERSION);
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
"\n"
|
printf("\n"
|
||||||
"Database plugins:\n",
|
"Database plugins:\n");
|
||||||
GIT_VERSION);
|
|
||||||
|
|
||||||
for (auto i = database_plugins; *i != nullptr; ++i)
|
for (auto i = database_plugins; *i != nullptr; ++i)
|
||||||
printf(" %s", (*i)->name);
|
printf(" %s", (*i)->name);
|
||||||
@@ -129,31 +131,35 @@ static void version(void)
|
|||||||
for (auto i = storage_plugins; *i != nullptr; ++i)
|
for (auto i = storage_plugins; *i != nullptr; ++i)
|
||||||
printf(" %s", (*i)->name);
|
printf(" %s", (*i)->name);
|
||||||
|
|
||||||
printf("\n"
|
printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
"\n"
|
printf("\n"
|
||||||
"Neighbor plugins:\n");
|
"Neighbor plugins:\n");
|
||||||
for (auto i = neighbor_plugins; *i != nullptr; ++i)
|
for (auto i = neighbor_plugins; *i != nullptr; ++i)
|
||||||
printf(" %s", (*i)->name);
|
printf(" %s", (*i)->name);
|
||||||
|
|
||||||
printf("\n"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
printf("\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Decoders plugins:\n");
|
"Decoders plugins:\n");
|
||||||
|
|
||||||
decoder_plugins_for_each([](const DecoderPlugin &plugin){
|
decoder_plugins_for_each([](const DecoderPlugin &plugin){
|
||||||
printf(" [%s]", plugin.name);
|
printf(" [%s]", plugin.name);
|
||||||
|
|
||||||
const char *const*suffixes = plugin.suffixes;
|
const char *const*suffixes = plugin.suffixes;
|
||||||
if (suffixes != nullptr)
|
if (suffixes != nullptr)
|
||||||
for (; *suffixes != nullptr; ++suffixes)
|
for (; *suffixes != nullptr; ++suffixes)
|
||||||
printf(" %s", *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"
|
printf("\n"
|
||||||
"Filters:\n"
|
"Filters:\n"
|
||||||
@@ -202,6 +208,9 @@ static void version(void)
|
|||||||
"\n"
|
"\n"
|
||||||
"Input plugins:\n"
|
"Input plugins:\n"
|
||||||
" file"
|
" file"
|
||||||
|
#ifdef HAVE_URING
|
||||||
|
" io_uring"
|
||||||
|
#endif
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
" archive"
|
" archive"
|
||||||
#endif
|
#endif
|
||||||
@@ -255,7 +264,7 @@ static void version(void)
|
|||||||
#endif
|
#endif
|
||||||
"\n");
|
"\n");
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
std::exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintOption(const OptionDef &opt)
|
static void PrintOption(const OptionDef &opt)
|
||||||
@@ -271,8 +280,8 @@ static void PrintOption(const OptionDef &opt)
|
|||||||
opt.GetDescription());
|
opt.GetDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_noreturn
|
[[noreturn]]
|
||||||
static void help(void)
|
static void help()
|
||||||
{
|
{
|
||||||
printf("Usage:\n"
|
printf("Usage:\n"
|
||||||
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
||||||
@@ -282,10 +291,10 @@ static void help(void)
|
|||||||
"Options:\n");
|
"Options:\n");
|
||||||
|
|
||||||
for (const auto &i : option_defs)
|
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);
|
PrintOption(i);
|
||||||
|
|
||||||
exit(EXIT_SUCCESS);
|
std::exit(EXIT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConfigLoader
|
class ConfigLoader
|
||||||
@@ -296,7 +305,7 @@ public:
|
|||||||
explicit ConfigLoader(ConfigData &_config) noexcept
|
explicit ConfigLoader(ConfigData &_config) noexcept
|
||||||
:config(_config) {}
|
:config(_config) {}
|
||||||
|
|
||||||
bool TryFile(const Path path);
|
bool TryFile(Path path);
|
||||||
bool TryFile(const AllocatedPath &base_path, Path path);
|
bool TryFile(const AllocatedPath &base_path, Path path);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,17 +389,7 @@ ParseCommandLine(int argc, char **argv, struct options &options,
|
|||||||
|
|
||||||
if (config_file != nullptr) {
|
if (config_file != nullptr) {
|
||||||
/* use specified configuration file */
|
/* use specified configuration file */
|
||||||
#ifdef _UNICODE
|
ReadConfigFile(config, FromNarrowPath(config_file));
|
||||||
wchar_t buffer[MAX_PATH];
|
|
||||||
auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
|
|
||||||
buffer, ARRAY_SIZE(buffer));
|
|
||||||
if (result <= 0)
|
|
||||||
throw MakeLastError("MultiByteToWideChar() failed");
|
|
||||||
|
|
||||||
ReadConfigFile(config, Path::FromFS(buffer));
|
|
||||||
#else
|
|
||||||
ReadConfigFile(config, Path::FromFS(config_file));
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2018 The Music Player Daemon Project
|
* Copyright 2003-2020 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -19,4 +19,4 @@
|
|||||||
|
|
||||||
#include "GitVersion.hxx"
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,6 +20,6 @@
|
|||||||
#ifndef MPD_GIT_VERSION_HXX
|
#ifndef MPD_GIT_VERSION_HXX
|
||||||
#define MPD_GIT_VERSION_HXX
|
#define MPD_GIT_VERSION_HXX
|
||||||
|
|
||||||
extern char GIT_VERSION[];
|
extern const char GIT_VERSION[];
|
||||||
|
|
||||||
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -18,16 +18,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "IcyMetaDataParser.hxx"
|
#include "IcyMetaDataParser.hxx"
|
||||||
#include "tag/Tag.hxx"
|
|
||||||
#include "tag/Builder.hxx"
|
#include "tag/Builder.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/AllocatedString.hxx"
|
||||||
#include "util/StringView.hxx"
|
#include "util/StringView.hxx"
|
||||||
#include "Log.hxx"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include <string.h>
|
#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
|
void
|
||||||
IcyMetaDataParser::Reset() noexcept
|
IcyMetaDataParser::Reset() noexcept
|
||||||
@@ -65,29 +73,40 @@ IcyMetaDataParser::Data(size_t length) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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 (value.size >= 2 && value.front() == '\'' && value.back() == '\'') {
|
||||||
|
|
||||||
if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') {
|
|
||||||
/* strip the single quotes */
|
/* strip the single quotes */
|
||||||
++value;
|
++value.data;
|
||||||
length -= 2;
|
value.size -= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length > 0)
|
if (value.size > 0)
|
||||||
tag.AddItem(type, {value, length});
|
tag.AddItem(type, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
icy_parse_tag_item(TagBuilder &tag,
|
icy_parse_tag_item(TagBuilder &tag,
|
||||||
|
#ifdef HAVE_ICU_CONVERTER
|
||||||
|
const IcuConverter *icu_converter,
|
||||||
|
#endif
|
||||||
const char *name, const char *value) noexcept
|
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);
|
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>
|
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(p != nullptr);
|
||||||
assert(end != nullptr);
|
assert(end != nullptr);
|
||||||
@@ -153,7 +176,11 @@ icy_parse_tag(char *p, char *const end) noexcept
|
|||||||
*quote = 0;
|
*quote = 0;
|
||||||
p = quote + 1;
|
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, ';');
|
char *semicolon = std::find(p, end, ';');
|
||||||
if (semicolon == end)
|
if (semicolon == end)
|
||||||
@@ -167,7 +194,7 @@ icy_parse_tag(char *p, char *const end) noexcept
|
|||||||
size_t
|
size_t
|
||||||
IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
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(IsDefined());
|
||||||
assert(data_rest == 0);
|
assert(data_rest == 0);
|
||||||
@@ -208,7 +235,11 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
|||||||
if (meta_position == meta_size) {
|
if (meta_position == meta_size) {
|
||||||
/* parse */
|
/* 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;
|
delete[] meta_data;
|
||||||
|
|
||||||
/* change back to normal data mode */
|
/* change back to normal data mode */
|
||||||
@@ -223,7 +254,7 @@ IcyMetaDataParser::Meta(const void *data, size_t length) noexcept
|
|||||||
size_t
|
size_t
|
||||||
IcyMetaDataParser::ParseInPlace(void *data, size_t length) noexcept
|
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;
|
uint8_t *dest = dest0;
|
||||||
const uint8_t *src = 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,18 +20,23 @@
|
|||||||
#ifndef MPD_ICY_META_DATA_PARSER_HXX
|
#ifndef MPD_ICY_META_DATA_PARSER_HXX
|
||||||
#define MPD_ICY_META_DATA_PARSER_HXX
|
#define MPD_ICY_META_DATA_PARSER_HXX
|
||||||
|
|
||||||
|
#include "lib/icu/Converter.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
class IcyMetaDataParser {
|
class IcyMetaDataParser {
|
||||||
size_t data_size = 0, data_rest;
|
size_t data_size = 0, data_rest;
|
||||||
|
|
||||||
size_t meta_size, meta_position;
|
size_t meta_size, meta_position;
|
||||||
char *meta_data;
|
char *meta_data;
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU_CONVERTER
|
||||||
|
std::unique_ptr<IcuConverter> icu_converter;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::unique_ptr<Tag> tag;
|
std::unique_ptr<Tag> tag;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -39,6 +44,13 @@ public:
|
|||||||
Reset();
|
Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ICU_CONVERTER
|
||||||
|
/**
|
||||||
|
* Throws on error.
|
||||||
|
*/
|
||||||
|
void SetCharset(const char *charset);
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize an enabled icy_metadata object with the specified
|
* Initialize an enabled icy_metadata object with the specified
|
||||||
* data_size (from the icy-metaint HTTP response header).
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -26,12 +26,12 @@
|
|||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
void
|
void
|
||||||
idle_add(unsigned flags)
|
idle_add(unsigned flags)
|
||||||
{
|
{
|
||||||
assert(flags != 0);
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
#include "IdleFlags.hxx"
|
#include "IdleFlags.hxx"
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
static const char *const idle_names[] = {
|
static const char *const idle_names[] = {
|
||||||
"database",
|
"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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,12 +20,15 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Idle.hxx"
|
#include "IdleFlags.hxx"
|
||||||
|
#include "StateFile.hxx"
|
||||||
#include "Stats.hxx"
|
#include "Stats.hxx"
|
||||||
|
#include "client/List.hxx"
|
||||||
|
#include "input/cache/Manager.hxx"
|
||||||
|
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
#include "RemoteTagCache.hxx"
|
#include "RemoteTagCache.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@@ -34,14 +37,16 @@
|
|||||||
#include "db/update/Service.hxx"
|
#include "db/update/Service.hxx"
|
||||||
#include "storage/StorageInterface.hxx"
|
#include "storage/StorageInterface.hxx"
|
||||||
|
|
||||||
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
|
#include "neighbor/Glue.hxx"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
#include "sticker/StickerDatabase.hxx"
|
#include "sticker/Database.hxx"
|
||||||
#include "sticker/SongSticker.hxx"
|
#include "sticker/SongSticker.hxx"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
Instance::Instance()
|
Instance::Instance()
|
||||||
:rtio_thread(true),
|
:rtio_thread(true),
|
||||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||||
@@ -65,6 +70,13 @@ Instance::~Instance() noexcept
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Instance::OnStateModified() noexcept
|
||||||
|
{
|
||||||
|
if (state_file)
|
||||||
|
state_file->CheckModified();
|
||||||
|
}
|
||||||
|
|
||||||
Partition *
|
Partition *
|
||||||
Instance::FindPartition(const char *name) noexcept
|
Instance::FindPartition(const char *name) noexcept
|
||||||
{
|
{
|
||||||
@@ -75,6 +87,20 @@ Instance::FindPartition(const char *name) noexcept
|
|||||||
return nullptr;
|
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
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
const Database &
|
const Database &
|
||||||
@@ -88,7 +114,7 @@ Instance::GetDatabaseOrThrow() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Instance::OnDatabaseModified()
|
Instance::OnDatabaseModified() noexcept
|
||||||
{
|
{
|
||||||
assert(database != nullptr);
|
assert(database != nullptr);
|
||||||
|
|
||||||
@@ -101,15 +127,15 @@ Instance::OnDatabaseModified()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Instance::OnDatabaseSongRemoved(const char *uri)
|
Instance::OnDatabaseSongRemoved(const char *uri) noexcept
|
||||||
{
|
{
|
||||||
assert(database != nullptr);
|
assert(database != nullptr);
|
||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
/* if the song has a sticker, remove it */
|
/* if the song has a sticker, remove it */
|
||||||
if (sticker_enabled()) {
|
if (HasStickerDatabase()) {
|
||||||
try {
|
try {
|
||||||
sticker_song_delete(uri);
|
sticker_song_delete(*sticker_database, uri);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,17 +150,15 @@ Instance::OnDatabaseSongRemoved(const char *uri)
|
|||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
|
|
||||||
void
|
void
|
||||||
Instance::FoundNeighbor(gcc_unused const NeighborInfo &info) noexcept
|
Instance::FoundNeighbor([[maybe_unused]] const NeighborInfo &info) noexcept
|
||||||
{
|
{
|
||||||
for (auto &partition : partitions)
|
EmitIdle(IDLE_NEIGHBOR);
|
||||||
partition.EmitIdle(IDLE_NEIGHBOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Instance::LostNeighbor(gcc_unused const NeighborInfo &info) noexcept
|
Instance::LostNeighbor([[maybe_unused]] const NeighborInfo &info) noexcept
|
||||||
{
|
{
|
||||||
for (auto &partition : partitions)
|
EmitIdle(IDLE_NEIGHBOR);
|
||||||
partition.EmitIdle(IDLE_NEIGHBOR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -166,3 +190,18 @@ Instance::OnRemoteTag(const char *uri, const Tag &tag) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -53,6 +53,8 @@ class ClientList;
|
|||||||
struct Partition;
|
struct Partition;
|
||||||
class StateFile;
|
class StateFile;
|
||||||
class RemoteTagCache;
|
class RemoteTagCache;
|
||||||
|
class StickerDatabase;
|
||||||
|
class InputCacheManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A utility class which, when used as the first base class, ensures
|
* A utility class which, when used as the first base class, ensures
|
||||||
@@ -97,10 +99,16 @@ struct Instance final
|
|||||||
Systemd::Watchdog systemd_watchdog;
|
Systemd::Watchdog systemd_watchdog;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::unique_ptr<InputCacheManager> input_cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitor for global idle events to be broadcasted to all
|
||||||
|
* partitions.
|
||||||
|
*/
|
||||||
MaskMonitor idle_monitor;
|
MaskMonitor idle_monitor;
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
NeighborGlue *neighbors;
|
std::unique_ptr<NeighborGlue> neighbors;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@@ -119,11 +127,15 @@ struct Instance final
|
|||||||
std::unique_ptr<RemoteTagCache> remote_tag_cache;
|
std::unique_ptr<RemoteTagCache> remote_tag_cache;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ClientList *client_list;
|
std::unique_ptr<ClientList> client_list;
|
||||||
|
|
||||||
std::list<Partition> partitions;
|
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();
|
||||||
~Instance() noexcept;
|
~Instance() noexcept;
|
||||||
@@ -131,14 +143,27 @@ struct Instance final
|
|||||||
/**
|
/**
|
||||||
* Wrapper for EventLoop::Break(). Call to initiate shutdown.
|
* Wrapper for EventLoop::Break(). Call to initiate shutdown.
|
||||||
*/
|
*/
|
||||||
void Break() {
|
void Break() noexcept {
|
||||||
event_loop.Break();
|
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);
|
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
|
* Find a #Partition with the given name. Returns nullptr if
|
||||||
* no such partition was found.
|
* no such partition was found.
|
||||||
@@ -146,6 +171,8 @@ struct Instance final
|
|||||||
gcc_pure
|
gcc_pure
|
||||||
Partition *FindPartition(const char *name) noexcept;
|
Partition *FindPartition(const char *name) noexcept;
|
||||||
|
|
||||||
|
void DeletePartition(Partition &partition) noexcept;
|
||||||
|
|
||||||
void BeginShutdownPartitions() noexcept;
|
void BeginShutdownPartitions() noexcept;
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@@ -154,7 +181,7 @@ struct Instance final
|
|||||||
* if this MPD configuration has no database (no
|
* if this MPD configuration has no database (no
|
||||||
* music_directory was configured).
|
* music_directory was configured).
|
||||||
*/
|
*/
|
||||||
Database *GetDatabase() {
|
Database *GetDatabase() noexcept {
|
||||||
return database.get();
|
return database.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,6 +193,12 @@ struct Instance final
|
|||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SQLITE
|
||||||
|
bool HasStickerDatabase() noexcept {
|
||||||
|
return sticker_database != nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void BeginShutdownUpdate() noexcept;
|
void BeginShutdownUpdate() noexcept;
|
||||||
|
|
||||||
#ifdef ENABLE_CURL
|
#ifdef ENABLE_CURL
|
||||||
@@ -176,10 +209,13 @@ struct Instance final
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void FlushCaches() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
void OnDatabaseModified() override;
|
/* virtual methods from class DatabaseListener */
|
||||||
void OnDatabaseSongRemoved(const char *uri) override;
|
void OnDatabaseModified() noexcept override;
|
||||||
|
void OnDatabaseSongRemoved(const char *uri) noexcept override;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
@@ -194,7 +230,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* callback for #idle_monitor */
|
/* callback for #idle_monitor */
|
||||||
void OnIdle(unsigned mask);
|
void OnIdle(unsigned mask) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -34,8 +34,6 @@
|
|||||||
#include "fs/XDG.hxx"
|
#include "fs/XDG.hxx"
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||||
#include <systemd/sd-daemon.h>
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,13 +22,15 @@
|
|||||||
#include "client/Client.hxx"
|
#include "client/Client.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "ls.hxx"
|
#include "ls.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
|
||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
|
#include "util/UriExtract.hxx"
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
#include "storage/StorageInterface.hxx"
|
#include "storage/StorageInterface.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
static LocatedUri
|
static LocatedUri
|
||||||
LocateFileUri(const char *uri, const Client *client
|
LocateFileUri(const char *uri, const Client *client
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
@@ -40,11 +42,13 @@ LocateFileUri(const char *uri, const Client *client
|
|||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
if (storage != nullptr) {
|
if (storage != nullptr) {
|
||||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
const auto suffix = storage->MapToRelativeUTF8(uri);
|
||||||
if (suffix != nullptr)
|
if (suffix.data() != nullptr)
|
||||||
/* this path was relative to the music
|
/* this path was relative to the music
|
||||||
directory */
|
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
|
#endif
|
||||||
|
|
||||||
@@ -55,20 +59,34 @@ LocateFileUri(const char *uri, const Client *client
|
|||||||
}
|
}
|
||||||
|
|
||||||
static LocatedUri
|
static LocatedUri
|
||||||
LocateAbsoluteUri(const char *uri
|
LocateAbsoluteUri(UriPluginKind kind, const char *uri
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
, const Storage *storage
|
, const Storage *storage
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (!uri_supported_scheme(uri))
|
switch (kind) {
|
||||||
throw std::runtime_error("Unsupported URI scheme");
|
case UriPluginKind::INPUT:
|
||||||
|
case UriPluginKind::STORAGE: // TODO: separate check for storage plugins
|
||||||
|
if (!uri_supported_scheme(uri))
|
||||||
|
throw std::runtime_error("Unsupported URI scheme");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case UriPluginKind::PLAYLIST:
|
||||||
|
/* for now, no validation for playlist URIs; this is
|
||||||
|
more complicated because there are three ways to
|
||||||
|
identify which plugin to use: URI scheme, filename
|
||||||
|
suffix and MIME type */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
if (storage != nullptr) {
|
if (storage != nullptr) {
|
||||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
const auto suffix = storage->MapToRelativeUTF8(uri);
|
||||||
if (suffix != nullptr)
|
if (suffix.data() != nullptr)
|
||||||
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
|
#endif
|
||||||
|
|
||||||
@@ -76,7 +94,8 @@ LocateAbsoluteUri(const char *uri
|
|||||||
}
|
}
|
||||||
|
|
||||||
LocatedUri
|
LocatedUri
|
||||||
LocateUri(const char *uri, const Client *client
|
LocateUri(UriPluginKind kind,
|
||||||
|
const char *uri, const Client *client
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
, const Storage *storage
|
, const Storage *storage
|
||||||
#endif
|
#endif
|
||||||
@@ -100,7 +119,7 @@ LocateUri(const char *uri, const Client *client
|
|||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
else if (uri_has_scheme(uri))
|
else if (uri_has_scheme(uri))
|
||||||
return LocateAbsoluteUri(uri
|
return LocateAbsoluteUri(kind, uri
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
, storage
|
, storage
|
||||||
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -21,7 +21,6 @@
|
|||||||
#define MPD_LOCATE_URI_HXX
|
#define MPD_LOCATE_URI_HXX
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/Compiler.h"
|
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@@ -41,6 +40,12 @@ class Client;
|
|||||||
class Storage;
|
class Storage;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum class UriPluginKind {
|
||||||
|
INPUT,
|
||||||
|
STORAGE,
|
||||||
|
PLAYLIST,
|
||||||
|
};
|
||||||
|
|
||||||
struct LocatedUri {
|
struct LocatedUri {
|
||||||
enum class Type {
|
enum class Type {
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +89,8 @@ struct LocatedUri {
|
|||||||
* that feature is disabled if this parameter is nullptr
|
* that feature is disabled if this parameter is nullptr
|
||||||
*/
|
*/
|
||||||
LocatedUri
|
LocatedUri
|
||||||
LocateUri(const char *uri, const Client *client
|
LocateUri(UriPluginKind kind,
|
||||||
|
const char *uri, const Client *client
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
, const Storage *storage
|
, const Storage *storage
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -19,162 +19,131 @@
|
|||||||
|
|
||||||
#include "LogV.hxx"
|
#include "LogV.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
|
#include "util/Exception.hxx"
|
||||||
|
|
||||||
#include <exception>
|
#include <cerrno>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
static constexpr Domain exception_domain("exception");
|
static constexpr Domain exception_domain("exception");
|
||||||
|
|
||||||
void
|
void
|
||||||
LogFormatV(const Domain &domain, LogLevel level,
|
LogFormatV(LogLevel level, const Domain &domain,
|
||||||
const char *fmt, va_list ap) noexcept
|
const char *fmt, std::va_list ap) noexcept
|
||||||
{
|
{
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
Log(domain, level, msg);
|
Log(level, domain, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, level, fmt, ap);
|
LogFormatV(level, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatDebug(const Domain &domain, const char *fmt, ...) noexcept
|
FormatDebug(const Domain &domain, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, LogLevel::DEBUG, fmt, ap);
|
LogFormatV(LogLevel::DEBUG, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept
|
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, LogLevel::INFO, fmt, ap);
|
LogFormatV(LogLevel::INFO, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, LogLevel::DEFAULT, fmt, ap);
|
LogFormatV(LogLevel::NOTICE, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatWarning(const Domain &domain, const char *fmt, ...) noexcept
|
FormatWarning(const Domain &domain, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, LogLevel::WARNING, fmt, ap);
|
LogFormatV(LogLevel::WARNING, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatError(const Domain &domain, const char *fmt, ...) noexcept
|
FormatError(const Domain &domain, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
LogFormatV(domain, LogLevel::ERROR, fmt, ap);
|
LogFormatV(LogLevel::ERROR, domain, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LogError(const std::exception &e) noexcept
|
Log(LogLevel level, const std::exception &e) noexcept
|
||||||
{
|
{
|
||||||
Log(exception_domain, LogLevel::ERROR, e.what());
|
Log(level, exception_domain, GetFullMessage(e).c_str());
|
||||||
|
|
||||||
try {
|
|
||||||
std::rethrow_if_nested(e);
|
|
||||||
} catch (const std::exception &nested) {
|
|
||||||
LogError(nested, "nested");
|
|
||||||
} catch (...) {
|
|
||||||
Log(exception_domain, LogLevel::ERROR,
|
|
||||||
"Unrecognized nested exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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());
|
LogFormat(level, exception_domain, "%s: %s", msg, GetFullMessage(e).c_str());
|
||||||
|
|
||||||
try {
|
|
||||||
std::rethrow_if_nested(e);
|
|
||||||
} catch (const std::exception &nested) {
|
|
||||||
LogError(nested);
|
|
||||||
} catch (...) {
|
|
||||||
Log(exception_domain, LogLevel::ERROR,
|
|
||||||
"Unrecognized nested exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FormatError(const std::exception &e, const char *fmt, ...) noexcept
|
LogFormat(LogLevel level, const std::exception &e, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
char msg[1024];
|
char msg[1024];
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
LogError(e, msg);
|
Log(level, e, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LogError(const std::exception_ptr &ep) noexcept
|
Log(LogLevel level, const std::exception_ptr &ep) noexcept
|
||||||
{
|
{
|
||||||
try {
|
Log(level, exception_domain, GetFullMessage(ep).c_str());
|
||||||
std::rethrow_exception(ep);
|
|
||||||
} catch (const std::exception &e) {
|
|
||||||
LogError(e);
|
|
||||||
} catch (...) {
|
|
||||||
Log(exception_domain, LogLevel::ERROR,
|
|
||||||
"Unrecognized exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LogError(const std::exception_ptr &ep, const char *msg) noexcept
|
Log(LogLevel level, const std::exception_ptr &ep, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
try {
|
LogFormat(level, exception_domain, "%s: %s", msg,
|
||||||
std::rethrow_exception(ep);
|
GetFullMessage(ep).c_str());
|
||||||
} catch (const std::exception &e) {
|
|
||||||
LogError(e, msg);
|
|
||||||
} catch (...) {
|
|
||||||
FormatError(exception_domain,
|
|
||||||
"%s: Unrecognized exception", msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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];
|
char msg[1024];
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
LogError(ep, msg);
|
Log(level, ep, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LogErrno(const Domain &domain, int e, const char *msg) noexcept
|
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
|
void
|
||||||
@@ -184,7 +153,7 @@ LogErrno(const Domain &domain, const char *msg) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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];
|
char msg[1024];
|
||||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
@@ -195,7 +164,7 @@ FormatErrnoV(const Domain &domain, int e, const char *fmt, va_list ap) noexcept
|
|||||||
void
|
void
|
||||||
FormatErrno(const Domain &domain, int e, const char *fmt, ...) noexcept
|
FormatErrno(const Domain &domain, int e, const char *fmt, ...) noexcept
|
||||||
{
|
{
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
FormatErrnoV(domain, e, fmt, ap);
|
FormatErrnoV(domain, e, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -206,7 +175,7 @@ FormatErrno(const Domain &domain, const char *fmt, ...) noexcept
|
|||||||
{
|
{
|
||||||
const int e = errno;
|
const int e = errno;
|
||||||
|
|
||||||
va_list ap;
|
std::va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
FormatErrnoV(domain, e, fmt, ap);
|
FormatErrnoV(domain, e, fmt, ap);
|
||||||
va_end(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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -28,16 +28,38 @@
|
|||||||
class Domain;
|
class Domain;
|
||||||
|
|
||||||
void
|
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)
|
gcc_printf(3,4)
|
||||||
void
|
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
|
static inline void
|
||||||
LogDebug(const Domain &domain, const char *msg) noexcept
|
LogDebug(const Domain &domain, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
Log(domain, LogLevel::DEBUG, msg);
|
Log(LogLevel::DEBUG, domain, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_printf(2,3)
|
gcc_printf(2,3)
|
||||||
@@ -47,7 +69,7 @@ FormatDebug(const Domain &domain, const char *fmt, ...) noexcept;
|
|||||||
static inline void
|
static inline void
|
||||||
LogInfo(const Domain &domain, const char *msg) noexcept
|
LogInfo(const Domain &domain, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
Log(domain, LogLevel::INFO, msg);
|
Log(LogLevel::INFO, domain, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_printf(2,3)
|
gcc_printf(2,3)
|
||||||
@@ -55,19 +77,19 @@ void
|
|||||||
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept;
|
FormatInfo(const Domain &domain, const char *fmt, ...) noexcept;
|
||||||
|
|
||||||
static inline void
|
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)
|
gcc_printf(2,3)
|
||||||
void
|
void
|
||||||
FormatDefault(const Domain &domain, const char *fmt, ...) noexcept;
|
FormatNotice(const Domain &domain, const char *fmt, ...) noexcept;
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
LogWarning(const Domain &domain, const char *msg) noexcept
|
LogWarning(const Domain &domain, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
Log(domain, LogLevel::WARNING, msg);
|
Log(LogLevel::WARNING, domain, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_printf(2,3)
|
gcc_printf(2,3)
|
||||||
@@ -77,28 +99,47 @@ FormatWarning(const Domain &domain, const char *fmt, ...) noexcept;
|
|||||||
static inline void
|
static inline void
|
||||||
LogError(const Domain &domain, const char *msg) noexcept
|
LogError(const Domain &domain, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
Log(domain, LogLevel::ERROR, msg);
|
Log(LogLevel::ERROR, domain, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
LogError(const std::exception &e) noexcept;
|
LogError(const std::exception &e) noexcept
|
||||||
|
{
|
||||||
|
Log(LogLevel::ERROR, e);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
LogError(const std::exception &e, const char *msg) noexcept;
|
LogError(const std::exception &e, const char *msg) noexcept
|
||||||
|
{
|
||||||
|
Log(LogLevel::ERROR, e, msg);
|
||||||
|
}
|
||||||
|
|
||||||
gcc_printf(2,3)
|
template<typename... Args>
|
||||||
void
|
inline void
|
||||||
FormatError(const std::exception &e, const char *fmt, ...) noexcept;
|
FormatError(const std::exception &e, const char *fmt, Args&&... args) noexcept
|
||||||
|
{
|
||||||
|
LogFormat(LogLevel::ERROR, e, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
LogError(const std::exception_ptr &ep) noexcept;
|
LogError(const std::exception_ptr &ep) noexcept
|
||||||
|
{
|
||||||
|
Log(LogLevel::ERROR, ep);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
LogError(const std::exception_ptr &ep, const char *msg) noexcept;
|
LogError(const std::exception_ptr &ep, const char *msg) noexcept
|
||||||
|
{
|
||||||
|
Log(LogLevel::ERROR, ep, msg);
|
||||||
|
}
|
||||||
|
|
||||||
gcc_printf(2,3)
|
template<typename... Args>
|
||||||
void
|
inline void
|
||||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...) noexcept;
|
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)
|
gcc_printf(2,3)
|
||||||
void
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -21,9 +21,11 @@
|
|||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/StringStrip.hxx"
|
#include "util/StringStrip.hxx"
|
||||||
|
#include "Version.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -45,7 +47,7 @@ ToAndroidLogLevel(LogLevel log_level) noexcept
|
|||||||
return ANDROID_LOG_DEBUG;
|
return ANDROID_LOG_DEBUG;
|
||||||
|
|
||||||
case LogLevel::INFO:
|
case LogLevel::INFO:
|
||||||
case LogLevel::DEFAULT:
|
case LogLevel::NOTICE:
|
||||||
return ANDROID_LOG_INFO;
|
return ANDROID_LOG_INFO;
|
||||||
|
|
||||||
case LogLevel::WARNING:
|
case LogLevel::WARNING:
|
||||||
@@ -61,7 +63,7 @@ ToAndroidLogLevel(LogLevel log_level) noexcept
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static LogLevel log_threshold = LogLevel::INFO;
|
static LogLevel log_threshold = LogLevel::NOTICE;
|
||||||
|
|
||||||
static bool enable_timestamp;
|
static bool enable_timestamp;
|
||||||
|
|
||||||
@@ -120,7 +122,7 @@ ToSysLogLevel(LogLevel log_level) noexcept
|
|||||||
case LogLevel::INFO:
|
case LogLevel::INFO:
|
||||||
return LOG_INFO;
|
return LOG_INFO;
|
||||||
|
|
||||||
case LogLevel::DEFAULT:
|
case LogLevel::NOTICE:
|
||||||
return LOG_NOTICE;
|
return LOG_NOTICE;
|
||||||
|
|
||||||
case LogLevel::WARNING:
|
case LogLevel::WARNING:
|
||||||
@@ -176,7 +178,7 @@ FileLog(const Domain &domain, const char *message) noexcept
|
|||||||
#endif /* !ANDROID */
|
#endif /* !ANDROID */
|
||||||
|
|
||||||
void
|
void
|
||||||
Log(const Domain &domain, LogLevel level, const char *msg) noexcept
|
Log(LogLevel level, const Domain &domain, const char *msg) noexcept
|
||||||
{
|
{
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
__android_log_print(ToAndroidLogLevel(level), "MPD",
|
__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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -28,24 +28,24 @@
|
|||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/StringAPI.hxx"
|
||||||
#include "system/Error.hxx"
|
#include "system/Error.hxx"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||||
#include <systemd/sd-daemon.h>
|
#include <systemd/sd-daemon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define LOG_LEVEL_SECURE LogLevel::INFO
|
|
||||||
|
|
||||||
#define LOG_DATE_BUF_SIZE 16
|
#define LOG_DATE_BUF_SIZE 16
|
||||||
#define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1)
|
#define LOG_DATE_LEN (LOG_DATE_BUF_SIZE - 1)
|
||||||
|
|
||||||
gcc_unused
|
[[maybe_unused]]
|
||||||
static constexpr Domain log_domain("log");
|
static constexpr Domain log_domain("log");
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
@@ -63,7 +63,7 @@ static void redirect_logs(int fd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
open_log_file(void)
|
open_log_file()
|
||||||
{
|
{
|
||||||
assert(!out_path.IsNull());
|
assert(!out_path.IsNull());
|
||||||
|
|
||||||
@@ -93,17 +93,24 @@ log_init_file(int line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline LogLevel
|
static inline LogLevel
|
||||||
parse_log_level(const char *value, int line)
|
parse_log_level(const char *value)
|
||||||
{
|
{
|
||||||
if (0 == strcmp(value, "default"))
|
if (StringIsEqual(value, "notice") ||
|
||||||
return LogLevel::DEFAULT;
|
/* deprecated name: */
|
||||||
if (0 == strcmp(value, "secure"))
|
StringIsEqual(value, "default"))
|
||||||
return LOG_LEVEL_SECURE;
|
return LogLevel::NOTICE;
|
||||||
else if (0 == strcmp(value, "verbose"))
|
else if (StringIsEqual(value, "info") ||
|
||||||
|
/* deprecated since MPD 0.22: */
|
||||||
|
StringIsEqual(value, "secure"))
|
||||||
|
return LogLevel::INFO;
|
||||||
|
else if (StringIsEqual(value, "verbose"))
|
||||||
return LogLevel::DEBUG;
|
return LogLevel::DEBUG;
|
||||||
|
else if (StringIsEqual(value, "warning"))
|
||||||
|
return LogLevel::WARNING;
|
||||||
|
else if (StringIsEqual(value, "error"))
|
||||||
|
return LogLevel::ERROR;
|
||||||
else
|
else
|
||||||
throw FormatRuntimeError("unknown log level \"%s\" at line %d",
|
throw FormatRuntimeError("unknown log level \"%s\"", value);
|
||||||
value, line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -132,9 +139,12 @@ log_init(const ConfigData &config, bool verbose, bool use_stdout)
|
|||||||
#else
|
#else
|
||||||
if (verbose)
|
if (verbose)
|
||||||
SetLogThreshold(LogLevel::DEBUG);
|
SetLogThreshold(LogLevel::DEBUG);
|
||||||
else if (const auto ¶m = config.GetParam(ConfigOption::LOG_LEVEL))
|
else
|
||||||
SetLogThreshold(parse_log_level(param->value.c_str(),
|
SetLogThreshold(config.With(ConfigOption::LOG_LEVEL, [](const char *s){
|
||||||
param->line));
|
return s != nullptr
|
||||||
|
? parse_log_level(s)
|
||||||
|
: LogLevel::NOTICE;
|
||||||
|
}));
|
||||||
|
|
||||||
if (use_stdout) {
|
if (use_stdout) {
|
||||||
out_fd = STDOUT_FILENO;
|
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");
|
throw std::runtime_error("config parameter 'log_file' not found");
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYSLOG
|
#ifdef HAVE_SYSLOG
|
||||||
} else if (strcmp(param->value.c_str(), "syslog") == 0) {
|
} else if (StringIsEqual(param->value.c_str(), "syslog")) {
|
||||||
LogInitSysLog();
|
LogInitSysLog();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -42,7 +42,7 @@ enum class LogLevel {
|
|||||||
/**
|
/**
|
||||||
* Interesting informational message.
|
* Interesting informational message.
|
||||||
*/
|
*/
|
||||||
DEFAULT,
|
NOTICE,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Warning: something may be wrong.
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,10 +22,10 @@
|
|||||||
|
|
||||||
#include "Log.hxx" // IWYU pragma: export
|
#include "Log.hxx" // IWYU pragma: export
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <cstdarg>
|
||||||
|
|
||||||
void
|
void
|
||||||
LogFormatV(const Domain &domain, LogLevel level,
|
LogFormatV(LogLevel level, const Domain &domain,
|
||||||
const char *fmt, va_list ap) noexcept;
|
const char *fmt, std::va_list ap) noexcept;
|
||||||
|
|
||||||
#endif /* LOG_H */
|
#endif /* LOG_H */
|
||||||
|
|||||||
459
src/Main.cxx
459
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -27,30 +27,30 @@
|
|||||||
#include "Mapper.hxx"
|
#include "Mapper.hxx"
|
||||||
#include "Permission.hxx"
|
#include "Permission.hxx"
|
||||||
#include "Listen.hxx"
|
#include "Listen.hxx"
|
||||||
#include "client/Listener.hxx"
|
#include "client/Config.hxx"
|
||||||
#include "client/Client.hxx"
|
#include "client/List.hxx"
|
||||||
#include "client/ClientList.hxx"
|
|
||||||
#include "command/AllCommands.hxx"
|
#include "command/AllCommands.hxx"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "tag/Config.hxx"
|
#include "tag/Config.hxx"
|
||||||
#include "ReplayGainGlobal.hxx"
|
#include "ReplayGainGlobal.hxx"
|
||||||
#include "Idle.hxx"
|
#include "IdleFlags.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "LogInit.hxx"
|
#include "LogInit.hxx"
|
||||||
#include "input/Init.hxx"
|
#include "input/Init.hxx"
|
||||||
|
#include "input/cache/Config.hxx"
|
||||||
|
#include "input/cache/Manager.hxx"
|
||||||
#include "event/Loop.hxx"
|
#include "event/Loop.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "fs/Config.hxx"
|
#include "fs/Config.hxx"
|
||||||
#include "playlist/PlaylistRegistry.hxx"
|
#include "playlist/PlaylistRegistry.hxx"
|
||||||
#include "zeroconf/ZeroconfGlue.hxx"
|
#include "zeroconf/ZeroconfGlue.hxx"
|
||||||
#include "decoder/DecoderList.hxx"
|
#include "decoder/DecoderList.hxx"
|
||||||
#include "AudioParser.hxx"
|
#include "pcm/AudioParser.hxx"
|
||||||
#include "pcm/PcmConvert.hxx"
|
#include "pcm/Convert.hxx"
|
||||||
#include "unix/SignalHandlers.hxx"
|
#include "unix/SignalHandlers.hxx"
|
||||||
#include "thread/Slack.hxx"
|
#include "thread/Slack.hxx"
|
||||||
#include "net/Init.hxx"
|
#include "net/Init.hxx"
|
||||||
#include "lib/icu/Init.hxx"
|
#include "lib/icu/Init.hxx"
|
||||||
#include "config/File.hxx"
|
|
||||||
#include "config/Check.hxx"
|
#include "config/Check.hxx"
|
||||||
#include "config/Data.hxx"
|
#include "config/Data.hxx"
|
||||||
#include "config/Param.hxx"
|
#include "config/Param.hxx"
|
||||||
@@ -58,6 +58,7 @@
|
|||||||
#include "config/Defaults.hxx"
|
#include "config/Defaults.hxx"
|
||||||
#include "config/Option.hxx"
|
#include "config/Option.hxx"
|
||||||
#include "config/Domain.hxx"
|
#include "config/Domain.hxx"
|
||||||
|
#include "config/Parser.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
|
||||||
@@ -82,7 +83,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_SQLITE
|
#ifdef ENABLE_SQLITE
|
||||||
#include "sticker/StickerDatabase.hxx"
|
#include "sticker/Database.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ENABLE_ARCHIVE
|
#ifdef ENABLE_ARCHIVE
|
||||||
@@ -95,6 +96,7 @@
|
|||||||
#include "android/Environment.hxx"
|
#include "android/Environment.hxx"
|
||||||
#include "android/Context.hxx"
|
#include "android/Context.hxx"
|
||||||
#include "android/LogListener.hxx"
|
#include "android/LogListener.hxx"
|
||||||
|
#include "config/File.hxx"
|
||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "org_musicpd_Bridge.h"
|
#include "org_musicpd_Bridge.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -107,14 +109,12 @@
|
|||||||
#include <systemd/sd-daemon.h>
|
#include <systemd/sd-daemon.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <climits>
|
||||||
|
|
||||||
#ifdef HAVE_LOCALE_H
|
#ifndef ANDROID
|
||||||
#include <locale.h>
|
#include <clocale>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
static constexpr size_t KILOBYTE = 1024;
|
static constexpr size_t KILOBYTE = 1024;
|
||||||
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||||
|
|
||||||
@@ -129,17 +129,14 @@ Context *context;
|
|||||||
LogListener *logListener;
|
LogListener *logListener;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Instance *instance;
|
Instance *global_instance;
|
||||||
|
|
||||||
struct Config {
|
struct Config {
|
||||||
ReplayGainConfig replay_gain;
|
ReplayGainConfig replay_gain;
|
||||||
};
|
|
||||||
|
|
||||||
static Config
|
explicit Config(const ConfigData &raw)
|
||||||
LoadConfig(const ConfigData &config)
|
:replay_gain(LoadReplayGainConfig(raw)) {}
|
||||||
{
|
};
|
||||||
return {LoadReplayGainConfig(config)};
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef ENABLE_DAEMON
|
#ifdef ENABLE_DAEMON
|
||||||
|
|
||||||
@@ -166,14 +163,15 @@ glue_mapper_init(const ConfigData &config)
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
static void
|
static void
|
||||||
InitStorage(const ConfigData &config, EventLoop &event_loop)
|
InitStorage(Instance &instance, EventLoop &event_loop,
|
||||||
|
const ConfigData &config)
|
||||||
{
|
{
|
||||||
auto storage = CreateConfiguredStorage(config, event_loop);
|
auto storage = CreateConfiguredStorage(config, event_loop);
|
||||||
if (storage == nullptr)
|
if (storage == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CompositeStorage *composite = new CompositeStorage();
|
auto *composite = new CompositeStorage();
|
||||||
instance->storage = composite;
|
instance.storage = composite;
|
||||||
composite->Mount("", std::move(storage));
|
composite->Mount("", std::move(storage));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,28 +181,29 @@ InitStorage(const ConfigData &config, EventLoop &event_loop)
|
|||||||
* process has been daemonized.
|
* process has been daemonized.
|
||||||
*/
|
*/
|
||||||
static bool
|
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,
|
auto db = CreateConfiguredDatabase(config, instance.event_loop,
|
||||||
instance->io_thread.GetEventLoop(),
|
instance.io_thread.GetEventLoop(),
|
||||||
*instance);
|
instance);
|
||||||
if (!db)
|
if (!db)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (db->GetPlugin().RequireStorage()) {
|
if (db->GetPlugin().RequireStorage()) {
|
||||||
InitStorage(config, instance->io_thread.GetEventLoop());
|
InitStorage(instance, instance.io_thread.GetEventLoop(),
|
||||||
|
config);
|
||||||
|
|
||||||
if (instance->storage == nullptr) {
|
if (instance.storage == nullptr) {
|
||||||
LogDefault(config_domain,
|
LogNotice(config_domain,
|
||||||
"Found database setting without "
|
"Found database setting without "
|
||||||
"music_directory - disabling database");
|
"music_directory - disabling database");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsStorageConfigured(config))
|
if (IsStorageConfigured(config))
|
||||||
LogDefault(config_domain,
|
LogNotice(config_domain,
|
||||||
"Ignoring the storage configuration "
|
"Ignoring the storage configuration "
|
||||||
"because the database does not need it");
|
"because the database does not need it");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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"));
|
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)
|
if (sdb == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
instance->update = new UpdateService(config,
|
instance.update = new UpdateService(config,
|
||||||
instance->event_loop, *sdb,
|
instance.event_loop, *sdb,
|
||||||
static_cast<CompositeStorage &>(*instance->storage),
|
static_cast<CompositeStorage &>(*instance.storage),
|
||||||
*instance);
|
instance);
|
||||||
|
|
||||||
/* run database update after daemonization? */
|
/* run database update after daemonization? */
|
||||||
return sdb->FileExists();
|
return sdb->FileExists();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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;
|
return create_db;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_SQLITE
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure and initialize the sticker subsystem.
|
* Configure and initialize the sticker subsystem.
|
||||||
*/
|
*/
|
||||||
static void
|
static std::unique_ptr<StickerDatabase>
|
||||||
glue_sticker_init(const ConfigData &config)
|
LoadStickerDatabase(const ConfigData &config)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_SQLITE
|
|
||||||
auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
|
auto sticker_file = config.GetPath(ConfigOption::STICKER_FILE);
|
||||||
if (sticker_file.IsNull())
|
if (sticker_file.IsNull())
|
||||||
return;
|
return nullptr;
|
||||||
|
|
||||||
sticker_global_init(std::move(sticker_file));
|
return std::make_unique<StickerDatabase>(std::move(sticker_file));
|
||||||
#else
|
|
||||||
(void)config;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
glue_state_file_init(const ConfigData &raw_config)
|
glue_state_file_init(Instance &instance, const ConfigData &raw_config)
|
||||||
{
|
{
|
||||||
StateFileConfig config(raw_config);
|
StateFileConfig config(raw_config);
|
||||||
if (!config.IsEnabled())
|
if (!config.IsEnabled())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
instance->state_file = new StateFile(std::move(config),
|
instance.state_file = std::make_unique< StateFile>(std::move(config),
|
||||||
instance->partitions.front(),
|
instance.partitions.front(),
|
||||||
instance->event_loop);
|
instance.event_loop);
|
||||||
instance->state_file->Read();
|
instance.state_file->Read();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the decoder and player core, including the music pipe.
|
* Initialize the decoder and player core, including the music pipe.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
initialize_decoder_and_player(const ConfigData &config,
|
initialize_decoder_and_player(Instance &instance,
|
||||||
|
const ConfigData &config,
|
||||||
const ReplayGainConfig &replay_gain_config)
|
const ReplayGainConfig &replay_gain_config)
|
||||||
{
|
{
|
||||||
const ConfigParam *param;
|
const ConfigParam *param;
|
||||||
@@ -279,20 +279,21 @@ initialize_decoder_and_player(const ConfigData &config,
|
|||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
|
param = config.GetParam(ConfigOption::AUDIO_BUFFER_SIZE);
|
||||||
if (param != nullptr) {
|
if (param != nullptr) {
|
||||||
char *test;
|
buffer_size = param->With([](const char *s){
|
||||||
long tmp = strtol(param->value.c_str(), &test, 10);
|
size_t result = ParseSize(s, KILOBYTE);
|
||||||
if (*test != '\0' || tmp <= 0 || tmp == LONG_MAX)
|
if (result <= 0)
|
||||||
throw FormatRuntimeError("buffer size \"%s\" is not a "
|
throw FormatRuntimeError("buffer size \"%s\" is not a "
|
||||||
"positive integer, line %i",
|
"positive integer", s);
|
||||||
param->value.c_str(), param->line);
|
|
||||||
buffer_size = tmp * KILOBYTE;
|
|
||||||
|
|
||||||
if (buffer_size < MIN_BUFFER_SIZE) {
|
if (result < MIN_BUFFER_SIZE) {
|
||||||
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
|
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
|
||||||
(unsigned long)buffer_size,
|
(unsigned long)result,
|
||||||
(unsigned long)MIN_BUFFER_SIZE);
|
(unsigned long)MIN_BUFFER_SIZE);
|
||||||
buffer_size = MIN_BUFFER_SIZE;
|
result = MIN_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
} else
|
} else
|
||||||
buffer_size = DEFAULT_BUFFER_SIZE;
|
buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
@@ -306,35 +307,26 @@ initialize_decoder_and_player(const ConfigData &config,
|
|||||||
config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
|
config.GetPositive(ConfigOption::MAX_PLAYLIST_LENGTH,
|
||||||
DEFAULT_PLAYLIST_MAX_LENGTH);
|
DEFAULT_PLAYLIST_MAX_LENGTH);
|
||||||
|
|
||||||
AudioFormat configured_audio_format = AudioFormat::Undefined();
|
AudioFormat configured_audio_format = config.With(ConfigOption::AUDIO_OUTPUT_FORMAT, [](const char *s){
|
||||||
param = config.GetParam(ConfigOption::AUDIO_OUTPUT_FORMAT);
|
if (s == nullptr)
|
||||||
if (param != nullptr) {
|
return AudioFormat::Undefined();
|
||||||
try {
|
|
||||||
configured_audio_format = ParseAudioFormat(param->value.c_str(),
|
|
||||||
true);
|
|
||||||
} catch (...) {
|
|
||||||
std::throw_with_nested(FormatRuntimeError("error parsing line %i",
|
|
||||||
param->line));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->partitions.emplace_back(*instance,
|
return ParseAudioFormat(s, true);
|
||||||
"default",
|
});
|
||||||
max_length,
|
|
||||||
buffered_chunks,
|
|
||||||
configured_audio_format,
|
|
||||||
replay_gain_config);
|
|
||||||
auto &partition = instance->partitions.back();
|
|
||||||
|
|
||||||
try {
|
instance.partitions.emplace_back(instance,
|
||||||
param = config.GetParam(ConfigOption::REPLAYGAIN);
|
"default",
|
||||||
if (param != nullptr)
|
max_length,
|
||||||
partition.replay_gain_mode =
|
buffered_chunks,
|
||||||
FromString(param->value.c_str());
|
configured_audio_format,
|
||||||
} catch (...) {
|
replay_gain_config);
|
||||||
std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
|
auto &partition = instance.partitions.back();
|
||||||
param->line));
|
|
||||||
}
|
partition.replay_gain_mode = config.With(ConfigOption::REPLAYGAIN, [](const char *s){
|
||||||
|
return s != nullptr
|
||||||
|
? FromString(s)
|
||||||
|
: ReplayGainMode::OFF;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@@ -354,56 +346,21 @@ inline void
|
|||||||
Instance::BeginShutdownPartitions() noexcept
|
Instance::BeginShutdownPartitions() noexcept
|
||||||
{
|
{
|
||||||
for (auto &partition : partitions) {
|
for (auto &partition : partitions) {
|
||||||
partition.pc.Kill();
|
partition.BeginShutdown();
|
||||||
partition.listener.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static inline void
|
||||||
Instance::OnIdle(unsigned flags)
|
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
|
#ifdef ENABLE_DAEMON
|
||||||
daemonize_close_stdin();
|
daemonize_close_stdin();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
#ifdef HAVE_LOCALE_H
|
|
||||||
/* initialize locale */
|
/* initialize locale */
|
||||||
setlocale(LC_CTYPE,"");
|
std::setlocale(LC_CTYPE,"");
|
||||||
setlocale(LC_COLLATE, "");
|
std::setlocale(LC_COLLATE, "");
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const ScopeIcuInit icu_init;
|
const ScopeIcuInit icu_init;
|
||||||
@@ -413,25 +370,8 @@ MainOrThrow(int argc, char *argv[])
|
|||||||
const ODBus::ScopeInit dbus_init;
|
const ODBus::ScopeInit dbus_init;
|
||||||
#endif
|
#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);
|
InitPathParser(raw_config);
|
||||||
const auto config = LoadConfig(raw_config);
|
const Config config(raw_config);
|
||||||
|
|
||||||
#ifdef ENABLE_DAEMON
|
#ifdef ENABLE_DAEMON
|
||||||
glue_daemonize_init(&options, raw_config);
|
glue_daemonize_init(&options, raw_config);
|
||||||
@@ -441,31 +381,33 @@ MainOrThrow(int argc, char *argv[])
|
|||||||
|
|
||||||
log_init(raw_config, options.verbose, options.log_stderr);
|
log_init(raw_config, options.verbose, options.log_stderr);
|
||||||
|
|
||||||
instance = new Instance();
|
Instance instance;
|
||||||
AtScopeExit() {
|
global_instance = &instance;
|
||||||
delete instance;
|
|
||||||
instance = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
instance->neighbors = new NeighborGlue();
|
instance.neighbors = std::make_unique<NeighborGlue>();
|
||||||
instance->neighbors->Init(raw_config,
|
instance.neighbors->Init(raw_config,
|
||||||
instance->io_thread.GetEventLoop(),
|
instance.io_thread.GetEventLoop(),
|
||||||
*instance);
|
instance);
|
||||||
|
|
||||||
if (instance->neighbors->IsEmpty()) {
|
if (instance.neighbors->IsEmpty())
|
||||||
delete instance->neighbors;
|
instance.neighbors.reset();
|
||||||
instance->neighbors = nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const unsigned max_clients =
|
const unsigned max_clients =
|
||||||
raw_config.GetPositive(ConfigOption::MAX_CONN, 10);
|
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
|
#ifdef ENABLE_DAEMON
|
||||||
daemonize_set_user();
|
daemonize_set_user();
|
||||||
@@ -473,27 +415,6 @@ MainOrThrow(int argc, char *argv[])
|
|||||||
AtScopeExit() { daemonize_finish(); };
|
AtScopeExit() { daemonize_finish(); };
|
||||||
#endif
|
#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);
|
ConfigureFS(raw_config);
|
||||||
AtScopeExit() { DeinitFS(); };
|
AtScopeExit() { DeinitFS(); };
|
||||||
|
|
||||||
@@ -510,24 +431,26 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|||||||
const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
|
const ScopeDecoderPluginsInit decoder_plugins_init(raw_config);
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
const bool create_db = InitDatabaseAndStorage(raw_config);
|
const bool create_db = InitDatabaseAndStorage(instance, raw_config);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glue_sticker_init(raw_config);
|
#ifdef ENABLE_SQLITE
|
||||||
|
instance.sticker_database = LoadStickerDatabase(raw_config);
|
||||||
|
#endif
|
||||||
|
|
||||||
command_init();
|
command_init();
|
||||||
|
|
||||||
for (auto &partition : instance->partitions) {
|
for (auto &partition : instance.partitions) {
|
||||||
partition.outputs.Configure(instance->rtio_thread.GetEventLoop(),
|
partition.outputs.Configure(instance.rtio_thread.GetEventLoop(),
|
||||||
raw_config,
|
raw_config,
|
||||||
config.replay_gain,
|
config.replay_gain);
|
||||||
partition.pc);
|
|
||||||
partition.UpdateEffectiveReplayGainMode();
|
partition.UpdateEffectiveReplayGainMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
client_manager_init(raw_config);
|
client_manager_init(raw_config);
|
||||||
const ScopeInputPluginsInit input_plugins_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);
|
const ScopePlaylistPluginsInit playlist_plugins_init(raw_config);
|
||||||
|
|
||||||
#ifdef ENABLE_DAEMON
|
#ifdef ENABLE_DAEMON
|
||||||
@@ -537,37 +460,42 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
setup_log_output();
|
setup_log_output();
|
||||||
|
|
||||||
const ScopeSignalHandlersInit signal_handlers_init(instance->event_loop);
|
const ScopeSignalHandlersInit signal_handlers_init(instance);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
instance->io_thread.Start();
|
instance.io_thread.Start();
|
||||||
instance->rtio_thread.Start();
|
instance.rtio_thread.Start();
|
||||||
|
|
||||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||||
if (instance->neighbors != nullptr)
|
if (instance.neighbors != nullptr)
|
||||||
instance->neighbors->Open();
|
instance.neighbors->Open();
|
||||||
|
|
||||||
|
AtScopeExit(&instance) {
|
||||||
|
if (instance.neighbors != nullptr)
|
||||||
|
instance.neighbors->Close();
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ZeroconfInit(raw_config, instance->event_loop);
|
ZeroconfInit(raw_config, instance.event_loop);
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
if (create_db) {
|
if (create_db) {
|
||||||
/* the database failed to load: recreate the
|
/* the database failed to load: recreate the
|
||||||
database */
|
database */
|
||||||
instance->update->Enqueue("", true);
|
instance.update->Enqueue("", true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
glue_state_file_init(raw_config);
|
glue_state_file_init(instance, raw_config);
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
|
if (raw_config.GetBool(ConfigOption::AUTO_UPDATE, false)) {
|
||||||
#ifdef ENABLE_INOTIFY
|
#ifdef ENABLE_INOTIFY
|
||||||
if (instance->storage != nullptr &&
|
if (instance.storage != nullptr &&
|
||||||
instance->update != nullptr)
|
instance.update != nullptr)
|
||||||
mpd_inotify_init(instance->event_loop,
|
mpd_inotify_init(instance.event_loop,
|
||||||
*instance->storage,
|
*instance.storage,
|
||||||
*instance->update,
|
*instance.update,
|
||||||
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
raw_config.GetUnsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
||||||
INT_MAX));
|
INT_MAX));
|
||||||
#else
|
#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
|
/* enable all audio outputs (if not already done by
|
||||||
playlist_state_restore() */
|
playlist_state_restore() */
|
||||||
for (auto &partition : instance->partitions)
|
for (auto &partition : instance.partitions)
|
||||||
partition.pc.LockUpdateAudio();
|
partition.pc.LockUpdateAudio();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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
|
/* the MPD frontend does not care about timer slack; set it to
|
||||||
a huge value to allow the kernel to reduce CPU wakeups */
|
a huge value to allow the kernel to reduce CPU wakeups */
|
||||||
SetThreadTimerSlackMS(100);
|
SetThreadTimerSlack(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||||
sd_notify(0, "READY=1");
|
sd_notify(0, "READY=1");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* run the main loop */
|
/* run the main loop */
|
||||||
instance->event_loop.Run();
|
instance.event_loop.Run();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
win32_app_stopping();
|
win32_app_stopping();
|
||||||
@@ -605,60 +533,101 @@ mpd_main_after_fork(const ConfigData &raw_config, const Config &config)
|
|||||||
|
|
||||||
/* cleanup */
|
/* cleanup */
|
||||||
|
|
||||||
instance->BeginShutdownUpdate();
|
if (instance.state_file)
|
||||||
|
instance.state_file->Write();
|
||||||
|
|
||||||
if (instance->state_file != nullptr) {
|
instance.BeginShutdownUpdate();
|
||||||
instance->state_file->Write();
|
|
||||||
delete instance->state_file;
|
|
||||||
}
|
|
||||||
|
|
||||||
ZeroconfDeinit();
|
ZeroconfDeinit();
|
||||||
|
|
||||||
instance->BeginShutdownPartitions();
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ANDROID
|
#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
|
gcc_visibility_default
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
|
Java_org_musicpd_Bridge_run(JNIEnv *env, jclass, jobject _context, jobject _logListener)
|
||||||
{
|
{
|
||||||
Java::Init(env);
|
Java::Init(env);
|
||||||
|
Java::Object::Initialise(env);
|
||||||
Java::File::Initialise(env);
|
Java::File::Initialise(env);
|
||||||
Environment::Initialise(env);
|
Environment::Initialise(env);
|
||||||
|
AtScopeExit(env) { Environment::Deinitialise(env); };
|
||||||
|
|
||||||
context = new Context(env, _context);
|
context = new Context(env, _context);
|
||||||
|
AtScopeExit() { delete context; };
|
||||||
|
|
||||||
if (_logListener != nullptr)
|
if (_logListener != nullptr)
|
||||||
logListener = new LogListener(env, _logListener);
|
logListener = new LogListener(env, _logListener);
|
||||||
|
AtScopeExit() { delete logListener; };
|
||||||
|
|
||||||
mpd_main(0, nullptr);
|
try {
|
||||||
|
AndroidMain();
|
||||||
delete logListener;
|
} catch (...) {
|
||||||
delete context;
|
LogError(std::current_exception());
|
||||||
Environment::Deinitialise(env);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_visibility_default
|
gcc_visibility_default
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
||||||
{
|
{
|
||||||
if (instance != nullptr)
|
if (global_instance != nullptr)
|
||||||
instance->Break();
|
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
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,18 +20,16 @@
|
|||||||
#ifndef MPD_MAIN_HXX
|
#ifndef MPD_MAIN_HXX
|
||||||
#define MPD_MAIN_HXX
|
#define MPD_MAIN_HXX
|
||||||
|
|
||||||
class EventLoop;
|
|
||||||
class Context;
|
|
||||||
struct Instance;
|
struct Instance;
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
#include "android/LogListener.hxx"
|
#include "android/LogListener.hxx"
|
||||||
|
|
||||||
extern Context *context;
|
extern class Context *context;
|
||||||
extern LogListener *logListener;
|
extern LogListener *logListener;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern Instance *instance;
|
extern Instance *global_instance;
|
||||||
|
|
||||||
#ifndef ANDROID
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "Main.hxx"
|
#include "Main.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The absolute path of the playlist directory encoded in the
|
* 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 != nullptr);
|
||||||
assert(*uri != '/');
|
assert(*uri != '/');
|
||||||
|
|
||||||
if (instance->storage == nullptr)
|
if (global_instance->storage == nullptr)
|
||||||
return 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())
|
if (music_dir_fs.IsNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ std::string
|
|||||||
map_fs_to_utf8(Path path_fs) noexcept
|
map_fs_to_utf8(Path path_fs) noexcept
|
||||||
{
|
{
|
||||||
if (path_fs.IsAbsolute()) {
|
if (path_fs.IsAbsolute()) {
|
||||||
if (instance->storage == nullptr)
|
if (global_instance->storage == nullptr)
|
||||||
return std::string();
|
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())
|
if (music_dir_fs.IsNull())
|
||||||
return std::string();
|
return std::string();
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ map_spl_utf8_to_fs(const char *name) noexcept
|
|||||||
filename_utf8.append(PLAYLIST_FILE_SUFFIX);
|
filename_utf8.append(PLAYLIST_FILE_SUFFIX);
|
||||||
|
|
||||||
const auto filename_fs =
|
const auto filename_fs =
|
||||||
AllocatedPath::FromUTF8(filename_utf8.c_str());
|
AllocatedPath::FromUTF8(filename_utf8);
|
||||||
if (filename_fs.IsNull())
|
if (filename_fs.IsNull())
|
||||||
return nullptr;
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "MusicBuffer.hxx"
|
#include "MusicBuffer.hxx"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
||||||
:buffer(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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -18,10 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
|
|
||||||
MusicChunkInfo::MusicChunkInfo() noexcept = default;
|
MusicChunkInfo::MusicChunkInfo() noexcept = default;
|
||||||
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -26,14 +26,13 @@
|
|||||||
#include "util/WritableBuffer.hxx"
|
#include "util/WritableBuffer.hxx"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include "AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
static constexpr size_t CHUNK_SIZE = 4096;
|
static constexpr size_t CHUNK_SIZE = 4096;
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2018 The Music Player Daemon Project
|
* Copyright 2003-2020 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
#include "MusicPipe.hxx"
|
#include "MusicPipe.hxx"
|
||||||
#include "MusicChunk.hxx"
|
#include "MusicChunk.hxx"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
bool
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -25,11 +25,9 @@
|
|||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#include "AudioFormat.hxx"
|
#include "pcm/AudioFormat.hxx"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A queue of #MusicChunk objects. One party appends chunks at the
|
* A queue of #MusicChunk objects. One party appends chunks at the
|
||||||
* tail, and the other consumes them from the head.
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,24 +20,33 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "Partition.hxx"
|
#include "Partition.hxx"
|
||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
|
#include "Log.hxx"
|
||||||
#include "song/DetachedSong.hxx"
|
#include "song/DetachedSong.hxx"
|
||||||
#include "mixer/Volume.hxx"
|
#include "mixer/Volume.hxx"
|
||||||
#include "IdleFlags.hxx"
|
#include "IdleFlags.hxx"
|
||||||
#include "client/Listener.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,
|
Partition::Partition(Instance &_instance,
|
||||||
const char *_name,
|
const char *_name,
|
||||||
unsigned max_length,
|
unsigned max_length,
|
||||||
unsigned buffer_chunks,
|
unsigned buffer_chunks,
|
||||||
AudioFormat configured_audio_format,
|
AudioFormat configured_audio_format,
|
||||||
const ReplayGainConfig &replay_gain_config)
|
const ReplayGainConfig &replay_gain_config) noexcept
|
||||||
:instance(_instance),
|
:instance(_instance),
|
||||||
name(_name),
|
name(_name),
|
||||||
listener(new ClientListener(instance.event_loop, *this)),
|
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)),
|
global_events(instance.event_loop, BIND_THIS_METHOD(OnGlobalEvent)),
|
||||||
playlist(max_length, *this),
|
playlist(max_length, *this),
|
||||||
outputs(*this),
|
outputs(pc, *this),
|
||||||
pc(*this, outputs, buffer_chunks,
|
pc(*this, outputs,
|
||||||
|
instance.input_cache.get(),
|
||||||
|
buffer_chunks,
|
||||||
configured_audio_format, replay_gain_config)
|
configured_audio_format, replay_gain_config)
|
||||||
{
|
{
|
||||||
UpdateEffectiveReplayGainMode();
|
UpdateEffectiveReplayGainMode();
|
||||||
@@ -46,13 +55,51 @@ Partition::Partition(Instance &_instance,
|
|||||||
Partition::~Partition() noexcept = default;
|
Partition::~Partition() noexcept = default;
|
||||||
|
|
||||||
void
|
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
|
void
|
||||||
Partition::UpdateEffectiveReplayGainMode()
|
Partition::UpdateEffectiveReplayGainMode() noexcept
|
||||||
{
|
{
|
||||||
auto mode = replay_gain_mode;
|
auto mode = replay_gain_mode;
|
||||||
if (mode == ReplayGainMode::AUTO)
|
if (mode == ReplayGainMode::AUTO)
|
||||||
@@ -68,7 +115,7 @@ Partition::UpdateEffectiveReplayGainMode()
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
const Database *
|
const Database *
|
||||||
Partition::GetDatabase() const
|
Partition::GetDatabase() const noexcept
|
||||||
{
|
{
|
||||||
return instance.GetDatabase();
|
return instance.GetDatabase();
|
||||||
}
|
}
|
||||||
@@ -80,7 +127,7 @@ Partition::GetDatabaseOrThrow() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::DatabaseModified(const Database &db)
|
Partition::DatabaseModified(const Database &db) noexcept
|
||||||
{
|
{
|
||||||
playlist.DatabaseModified(db);
|
playlist.DatabaseModified(db);
|
||||||
EmitIdle(IDLE_DATABASE);
|
EmitIdle(IDLE_DATABASE);
|
||||||
@@ -89,7 +136,7 @@ Partition::DatabaseModified(const Database &db)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::TagModified()
|
Partition::TagModified() noexcept
|
||||||
{
|
{
|
||||||
auto song = pc.LockReadTaggedSong();
|
auto song = pc.LockReadTaggedSong();
|
||||||
if (song)
|
if (song)
|
||||||
@@ -103,31 +150,35 @@ Partition::TagModified(const char *uri, const Tag &tag) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::SyncWithPlayer()
|
Partition::SyncWithPlayer() noexcept
|
||||||
{
|
{
|
||||||
playlist.SyncWithPlayer(pc);
|
playlist.SyncWithPlayer(pc);
|
||||||
|
|
||||||
|
/* TODO: invoke this function in batches, to let the hard disk
|
||||||
|
spin down in between */
|
||||||
|
PrefetchQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::BorderPause()
|
Partition::BorderPause() noexcept
|
||||||
{
|
{
|
||||||
playlist.BorderPause(pc);
|
playlist.BorderPause(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::OnQueueModified()
|
Partition::OnQueueModified() noexcept
|
||||||
{
|
{
|
||||||
EmitIdle(IDLE_PLAYLIST);
|
EmitIdle(IDLE_PLAYLIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::OnQueueOptionsChanged()
|
Partition::OnQueueOptionsChanged() noexcept
|
||||||
{
|
{
|
||||||
EmitIdle(IDLE_OPTIONS);
|
EmitIdle(IDLE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::OnQueueSongStarted()
|
Partition::OnQueueSongStarted() noexcept
|
||||||
{
|
{
|
||||||
EmitIdle(IDLE_PLAYER);
|
EmitIdle(IDLE_PLAYER);
|
||||||
}
|
}
|
||||||
@@ -151,7 +202,7 @@ Partition::OnBorderPause() noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
Partition::OnMixerVolumeChanged(Mixer &, int) noexcept
|
||||||
{
|
{
|
||||||
InvalidateHardwareVolume();
|
InvalidateHardwareVolume();
|
||||||
|
|
||||||
@@ -160,7 +211,19 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)
|
if ((mask & SYNC_WITH_PLAYER) != 0)
|
||||||
SyncWithPlayer();
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -30,9 +30,10 @@
|
|||||||
#include "ReplayGainMode.hxx"
|
#include "ReplayGainMode.hxx"
|
||||||
#include "SingleMode.hxx"
|
#include "SingleMode.hxx"
|
||||||
#include "Chrono.hxx"
|
#include "Chrono.hxx"
|
||||||
#include "util/Compiler.h"
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <boost/intrusive/list.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ struct Instance;
|
|||||||
class MultipleOutputs;
|
class MultipleOutputs;
|
||||||
class SongLoader;
|
class SongLoader;
|
||||||
class ClientListener;
|
class ClientListener;
|
||||||
|
class Client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A partition of the Music Player Daemon. It is a separate unit with
|
* 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;
|
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;
|
MaskMonitor global_events;
|
||||||
|
|
||||||
struct playlist playlist;
|
struct playlist playlist;
|
||||||
@@ -71,17 +83,34 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
unsigned max_length,
|
unsigned max_length,
|
||||||
unsigned buffer_chunks,
|
unsigned buffer_chunks,
|
||||||
AudioFormat configured_audio_format,
|
AudioFormat configured_audio_format,
|
||||||
const ReplayGainConfig &replay_gain_config);
|
const ReplayGainConfig &replay_gain_config) noexcept;
|
||||||
|
|
||||||
~Partition() noexcept;
|
~Partition() noexcept;
|
||||||
|
|
||||||
void EmitGlobalEvent(unsigned mask) {
|
void BeginShutdown() noexcept;
|
||||||
|
|
||||||
|
void EmitGlobalEvent(unsigned mask) noexcept {
|
||||||
global_events.OrMask(mask);
|
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);
|
playlist.Clear(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,11 +137,11 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
playlist.DeleteRange(pc, start, end);
|
playlist.DeleteRange(pc, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaleSong(const char *uri) {
|
void StaleSong(const char *uri) noexcept {
|
||||||
playlist.StaleSong(pc, uri);
|
playlist.StaleSong(pc, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shuffle(unsigned start, unsigned end) {
|
void Shuffle(unsigned start, unsigned end) noexcept {
|
||||||
playlist.Shuffle(pc, start, end);
|
playlist.Shuffle(pc, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +171,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
playlist.SetPriorityId(pc, song_id, priority);
|
playlist.SetPriorityId(pc, song_id, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop() {
|
void Stop() noexcept {
|
||||||
playlist.Stop(pc);
|
playlist.Stop(pc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,27 +203,27 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
playlist.SeekCurrent(pc, seek_time, relative);
|
playlist.SeekCurrent(pc, seek_time, relative);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRepeat(bool new_value) {
|
void SetRepeat(bool new_value) noexcept {
|
||||||
playlist.SetRepeat(pc, new_value);
|
playlist.SetRepeat(pc, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetRandom() const {
|
bool GetRandom() const noexcept {
|
||||||
return playlist.GetRandom();
|
return playlist.GetRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRandom(bool new_value) {
|
void SetRandom(bool new_value) noexcept {
|
||||||
playlist.SetRandom(pc, new_value);
|
playlist.SetRandom(pc, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSingle(SingleMode new_value) {
|
void SetSingle(SingleMode new_value) noexcept {
|
||||||
playlist.SetSingle(pc, new_value);
|
playlist.SetSingle(pc, new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetConsume(bool new_value) {
|
void SetConsume(bool new_value) noexcept {
|
||||||
playlist.SetConsume(new_value);
|
playlist.SetConsume(new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetReplayGainMode(ReplayGainMode mode) {
|
void SetReplayGainMode(ReplayGainMode mode) noexcept {
|
||||||
replay_gain_mode = mode;
|
replay_gain_mode = mode;
|
||||||
UpdateEffectiveReplayGainMode();
|
UpdateEffectiveReplayGainMode();
|
||||||
}
|
}
|
||||||
@@ -203,7 +232,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
* Publishes the effective #ReplayGainMode to all subsystems.
|
* Publishes the effective #ReplayGainMode to all subsystems.
|
||||||
* #ReplayGainMode::AUTO is substituted.
|
* #ReplayGainMode::AUTO is substituted.
|
||||||
*/
|
*/
|
||||||
void UpdateEffectiveReplayGainMode();
|
void UpdateEffectiveReplayGainMode() noexcept;
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
/**
|
/**
|
||||||
@@ -211,7 +240,7 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
* if this MPD configuration has no database (no
|
* if this MPD configuration has no database (no
|
||||||
* music_directory was configured).
|
* music_directory was configured).
|
||||||
*/
|
*/
|
||||||
const Database *GetDatabase() const;
|
const Database *GetDatabase() const noexcept;
|
||||||
|
|
||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
|
|
||||||
@@ -219,14 +248,14 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
* The database has been modified. Propagate the change to
|
* The database has been modified. Propagate the change to
|
||||||
* all subsystems.
|
* all subsystems.
|
||||||
*/
|
*/
|
||||||
void DatabaseModified(const Database &db);
|
void DatabaseModified(const Database &db) noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tag in the play queue has been modified by the player
|
* A tag in the play queue has been modified by the player
|
||||||
* thread. Propagate the change to all subsystems.
|
* thread. Propagate the change to all subsystems.
|
||||||
*/
|
*/
|
||||||
void TagModified();
|
void TagModified() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The tag of the given song has been modified. Propagate the
|
* 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.
|
* Synchronize the player with the play queue.
|
||||||
*/
|
*/
|
||||||
void SyncWithPlayer();
|
void SyncWithPlayer() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Border pause has just been enabled. Change single mode to off
|
* Border pause has just been enabled. Change single mode to off
|
||||||
* if it was one-shot.
|
* if it was one-shot.
|
||||||
*/
|
*/
|
||||||
void BorderPause();
|
void BorderPause() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* virtual methods from class QueueListener */
|
/* virtual methods from class QueueListener */
|
||||||
void OnQueueModified() override;
|
void OnQueueModified() noexcept override;
|
||||||
void OnQueueOptionsChanged() override;
|
void OnQueueOptionsChanged() noexcept override;
|
||||||
void OnQueueSongStarted() override;
|
void OnQueueSongStarted() noexcept override;
|
||||||
|
|
||||||
/* virtual methods from class PlayerListener */
|
/* virtual methods from class PlayerListener */
|
||||||
void OnPlayerSync() noexcept override;
|
void OnPlayerSync() noexcept override;
|
||||||
@@ -257,10 +286,13 @@ private:
|
|||||||
void OnBorderPause() noexcept override;
|
void OnBorderPause() noexcept override;
|
||||||
|
|
||||||
/* virtual methods from class MixerListener */
|
/* 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 */
|
/* callback for #global_events */
|
||||||
void OnGlobalEvent(unsigned mask);
|
void OnGlobalEvent(unsigned mask) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,14 +22,15 @@
|
|||||||
#include "config/Param.hxx"
|
#include "config/Param.hxx"
|
||||||
#include "config/Data.hxx"
|
#include "config/Data.hxx"
|
||||||
#include "config/Option.hxx"
|
#include "config/Option.hxx"
|
||||||
|
#include "util/IterableSplitString.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
#include "util/StringView.hxx"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static constexpr char PERMISSION_PASSWORD_CHAR = '@';
|
static constexpr char PERMISSION_PASSWORD_CHAR = '@';
|
||||||
static constexpr char PERMISSION_SEPARATOR = ',';
|
static constexpr char PERMISSION_SEPARATOR = ',';
|
||||||
@@ -54,35 +55,25 @@ static unsigned local_permissions;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
ParsePermission(const char *p)
|
ParsePermission(StringView s)
|
||||||
{
|
{
|
||||||
for (auto i = permission_names; i->name != nullptr; ++i)
|
for (auto i = permission_names; i->name != nullptr; ++i)
|
||||||
if (strcmp(p, i->name) == 0)
|
if (s.Equals(i->name))
|
||||||
return i->value;
|
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)
|
static unsigned parsePermissions(const char *string)
|
||||||
{
|
{
|
||||||
assert(string != nullptr);
|
assert(string != nullptr);
|
||||||
|
|
||||||
const char *const end = string + strlen(string);
|
|
||||||
|
|
||||||
unsigned permission = 0;
|
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)
|
for (const auto i : IterableSplitString(string, PERMISSION_SEPARATOR))
|
||||||
break;
|
if (!i.empty())
|
||||||
|
permission |= ParsePermission(i);
|
||||||
string = comma + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return permission;
|
return permission;
|
||||||
}
|
}
|
||||||
@@ -90,48 +81,44 @@ static unsigned parsePermissions(const char *string)
|
|||||||
void
|
void
|
||||||
initPermissions(const ConfigData &config)
|
initPermissions(const ConfigData &config)
|
||||||
{
|
{
|
||||||
unsigned permission;
|
|
||||||
|
|
||||||
permission_default = PERMISSION_READ | PERMISSION_ADD |
|
permission_default = PERMISSION_READ | PERMISSION_ADD |
|
||||||
PERMISSION_CONTROL | PERMISSION_ADMIN;
|
PERMISSION_CONTROL | PERMISSION_ADMIN;
|
||||||
|
|
||||||
for (const auto ¶m : config.GetParamList(ConfigOption::PASSWORD)) {
|
for (const auto ¶m : config.GetParamList(ConfigOption::PASSWORD)) {
|
||||||
permission_default = 0;
|
permission_default = 0;
|
||||||
|
|
||||||
const char *separator = strchr(param.value.c_str(),
|
param.With([](const char *value){
|
||||||
PERMISSION_PASSWORD_CHAR);
|
const char *separator = std::strchr(value,
|
||||||
|
PERMISSION_PASSWORD_CHAR);
|
||||||
|
|
||||||
if (separator == NULL)
|
if (separator == nullptr)
|
||||||
throw FormatRuntimeError("\"%c\" not found in password string "
|
throw FormatRuntimeError("\"%c\" not found in password string",
|
||||||
"\"%s\", line %i",
|
PERMISSION_PASSWORD_CHAR);
|
||||||
PERMISSION_PASSWORD_CHAR,
|
|
||||||
param.value.c_str(),
|
|
||||||
param.line);
|
|
||||||
|
|
||||||
std::string password(param.value.c_str(), separator);
|
std::string password(value, separator);
|
||||||
|
|
||||||
permission = parsePermissions(separator + 1);
|
unsigned permission = parsePermissions(separator + 1);
|
||||||
|
permission_passwords.insert(std::make_pair(std::move(password),
|
||||||
permission_passwords.insert(std::make_pair(std::move(password),
|
permission));
|
||||||
permission));
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfigParam *param;
|
config.With(ConfigOption::DEFAULT_PERMS, [](const char *value){
|
||||||
param = config.GetParam(ConfigOption::DEFAULT_PERMS);
|
if (value != nullptr)
|
||||||
|
permission_default = parsePermissions(value);
|
||||||
if (param)
|
});
|
||||||
permission_default = parsePermissions(param->value.c_str());
|
|
||||||
|
|
||||||
#ifdef HAVE_UN
|
#ifdef HAVE_UN
|
||||||
param = config.GetParam(ConfigOption::LOCAL_PERMISSIONS);
|
local_permissions = config.With(ConfigOption::LOCAL_PERMISSIONS, [](const char *value){
|
||||||
if (param != nullptr)
|
return value != nullptr
|
||||||
local_permissions = parsePermissions(param->value.c_str());
|
? parsePermissions(value)
|
||||||
else
|
: permission_default;
|
||||||
local_permissions = permission_default;
|
});
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int getPermissionFromPassword(char const* password, unsigned* permission)
|
int
|
||||||
|
getPermissionFromPassword(const char *password, unsigned *permission) noexcept
|
||||||
{
|
{
|
||||||
auto i = permission_passwords.find(password);
|
auto i = permission_passwords.find(password);
|
||||||
if (i == permission_passwords.end())
|
if (i == permission_passwords.end())
|
||||||
@@ -141,7 +128,8 @@ int getPermissionFromPassword(char const* password, unsigned* permission)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getDefaultPermissions(void)
|
unsigned
|
||||||
|
getDefaultPermissions() noexcept
|
||||||
{
|
{
|
||||||
return permission_default;
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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_CONTROL = 4;
|
||||||
static constexpr unsigned PERMISSION_ADMIN = 8;
|
static constexpr unsigned PERMISSION_ADMIN = 8;
|
||||||
|
|
||||||
int getPermissionFromPassword(char const* password, unsigned* permission);
|
int
|
||||||
|
getPermissionFromPassword(const char *password, unsigned *permission) noexcept;
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
getDefaultPermissions();
|
getDefaultPermissions() noexcept;
|
||||||
|
|
||||||
#ifdef HAVE_UN
|
#ifdef HAVE_UN
|
||||||
unsigned
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -21,11 +21,12 @@
|
|||||||
#include "db/PlaylistVector.hxx"
|
#include "db/PlaylistVector.hxx"
|
||||||
#include "fs/io/TextFile.hxx"
|
#include "fs/io/TextFile.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "fs/io/BufferedOutputStream.hxx"
|
||||||
|
#include "time/ChronoUtil.hxx"
|
||||||
#include "util/StringStrip.hxx"
|
#include "util/StringStrip.hxx"
|
||||||
#include "util/ChronoUtil.hxx"
|
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
|
|
||||||
#include <string.h>
|
#include <cstring>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -49,8 +50,8 @@ playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
|
|||||||
const char *value;
|
const char *value;
|
||||||
|
|
||||||
while ((line = file.ReadLine()) != nullptr &&
|
while ((line = file.ReadLine()) != nullptr &&
|
||||||
strcmp(line, "playlist_end") != 0) {
|
std::strcmp(line, "playlist_end") != 0) {
|
||||||
colon = strchr(line, ':');
|
colon = std::strchr(line, ':');
|
||||||
if (colon == nullptr || colon == line)
|
if (colon == nullptr || colon == line)
|
||||||
throw FormatRuntimeError("unknown line in db: %s",
|
throw FormatRuntimeError("unknown line in db: %s",
|
||||||
line);
|
line);
|
||||||
@@ -58,7 +59,7 @@ playlist_metadata_load(TextFile &file, PlaylistVector &pv, const char *name)
|
|||||||
*colon++ = 0;
|
*colon++ = 0;
|
||||||
value = StripLeft(colon);
|
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));
|
pm.mtime = std::chrono::system_clock::from_time_t(strtol(value, nullptr, 10));
|
||||||
else
|
else
|
||||||
throw FormatRuntimeError("unknown line in db: %s",
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -39,15 +39,11 @@
|
|||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/FileInfo.hxx"
|
#include "fs/FileInfo.hxx"
|
||||||
#include "fs/DirectoryReader.hxx"
|
#include "fs/DirectoryReader.hxx"
|
||||||
#include "util/Macros.hxx"
|
|
||||||
#include "util/StringCompare.hxx"
|
#include "util/StringCompare.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
|
|
||||||
#include <memory>
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
static const char PLAYLIST_COMMENT = '#';
|
static const char PLAYLIST_COMMENT = '#';
|
||||||
|
|
||||||
@@ -84,9 +80,9 @@ spl_valid_name(const char *name_utf8)
|
|||||||
* filenames isn't going to happen, either.
|
* filenames isn't going to happen, either.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return strchr(name_utf8, '/') == nullptr &&
|
return std::strchr(name_utf8, '/') == nullptr &&
|
||||||
strchr(name_utf8, '\n') == nullptr &&
|
std::strchr(name_utf8, '\n') == nullptr &&
|
||||||
strchr(name_utf8, '\r') == nullptr;
|
std::strchr(name_utf8, '\r') == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const AllocatedPath &
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,11 +22,6 @@
|
|||||||
#include "PlaylistError.hxx"
|
#include "PlaylistError.hxx"
|
||||||
#include "queue/Playlist.hxx"
|
#include "queue/Playlist.hxx"
|
||||||
#include "queue/QueuePrint.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_FILE "file: "
|
||||||
#define SONG_TIME "Time: "
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#ifndef MPD_PLAYLIST_PRINT_HXX
|
#ifndef MPD_PLAYLIST_PRINT_HXX
|
||||||
#define MPD_PLAYLIST_PRINT_HXX
|
#define MPD_PLAYLIST_PRINT_HXX
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
struct playlist;
|
struct playlist;
|
||||||
class SongFilter;
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -30,9 +30,7 @@
|
|||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/io/FileOutputStream.hxx"
|
#include "fs/io/FileOutputStream.hxx"
|
||||||
#include "fs/io/BufferedOutputStream.hxx"
|
#include "fs/io/BufferedOutputStream.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriExtract.hxx"
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
playlist_print_path(BufferedOutputStream &os, const Path path)
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* that this plugin is unavailable. It will be disabled, and MPD can
|
||||||
* continue initialization.
|
* continue initialization.
|
||||||
*/
|
*/
|
||||||
class PluginUnavailable final : public std::runtime_error {
|
class PluginUnavailable : public std::runtime_error {
|
||||||
public:
|
public:
|
||||||
explicit PluginUnavailable(const char *msg)
|
using std::runtime_error::runtime_error;
|
||||||
:std::runtime_error(msg) {}
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
#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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -19,13 +19,12 @@
|
|||||||
|
|
||||||
#include "ReplayGainGlobal.hxx"
|
#include "ReplayGainGlobal.hxx"
|
||||||
#include "ReplayGainConfig.hxx"
|
#include "ReplayGainConfig.hxx"
|
||||||
#include "config/Param.hxx"
|
|
||||||
#include "config/Data.hxx"
|
#include "config/Data.hxx"
|
||||||
#include "util/RuntimeError.hxx"
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
#include <stdlib.h>
|
#include <cmath>
|
||||||
#include <math.h>
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
static float
|
static float
|
||||||
ParsePreamp(const char *s)
|
ParsePreamp(const char *s)
|
||||||
@@ -33,25 +32,14 @@ ParsePreamp(const char *s)
|
|||||||
assert(s != nullptr);
|
assert(s != nullptr);
|
||||||
|
|
||||||
char *endptr;
|
char *endptr;
|
||||||
float f = strtod(s, &endptr);
|
float f = std::strtof(s, &endptr);
|
||||||
if (endptr == s || *endptr != '\0')
|
if (endptr == s || *endptr != '\0')
|
||||||
throw std::invalid_argument("Not a numeric value");
|
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");
|
throw std::invalid_argument("Number must be between -15 and 15");
|
||||||
|
|
||||||
return pow(10, f / 20.0);
|
return std::pow(10.0f, f / 20.0f);
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplayGainConfig
|
ReplayGainConfig
|
||||||
@@ -59,13 +47,17 @@ LoadReplayGainConfig(const ConfigData &config)
|
|||||||
{
|
{
|
||||||
ReplayGainConfig replay_gain_config;
|
ReplayGainConfig replay_gain_config;
|
||||||
|
|
||||||
const auto *param = config.GetParam(ConfigOption::REPLAYGAIN_PREAMP);
|
replay_gain_config.preamp = config.With(ConfigOption::REPLAYGAIN_PREAMP, [](const char *s){
|
||||||
if (param)
|
return s != nullptr
|
||||||
replay_gain_config.preamp = ParsePreamp(*param);
|
? ParsePreamp(s)
|
||||||
|
: 1.0f;
|
||||||
|
});
|
||||||
|
|
||||||
param = config.GetParam(ConfigOption::REPLAYGAIN_MISSING_PREAMP);
|
replay_gain_config.missing_preamp = config.With(ConfigOption::REPLAYGAIN_MISSING_PREAMP, [](const char *s){
|
||||||
if (param)
|
return s != nullptr
|
||||||
replay_gain_config.missing_preamp = ParsePreamp(*param);
|
? ParsePreamp(s)
|
||||||
|
: 1.0f;
|
||||||
|
});
|
||||||
|
|
||||||
replay_gain_config.limit = config.GetBool(ConfigOption::REPLAYGAIN_LIMIT,
|
replay_gain_config.limit = config.GetBool(ConfigOption::REPLAYGAIN_LIMIT,
|
||||||
ReplayGainConfig::DEFAULT_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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#include "ReplayGainInfo.hxx"
|
#include "ReplayGainInfo.hxx"
|
||||||
#include "ReplayGainConfig.hxx"
|
#include "ReplayGainConfig.hxx"
|
||||||
|
|
||||||
#include <math.h>
|
#include <cmath>
|
||||||
|
|
||||||
float
|
float
|
||||||
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
||||||
@@ -28,13 +28,13 @@ ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
|||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
if (IsDefined()) {
|
if (IsDefined()) {
|
||||||
scale = pow(10.0, gain / 20.0);
|
scale = std::pow(10.0f, gain / 20.0f);
|
||||||
scale *= config.preamp;
|
scale *= config.preamp;
|
||||||
if (scale > 15.0)
|
if (scale > 15.0f)
|
||||||
scale = 15.0;
|
scale = 15.0f;
|
||||||
|
|
||||||
if (config.limit && scale * peak > 1.0)
|
if (config.limit && scale * peak > 1.0f)
|
||||||
scale = 1.0 / peak;
|
scale = 1.0f / peak;
|
||||||
} else
|
} else
|
||||||
scale = config.missing_preamp;
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -38,6 +38,10 @@ struct ReplayGainTuple {
|
|||||||
return gain > -100;
|
return gain > -100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr ReplayGainTuple Undefined() noexcept {
|
||||||
|
return {-200.0f, 0.0f};
|
||||||
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
float CalculateScale(const ReplayGainConfig &config) const noexcept;
|
float CalculateScale(const ReplayGainConfig &config) const noexcept;
|
||||||
};
|
};
|
||||||
@@ -49,6 +53,13 @@ struct ReplayGainInfo {
|
|||||||
return track.IsDefined() || album.IsDefined();
|
return track.IsDefined() || album.IsDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr ReplayGainInfo Undefined() noexcept {
|
||||||
|
return {
|
||||||
|
ReplayGainTuple::Undefined(),
|
||||||
|
ReplayGainTuple::Undefined(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const ReplayGainTuple &Get(ReplayGainMode mode) const noexcept {
|
const ReplayGainTuple &Get(ReplayGainMode mode) const noexcept {
|
||||||
return mode == ReplayGainMode::ALBUM
|
return mode == ReplayGainMode::ALBUM
|
||||||
? (album.IsDefined() ? album : track)
|
? (album.IsDefined() ? album : track)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2018 The Music Player Daemon Project
|
* Copyright 2003-2020 The Music Player Daemon Project
|
||||||
* http://www.musicpd.org
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
#include "ReplayGainMode.hxx"
|
#include "ReplayGainMode.hxx"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
enum class ReplayGainMode : uint8_t {
|
enum class ReplayGainMode : uint8_t {
|
||||||
OFF,
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
#include "SingleMode.hxx"
|
#include "SingleMode.hxx"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *
|
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
|
* http://www.musicpd.org
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <cstdint>
|
||||||
|
|
||||||
enum class SingleMode : uint8_t {
|
enum class SingleMode : uint8_t {
|
||||||
OFF,
|
OFF,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user