Compare commits
250 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
323231d1dd | ||
![]() |
714011c81e | ||
![]() |
952ff4207b | ||
![]() |
150b16ec2c | ||
![]() |
c98bc4a243 | ||
![]() |
014f8cd693 | ||
![]() |
aea37e46e3 | ||
![]() |
31ab78ae8e | ||
![]() |
f82e1453e4 | ||
![]() |
a2b77c8813 | ||
![]() |
18add29472 | ||
![]() |
b111a8fe8d | ||
![]() |
3b23cf0258 | ||
![]() |
28e864e096 | ||
![]() |
1de19b921a | ||
![]() |
ff162b5a03 | ||
![]() |
d8e4705dd4 | ||
![]() |
338e1f5926 | ||
![]() |
a7fdfa08e1 | ||
![]() |
9703a401c5 | ||
![]() |
753a2aa462 | ||
![]() |
10990a0684 | ||
![]() |
91254e9211 | ||
![]() |
0f79287b04 | ||
![]() |
f2fac77d8c | ||
![]() |
81b7373637 | ||
![]() |
fa67c2548a | ||
![]() |
ea80587ddb | ||
![]() |
828f5f8384 | ||
![]() |
1295a1272a | ||
![]() |
66646d9276 | ||
![]() |
d0497dba92 | ||
![]() |
42914e8227 | ||
![]() |
59b49b7881 | ||
![]() |
5620f16330 | ||
![]() |
be024d4ad7 | ||
![]() |
75c740fe2b | ||
![]() |
6c8d86bb90 | ||
![]() |
b253a6b71e | ||
![]() |
ca7b4df812 | ||
![]() |
bc8dd57236 | ||
![]() |
f4f461b8bb | ||
![]() |
cbb9b6957f | ||
![]() |
f6b56c9317 | ||
![]() |
3717fb6c8d | ||
![]() |
f6abbc01bd | ||
![]() |
57a71c157d | ||
![]() |
cc76aeb7bb | ||
![]() |
811cabf8a9 | ||
![]() |
bf8d2f93d2 | ||
![]() |
07d8259ad6 | ||
![]() |
a00d412008 | ||
![]() |
5fb39658f1 | ||
![]() |
b0703b92c3 | ||
![]() |
dd9fd3d8a7 | ||
![]() |
cf0c59864f | ||
![]() |
4c0404c70d | ||
![]() |
573a413ee1 | ||
![]() |
f633e6ca49 | ||
![]() |
07b06d76be | ||
![]() |
856fe2da15 | ||
![]() |
f82aae65cd | ||
![]() |
3fbd11a104 | ||
![]() |
58a99f1907 | ||
![]() |
cf86dfd317 | ||
![]() |
a057b4f6d8 | ||
![]() |
62b03cfddf | ||
![]() |
18b827b979 | ||
![]() |
0a379fc514 | ||
![]() |
445c11b8d9 | ||
![]() |
8d290ad509 | ||
![]() |
b90c48b50f | ||
![]() |
d19e7db09e | ||
![]() |
9939904b02 | ||
![]() |
ca23b15f5c | ||
![]() |
ffa676f577 | ||
![]() |
6d023c4df3 | ||
![]() |
b31bd37a30 | ||
![]() |
78faee8c7c | ||
![]() |
40e2a703d0 | ||
![]() |
b01edcb9bc | ||
![]() |
f7fffc9be8 | ||
![]() |
50e8634097 | ||
![]() |
e3994e517e | ||
![]() |
2bb7785189 | ||
![]() |
90c8408111 | ||
![]() |
64786ec12a | ||
![]() |
b3c82f8886 | ||
![]() |
063259dc52 | ||
![]() |
b4c9d9c2a7 | ||
![]() |
fa2b59df4b | ||
![]() |
f41a169460 | ||
![]() |
f567083006 | ||
![]() |
a2a677e539 | ||
![]() |
9123c0b733 | ||
![]() |
788e3b31e1 | ||
![]() |
71f0ed8b74 | ||
![]() |
ac2e4e593d | ||
![]() |
edaa7d7748 | ||
![]() |
3cdf965fba | ||
![]() |
6b60d1e71f | ||
![]() |
7b7fb5acd5 | ||
![]() |
0a7d612f41 | ||
![]() |
38da76bbe0 | ||
![]() |
a13e045742 | ||
![]() |
811620c0a0 | ||
![]() |
504f5f7bdd | ||
![]() |
32bcad51b8 | ||
![]() |
a40510c241 | ||
![]() |
ac8dce6599 | ||
![]() |
190d525099 | ||
![]() |
1b6666fa39 | ||
![]() |
1dd01c99e8 | ||
![]() |
d50b30a498 | ||
![]() |
42a3a87f13 | ||
![]() |
9dfedbe619 | ||
![]() |
88957b4c9d | ||
![]() |
b2f2c9322b | ||
![]() |
3be2051808 | ||
![]() |
ff32b0dc9b | ||
![]() |
c1869a11af | ||
![]() |
e22a4fdba4 | ||
![]() |
29a7b2c5b5 | ||
![]() |
3b6c285c2a | ||
![]() |
575d1786af | ||
![]() |
bc1c927952 | ||
![]() |
f95bc85f91 | ||
![]() |
4015195314 | ||
![]() |
c3d883c6cb | ||
![]() |
097e30321b | ||
![]() |
b6ddeaacf2 | ||
![]() |
b0c60ec124 | ||
![]() |
f3b788703e | ||
![]() |
4bb83781e8 | ||
![]() |
a73195b7cc | ||
![]() |
1bd00b8a9a | ||
![]() |
d84eaeafc5 | ||
![]() |
20ae84bff9 | ||
![]() |
7372c931b3 | ||
![]() |
29e1b6e465 | ||
![]() |
eda06993f8 | ||
![]() |
4b30ef1cf2 | ||
![]() |
e92e5e8eb8 | ||
![]() |
4e5271fcdf | ||
![]() |
3c55487a16 | ||
![]() |
76a1cae5d8 | ||
![]() |
81a97315e3 | ||
![]() |
53c14d97a6 | ||
![]() |
69a82eec17 | ||
![]() |
45cadef22f | ||
![]() |
0a033fb10a | ||
![]() |
591afa0647 | ||
![]() |
05eac20ffe | ||
![]() |
38d263ac19 | ||
![]() |
f71c204eef | ||
![]() |
51147203be | ||
![]() |
a931686317 | ||
![]() |
5bd322bdcf | ||
![]() |
bb097109f0 | ||
![]() |
2ab6c40ff1 | ||
![]() |
68bb738af2 | ||
![]() |
6b968beede | ||
![]() |
f68dd1bffb | ||
![]() |
f92b71ca99 | ||
![]() |
2b79fe2d6a | ||
![]() |
44dd9af276 | ||
![]() |
d3013d4f8c | ||
![]() |
678524ad21 | ||
![]() |
32a64481f2 | ||
![]() |
1776015c6c | ||
![]() |
f1c71a26e3 | ||
![]() |
e78ab767d3 | ||
![]() |
f01eb2f95d | ||
![]() |
1450e45d97 | ||
![]() |
ec8cba369c | ||
![]() |
f4c248f406 | ||
![]() |
f3b2a58646 | ||
![]() |
c6f89c42b2 | ||
![]() |
5e93cfdd9e | ||
![]() |
d91d5a3ab5 | ||
![]() |
907c045f33 | ||
![]() |
90f189eb54 | ||
![]() |
4abd5b2112 | ||
![]() |
df9a665994 | ||
![]() |
7a098ca0ed | ||
![]() |
33716732a1 | ||
![]() |
97ae594375 | ||
![]() |
3f321ae9a0 | ||
![]() |
161d32a7e7 | ||
![]() |
d7137586a9 | ||
![]() |
cd0c06ba6e | ||
![]() |
899ab63d91 | ||
![]() |
1097820a5a | ||
![]() |
39114f91a7 | ||
![]() |
4f01387edf | ||
![]() |
de3e0585f1 | ||
![]() |
f85f25ba82 | ||
![]() |
10a2c179f9 | ||
![]() |
6eea56861b | ||
![]() |
21fd2064ae | ||
![]() |
dcbab8e37a | ||
![]() |
5677278251 | ||
![]() |
a83bee993d | ||
![]() |
96a31f554a | ||
![]() |
d14ec6aea5 | ||
![]() |
917cedf893 | ||
![]() |
193dd71600 | ||
![]() |
6c293a3d7f | ||
![]() |
e847ddf011 | ||
![]() |
7e8b448985 | ||
![]() |
d1f3a87c08 | ||
![]() |
9f8145e590 | ||
![]() |
791efc171a | ||
![]() |
144312a525 | ||
![]() |
92684112ed | ||
![]() |
ef114ee6cb | ||
![]() |
667f209742 | ||
![]() |
4ad0747c78 | ||
![]() |
c5cf66402c | ||
![]() |
05417049eb | ||
![]() |
c7b0c46d9f | ||
![]() |
df578c91ad | ||
![]() |
70008c47c9 | ||
![]() |
938affef32 | ||
![]() |
a3c33000ee | ||
![]() |
1e54b7b294 | ||
![]() |
cc0dbcf3f4 | ||
![]() |
c5a2cadccc | ||
![]() |
9aa43416b6 | ||
![]() |
8364029db8 | ||
![]() |
d842d21be0 | ||
![]() |
3514fd2433 | ||
![]() |
6778ff27ea | ||
![]() |
f32315d699 | ||
![]() |
8b754b24b6 | ||
![]() |
b1bee9ff38 | ||
![]() |
569be2d402 | ||
![]() |
78a73eac53 | ||
![]() |
533cb99c33 | ||
![]() |
79726940dc | ||
![]() |
27c7891169 | ||
![]() |
7a3a793a12 | ||
![]() |
8088469eca | ||
![]() |
3dcb082015 | ||
![]() |
bece023028 | ||
![]() |
9c4df66925 | ||
![]() |
2b43ceb6c6 | ||
![]() |
c143adba91 | ||
![]() |
142fdc8d86 | ||
![]() |
67778dcd3d |
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
dist: trusty
|
||||||
|
language: cpp
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- libcppunit-dev
|
||||||
|
- libboost-dev
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- MAKEFLAGS="-j2"
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# C++14
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get update -qq
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew update
|
||||||
|
|
||||||
|
install:
|
||||||
|
# C++14
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get install -qq g++-5
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || brew install cppunit
|
||||||
|
|
||||||
|
script:
|
||||||
|
- OPTIONS="--enable-test"
|
||||||
|
- test "$TRAVIS_OS_NAME" != "linux" || export CC=gcc-5 CXX=g++-5
|
||||||
|
- test "$TRAVIS_OS_NAME" != "osx" || OPTIONS="$OPTIONS --enable-osx"
|
||||||
|
- ./autogen.sh
|
||||||
|
- ./configure --disable-silent-rules --disable-dependency-tracking $OPTIONS
|
||||||
|
- make
|
||||||
|
- make check
|
3
AUTHORS
3
AUTHORS
@@ -5,7 +5,7 @@ The following people have contributed code to MPD:
|
|||||||
|
|
||||||
Warren Dukes <warren.dukes@gmail.com>
|
Warren Dukes <warren.dukes@gmail.com>
|
||||||
Avuton Olrich <avuton@gmail.com>
|
Avuton Olrich <avuton@gmail.com>
|
||||||
Max Kellermann <max@duempel.org>
|
Max Kellermann <max.kellermann@gmail.com>
|
||||||
Laszlo Ashin <kodest@gmail.com>
|
Laszlo Ashin <kodest@gmail.com>
|
||||||
Viliam Mateicka <viliam.mateicka@gmail.com>
|
Viliam Mateicka <viliam.mateicka@gmail.com>
|
||||||
Eric Wollesen <encoded@xmtp.net>
|
Eric Wollesen <encoded@xmtp.net>
|
||||||
@@ -30,3 +30,4 @@ The following people have contributed code to MPD:
|
|||||||
Jurgen Kramer <gtmkramer@xs4all.nl>
|
Jurgen Kramer <gtmkramer@xs4all.nl>
|
||||||
Jean-Francois Dockes <jf@dockes.org>
|
Jean-Francois Dockes <jf@dockes.org>
|
||||||
Yue Wang <yuleopen@gmail.com>
|
Yue Wang <yuleopen@gmail.com>
|
||||||
|
Matthew Leon Grinshpun <ml@matthewleon.com>
|
||||||
|
206
INSTALL
206
INSTALL
@@ -1,206 +0,0 @@
|
|||||||
Music Player Daemon (MPD) - INSTALL
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
------------
|
|
||||||
|
|
||||||
This document is a very small amount of documentation about what is needed to
|
|
||||||
install MPD. If more information is desired, read the user manual:
|
|
||||||
|
|
||||||
http://www.musicpd.org/doc/user/
|
|
||||||
|
|
||||||
Dependencies
|
|
||||||
------------
|
|
||||||
|
|
||||||
gcc 4.7 or later - http://gcc.gnu.org/
|
|
||||||
clang 3.2 or later - http://clang.llvm.org/
|
|
||||||
Any other C++11 compliant compiler should also work.
|
|
||||||
|
|
||||||
Boost 1.46 - http://www.boost.org/
|
|
||||||
|
|
||||||
|
|
||||||
Optional Output Dependencies
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
You will need at least one of these to compile MPD.
|
|
||||||
|
|
||||||
Most of these are available as packages on major distributions. Be sure to
|
|
||||||
install both the library package as well as the development package.
|
|
||||||
|
|
||||||
AO - http://www.xiph.org/ao/
|
|
||||||
A portable library that abstracts many audio output types as one API. Should
|
|
||||||
be used only if there is no native plugin available or if the native plugin
|
|
||||||
doesn't work. You will need libao.
|
|
||||||
|
|
||||||
ALSA - http://www.alsa-project.org/
|
|
||||||
The Advanced Linux Sound Architecture. Recommended audio output if you use
|
|
||||||
Linux. You will need libasound.
|
|
||||||
|
|
||||||
FIFO
|
|
||||||
This is a mostly undocumented, developer plugin to transmit raw data.
|
|
||||||
|
|
||||||
OSS - http://www.opensound.com
|
|
||||||
Open Sound System.
|
|
||||||
|
|
||||||
PulseAudio - http://www.pulseaudio.org/
|
|
||||||
An advanced sound daemon. You will need libpulse.
|
|
||||||
|
|
||||||
JACK - http://www.jackaudio.org/
|
|
||||||
A low-latency sound daemon.
|
|
||||||
|
|
||||||
libshout - http://www.icecast.org/
|
|
||||||
For streaming to an Icecast or Shoutcast server.
|
|
||||||
You also need an encoder: either libvorbisenc (ogg), or liblame (mp3).
|
|
||||||
|
|
||||||
OpenAL - http://kcat.strangesoft.net/openal.html
|
|
||||||
Open Audio Library
|
|
||||||
|
|
||||||
|
|
||||||
Optional Input Dependencies
|
|
||||||
---------------------------
|
|
||||||
|
|
||||||
You will need at least one of these to compile MPD.
|
|
||||||
|
|
||||||
Most of these are available as packages on major distributions. Be sure to
|
|
||||||
install both the library package as well as the development package.
|
|
||||||
|
|
||||||
MAD - http://www.underbit.com/products/mad/
|
|
||||||
For MP3 support. You will need libmad, and optionally libid3tag if you want
|
|
||||||
ID3 tag support.
|
|
||||||
|
|
||||||
libmpg123 - http://www.mpg123.de/
|
|
||||||
Alternative for MP3 support.
|
|
||||||
|
|
||||||
Ogg Vorbis - http://www.xiph.org/ogg/vorbis/
|
|
||||||
For Ogg Vorbis support. You will need libogg and libvorbis.
|
|
||||||
|
|
||||||
libopus - http://www.opus-codec.org/
|
|
||||||
Opus codec support
|
|
||||||
|
|
||||||
FLAC - http://flac.sourceforge.net/
|
|
||||||
For FLAC support. You will need version 1.2 or higher of libFLAC.
|
|
||||||
|
|
||||||
Audio File - http://www.68k.org/~michael/audiofile/
|
|
||||||
For WAVE, AIFF, and AU support. You will need libaudiofile.
|
|
||||||
|
|
||||||
FAAD2 - http://www.audiocoding.com/
|
|
||||||
For MP4/AAC support.
|
|
||||||
|
|
||||||
libmpcdec - http://www.musepack.net/
|
|
||||||
For Musepack support.
|
|
||||||
|
|
||||||
MikMod - http://mikmod.raphnet.net/
|
|
||||||
For MOD support. You will need libmikmod.
|
|
||||||
|
|
||||||
libavcodec, libavformat (ffmpeg or libav) - http://ffmpeg.mplayerhq.hu/ http://libav.org/
|
|
||||||
Multi-codec library.
|
|
||||||
|
|
||||||
libsidplay2 - http://sidplay2.sourceforge.net/
|
|
||||||
For C64 SID support.
|
|
||||||
|
|
||||||
libfluidsynth - http://fluidsynth.resonance.org/
|
|
||||||
For MIDI support.
|
|
||||||
|
|
||||||
libwildmidi 0.2.3 - http://wildmidi.sourceforge.net/
|
|
||||||
For MIDI support.
|
|
||||||
|
|
||||||
libsndfile - http://www.mega-nerd.com/libsndfile/
|
|
||||||
WAVE, AIFF, and many others.
|
|
||||||
|
|
||||||
libwavpack - http://www.wavpack.com/
|
|
||||||
For WavPack playback.
|
|
||||||
|
|
||||||
libadplug - http://adplug.sourceforge.net/
|
|
||||||
For AdLib playback.
|
|
||||||
|
|
||||||
|
|
||||||
Optional Miscellaneous Dependencies
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
Avahi - http://www.avahi.org/
|
|
||||||
For Zeroconf support.
|
|
||||||
|
|
||||||
libsamplerate - http://www.mega-nerd.com/SRC/
|
|
||||||
For advanced samplerate conversions.
|
|
||||||
|
|
||||||
libcurl - http://curl.haxx.se/
|
|
||||||
For playing HTTP streams.
|
|
||||||
|
|
||||||
libmms - https://launchpad.net/libmms
|
|
||||||
For playing MMS streams.
|
|
||||||
|
|
||||||
SQLite - http://www.sqlite.org/
|
|
||||||
For the sticker database.
|
|
||||||
|
|
||||||
libcdio - http://www.gnu.org/software/libcdio/
|
|
||||||
For playing audio CDs.
|
|
||||||
|
|
||||||
libsystemd-daemon - http://freedesktop.org/wiki/Software/systemd/
|
|
||||||
For systemd activation.
|
|
||||||
|
|
||||||
|
|
||||||
pkg-config
|
|
||||||
----------
|
|
||||||
|
|
||||||
MPD uses pkg-config to locate most external libraries. If you do not
|
|
||||||
have pkg-config, or if your version of the library does not ship the
|
|
||||||
".pc" file, you have to provide the library's build options in
|
|
||||||
environment variables. These variables are documented in "./configure
|
|
||||||
--help". Example:
|
|
||||||
|
|
||||||
FLAC_CFLAGS=-I/usr/include/FLAC FLAC_LIBS=-lFLAC ./configure
|
|
||||||
|
|
||||||
|
|
||||||
Download
|
|
||||||
--------
|
|
||||||
|
|
||||||
Get the latest release from of MPD from <http://www.musicpd.org/>.
|
|
||||||
|
|
||||||
Compile
|
|
||||||
-------
|
|
||||||
|
|
||||||
1) unpack the archive
|
|
||||||
|
|
||||||
$ tar xf mpd-x.x.x.tar.xz
|
|
||||||
|
|
||||||
2) change to directory created
|
|
||||||
|
|
||||||
$ cd mpd-x.x.x
|
|
||||||
|
|
||||||
3) Run configure script (this will determine what dependencies you have)
|
|
||||||
|
|
||||||
$ ./configure
|
|
||||||
|
|
||||||
4) Compile
|
|
||||||
|
|
||||||
$ make
|
|
||||||
|
|
||||||
Install (Optional)
|
|
||||||
-------
|
|
||||||
|
|
||||||
(as root)
|
|
||||||
$ make install
|
|
||||||
|
|
||||||
Run
|
|
||||||
---
|
|
||||||
|
|
||||||
1) run mpd:
|
|
||||||
|
|
||||||
$ mpd <config file>
|
|
||||||
|
|
||||||
First default is $XDG_CONFIG_HOME/mpd/mpd.conf then ~/.mpdconf then
|
|
||||||
~/.mpd/mpd.conf then /etc/mpd.conf. If neither of these exist a mpd
|
|
||||||
configuration file must be specified at runtime.
|
|
||||||
|
|
||||||
A sample config file is included with the source of MPD, mpdconf.example.
|
|
||||||
|
|
||||||
The first time MPD is run it will attempt to discover all music in your
|
|
||||||
music root, recursively. This can be affected by the symbolic link
|
|
||||||
options specified in the example mpd.conf.
|
|
||||||
|
|
||||||
Using MPD
|
|
||||||
---------
|
|
||||||
|
|
||||||
You can download many different interfaces for MPD at
|
|
||||||
|
|
||||||
http://www.musicpd.org/clients/
|
|
20
Makefile.am
20
Makefile.am
@@ -243,6 +243,7 @@ CURL_SOURCES = \
|
|||||||
src/lib/curl/Slist.hxx
|
src/lib/curl/Slist.hxx
|
||||||
|
|
||||||
UPNP_SOURCES = \
|
UPNP_SOURCES = \
|
||||||
|
src/lib/upnp/Compat.hxx \
|
||||||
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
|
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
|
||||||
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
|
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
|
||||||
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
|
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
|
||||||
@@ -415,6 +416,7 @@ libutil_a_SOURCES = \
|
|||||||
src/util/CharUtil.hxx \
|
src/util/CharUtil.hxx \
|
||||||
src/util/NumberParser.hxx \
|
src/util/NumberParser.hxx \
|
||||||
src/util/MimeType.cxx src/util/MimeType.hxx \
|
src/util/MimeType.cxx src/util/MimeType.hxx \
|
||||||
|
src/util/StringBuffer.hxx \
|
||||||
src/util/StringPointer.hxx \
|
src/util/StringPointer.hxx \
|
||||||
src/util/StringView.cxx src/util/StringView.hxx \
|
src/util/StringView.cxx src/util/StringView.hxx \
|
||||||
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
|
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
|
||||||
@@ -517,6 +519,8 @@ libevent_a_SOURCES = \
|
|||||||
# UTF-8 library
|
# UTF-8 library
|
||||||
|
|
||||||
libicu_a_SOURCES = \
|
libicu_a_SOURCES = \
|
||||||
|
src/lib/icu/CaseFold.cxx src/lib/icu/CaseFold.hxx \
|
||||||
|
src/lib/icu/Compare.cxx src/lib/icu/Compare.hxx \
|
||||||
src/lib/icu/Collate.cxx src/lib/icu/Collate.hxx \
|
src/lib/icu/Collate.cxx src/lib/icu/Collate.hxx \
|
||||||
src/lib/icu/Converter.cxx src/lib/icu/Converter.hxx
|
src/lib/icu/Converter.cxx src/lib/icu/Converter.hxx
|
||||||
|
|
||||||
@@ -539,6 +543,10 @@ ICU_LDADD = libicu.a $(ICU_LIBS)
|
|||||||
# PCM library
|
# PCM library
|
||||||
|
|
||||||
libpcm_a_SOURCES = \
|
libpcm_a_SOURCES = \
|
||||||
|
src/CheckAudioFormat.cxx src/CheckAudioFormat.hxx \
|
||||||
|
src/AudioFormat.cxx src/AudioFormat.hxx \
|
||||||
|
src/AudioParser.cxx src/AudioParser.hxx \
|
||||||
|
src/pcm/SampleFormat.cxx src/pcm/SampleFormat.hxx \
|
||||||
src/pcm/Traits.hxx \
|
src/pcm/Traits.hxx \
|
||||||
src/pcm/Interleave.cxx src/pcm/Interleave.hxx \
|
src/pcm/Interleave.cxx src/pcm/Interleave.hxx \
|
||||||
src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
|
src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
|
||||||
@@ -575,6 +583,8 @@ PCM_LIBS = \
|
|||||||
|
|
||||||
if ENABLE_DSD
|
if ENABLE_DSD
|
||||||
libpcm_a_SOURCES += \
|
libpcm_a_SOURCES += \
|
||||||
|
src/pcm/Dsd16.cxx src/pcm/Dsd16.hxx \
|
||||||
|
src/pcm/Dsd32.cxx src/pcm/Dsd32.hxx \
|
||||||
src/pcm/PcmDsd.cxx src/pcm/PcmDsd.hxx \
|
src/pcm/PcmDsd.cxx src/pcm/PcmDsd.hxx \
|
||||||
src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h
|
src/pcm/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h
|
||||||
endif
|
endif
|
||||||
@@ -613,7 +623,8 @@ libxiph_a_SOURCES += \
|
|||||||
src/lib/xiph/OggStreamState.hxx
|
src/lib/xiph/OggStreamState.hxx
|
||||||
endif
|
endif
|
||||||
|
|
||||||
XIPH_LIBS = libxiph.a
|
XIPH_LIBS = libxiph.a \
|
||||||
|
$(OGG_LIBS)
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -869,9 +880,6 @@ ARCHIVE_LIBS =
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
libbasic_a_SOURCES = \
|
libbasic_a_SOURCES = \
|
||||||
src/CheckAudioFormat.cxx src/CheckAudioFormat.hxx \
|
|
||||||
src/AudioFormat.cxx src/AudioFormat.hxx \
|
|
||||||
src/AudioParser.cxx src/AudioParser.hxx \
|
|
||||||
src/ReplayGainConfig.hxx \
|
src/ReplayGainConfig.hxx \
|
||||||
src/ReplayGainMode.cxx src/ReplayGainMode.hxx \
|
src/ReplayGainMode.cxx src/ReplayGainMode.hxx \
|
||||||
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx
|
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx
|
||||||
@@ -918,6 +926,7 @@ libtag_a_SOURCES =\
|
|||||||
src/tag/ReplayGain.cxx src/tag/ReplayGain.hxx \
|
src/tag/ReplayGain.cxx src/tag/ReplayGain.hxx \
|
||||||
src/tag/MixRamp.cxx src/tag/MixRamp.hxx \
|
src/tag/MixRamp.cxx src/tag/MixRamp.hxx \
|
||||||
src/tag/Generic.cxx src/tag/Generic.hxx \
|
src/tag/Generic.cxx src/tag/Generic.hxx \
|
||||||
|
src/tag/Id3MusicBrainz.cxx src/tag/Id3MusicBrainz.hxx \
|
||||||
src/tag/ApeLoader.cxx src/tag/ApeLoader.hxx \
|
src/tag/ApeLoader.cxx src/tag/ApeLoader.hxx \
|
||||||
src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
|
src/tag/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
|
||||||
src/tag/ApeTag.cxx src/tag/ApeTag.hxx
|
src/tag/ApeTag.cxx src/tag/ApeTag.hxx
|
||||||
@@ -1484,6 +1493,8 @@ liboutput_plugins_a_SOURCES += \
|
|||||||
src/output/plugins/OSXOutputPlugin.cxx \
|
src/output/plugins/OSXOutputPlugin.cxx \
|
||||||
src/output/plugins/OSXOutputPlugin.hxx
|
src/output/plugins/OSXOutputPlugin.hxx
|
||||||
endif
|
endif
|
||||||
|
libmixer_plugins_a_SOURCES += \
|
||||||
|
src/mixer/plugins/OSXMixerPlugin.cxx
|
||||||
|
|
||||||
if ENABLE_PULSE
|
if ENABLE_PULSE
|
||||||
liboutput_plugins_a_SOURCES += \
|
liboutput_plugins_a_SOURCES += \
|
||||||
@@ -2225,6 +2236,7 @@ test_test_icy_parser_LDADD = \
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
test_test_pcm_SOURCES = \
|
test_test_pcm_SOURCES = \
|
||||||
|
test/TestAudioFormat.cxx test/TestAudioFormat.hxx \
|
||||||
test/test_pcm_util.hxx \
|
test/test_pcm_util.hxx \
|
||||||
test/test_pcm_dither.cxx \
|
test/test_pcm_dither.cxx \
|
||||||
test/test_pcm_pack.cxx \
|
test/test_pcm_pack.cxx \
|
||||||
|
116
NEWS
116
NEWS
@@ -1,3 +1,119 @@
|
|||||||
|
ver 0.20.12 (2017/11/25)
|
||||||
|
* database
|
||||||
|
- upnp: adapt to libupnp 1.8 API changes
|
||||||
|
* input
|
||||||
|
- cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention,
|
||||||
|
fixing lots of xrun problems
|
||||||
|
- curl: fix seeking
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: fix GCC 8 warning
|
||||||
|
- vorbis: fix Tremor support
|
||||||
|
* player
|
||||||
|
- log message when decoder is too slow
|
||||||
|
* encoder
|
||||||
|
- vorbis: default to quality 3
|
||||||
|
* output
|
||||||
|
- fix hanging playback with soxr resampler
|
||||||
|
- httpd: flush encoder after tag; fixes corrupt Vorbis stream
|
||||||
|
|
||||||
|
ver 0.20.11 (2017/10/18)
|
||||||
|
* storage
|
||||||
|
- curl: support Content-Type application/xml
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: more reliable song duration
|
||||||
|
- gme: fix track numbering
|
||||||
|
* improve random song order when switching songs manually
|
||||||
|
* fix case insensitive search without libicu
|
||||||
|
* fix Unicode file names in playlists on Windows
|
||||||
|
* fix endless loop when accessing malformed file names in ZIP files
|
||||||
|
|
||||||
|
ver 0.20.10 (2017/08/24)
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: support MusicBrainz ID3v2 tags
|
||||||
|
* tags
|
||||||
|
- aiff: fix FORM chunk size endianess (is big-endian)
|
||||||
|
* mixer
|
||||||
|
- osx: add a mixer for OSX.
|
||||||
|
* fix crash when resuming playback before decoder is ready
|
||||||
|
* fix crash on Windows
|
||||||
|
|
||||||
|
ver 0.20.9 (2017/06/04)
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: support *.adx
|
||||||
|
* fix byte order detection on FreeBSD/aarch64
|
||||||
|
* fix more random crashes when compiled with clang
|
||||||
|
|
||||||
|
ver 0.20.8 (2017/05/19)
|
||||||
|
* output
|
||||||
|
- osx: fix build failure due to missing "noexcept"
|
||||||
|
* playlist
|
||||||
|
- m3u: support MIME type `audio/mpegurl`
|
||||||
|
* fix build failure with GCC 4.x
|
||||||
|
|
||||||
|
ver 0.20.7 (2017/05/15)
|
||||||
|
* database
|
||||||
|
- simple: fix false positive directory loop detection with NFS
|
||||||
|
* enforce a reasonable minimum audio_buffer_size setting
|
||||||
|
* cap buffer_before_play at 80% to prevent deadlock
|
||||||
|
* fix random crashes when compiled with clang
|
||||||
|
|
||||||
|
ver 0.20.6 (2017/03/10)
|
||||||
|
* input
|
||||||
|
- curl: fix headers after HTTP redirect to Shoutcast server
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: re-enable as fallback
|
||||||
|
- mpcdec: fix crash (division by zero) after seeking
|
||||||
|
- sidplay: make compatible with libsidplayfp < 1.8
|
||||||
|
* fix stream tags after automatic song change
|
||||||
|
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
|
||||||
|
|
||||||
|
ver 0.20.5 (2017/02/20)
|
||||||
|
* tags
|
||||||
|
- id3: fix memory leak on corrupt ID3 tags
|
||||||
|
* decoder
|
||||||
|
- sidplay: don't require libsidutils when building with libsidplayfp
|
||||||
|
* output
|
||||||
|
- httpd: fix two buffer overflows in IcyMetaData length calculation
|
||||||
|
* mixer
|
||||||
|
- alsa: fix crash bug
|
||||||
|
|
||||||
|
ver 0.20.4 (2017/02/01)
|
||||||
|
* input
|
||||||
|
- nfs: fix freeze after reconnect
|
||||||
|
* output
|
||||||
|
- sndio: work around a libroar C++ incompatibility
|
||||||
|
* workaround for GCC 4.9 "constexpr" bug
|
||||||
|
* fix FreeBSD build failure
|
||||||
|
|
||||||
|
ver 0.20.3 (2017/01/25)
|
||||||
|
* protocol
|
||||||
|
- "playlistadd" creates new playlist if it does not exist, as documented
|
||||||
|
* database
|
||||||
|
- proxy: fix error "terminate called after throwing ..."
|
||||||
|
- proxy: make connect errors during startup non-fatal
|
||||||
|
* neighbor
|
||||||
|
- upnp: fix premature expiry
|
||||||
|
* replay gain: don't reset ReplayGain levels when unpausing playback
|
||||||
|
* silence surround channels when converting from stereo
|
||||||
|
* use shortcuts such as "dsd64" in log messages
|
||||||
|
|
||||||
|
ver 0.20.2 (2017/01/15)
|
||||||
|
* input
|
||||||
|
- alsa: fix crash bug
|
||||||
|
- alsa: fix buffer overruns
|
||||||
|
* decoder
|
||||||
|
- flac: add options "probesize" and "analyzeduration"
|
||||||
|
* resampler
|
||||||
|
- libsamplerate: reset state after seeking
|
||||||
|
* output
|
||||||
|
- fix static noise after changing to a different audio format
|
||||||
|
- alsa: fix the DSD_U32 sample rate
|
||||||
|
- alsa: fix the DSD_U32 byte order
|
||||||
|
- alsa: support DSD_U16
|
||||||
|
- recorder: fix error "Failed to create : No such file or directory"
|
||||||
|
* playlist
|
||||||
|
- cue: fix skipping songs
|
||||||
|
|
||||||
ver 0.20.1 (2017/01/09)
|
ver 0.20.1 (2017/01/09)
|
||||||
* input
|
* input
|
||||||
- curl: fix crash bug
|
- curl: fix crash bug
|
||||||
|
@@ -7,14 +7,15 @@ server's audio device. The daemon stores info about all available music,
|
|||||||
and this info can be easily searched and retrieved. Player control, info
|
and this info can be easily searched and retrieved. Player control, info
|
||||||
retrieval, and playlist management can all be managed remotely.
|
retrieval, and playlist management can all be managed remotely.
|
||||||
|
|
||||||
For basic installation information see the INSTALL file.
|
For basic installation instructions
|
||||||
|
[read the manual](https://www.musicpd.org/doc/user/install.html).
|
||||||
|
|
||||||
# Users
|
# Users
|
||||||
|
|
||||||
- [Manual](http://www.musicpd.org/doc/user/)
|
- [Manual](http://www.musicpd.org/doc/user/)
|
||||||
- [Forum](http://forum.musicpd.org/)
|
- [Forum](http://forum.musicpd.org/)
|
||||||
- [IRC](irc://chat.freenode.net/#mpd)
|
- [IRC](irc://chat.freenode.net/#mpd)
|
||||||
- [Bug tracker](http://bugs.musicpd.org/)
|
- [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
|
||||||
|
|
||||||
# Developers
|
# Developers
|
||||||
|
|
||||||
|
@@ -87,9 +87,14 @@ class AndroidNdkToolchain:
|
|||||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||||
self.is_windows = False
|
self.is_windows = False
|
||||||
|
|
||||||
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
|
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
|
||||||
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
|
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
|
||||||
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
|
|
||||||
|
libstdcxx_cppflags = '-nostdinc++ -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
||||||
|
libstdcxx_ldadd = os.path.join(libcxx_libs_path, 'libc++_static.a') + ' ' + os.path.join(libcxx_libs_path, 'libc++abi.a')
|
||||||
|
|
||||||
|
if self.is_armv7:
|
||||||
|
libstdcxx_ldadd += ' ' + os.path.join(libcxx_libs_path, 'libunwind.a')
|
||||||
|
|
||||||
if use_cxx:
|
if use_cxx:
|
||||||
self.libs += ' ' + libstdcxx_ldadd
|
self.libs += ' ' + libstdcxx_ldadd
|
||||||
@@ -149,5 +154,9 @@ configure = [
|
|||||||
|
|
||||||
] + configure_args
|
] + configure_args
|
||||||
|
|
||||||
|
from build.cmdline import concatenate_cmdline_variables
|
||||||
|
configure = concatenate_cmdline_variables(configure,
|
||||||
|
set(('CFLAGS', 'CXXFLAGS', 'CPPFLAGS', 'LDFLAGS', 'LIBS')))
|
||||||
|
|
||||||
subprocess.check_call(configure, env=toolchain.env)
|
subprocess.check_call(configure, env=toolchain.env)
|
||||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
||||||
|
12
configure.ac
12
configure.ac
@@ -1,10 +1,10 @@
|
|||||||
AC_PREREQ(2.60)
|
AC_PREREQ(2.60)
|
||||||
|
|
||||||
AC_INIT(mpd, 0.20.1, musicpd-dev-team@lists.sourceforge.net)
|
AC_INIT(mpd, 0.20.12, musicpd-dev-team@lists.sourceforge.net)
|
||||||
|
|
||||||
VERSION_MAJOR=0
|
VERSION_MAJOR=0
|
||||||
VERSION_MINOR=20
|
VERSION_MINOR=20
|
||||||
VERSION_REVISION=1
|
VERSION_REVISION=12
|
||||||
VERSION_EXTRA=0
|
VERSION_EXTRA=0
|
||||||
|
|
||||||
AC_CONFIG_SRCDIR([src/Main.cxx])
|
AC_CONFIG_SRCDIR([src/Main.cxx])
|
||||||
@@ -241,6 +241,7 @@ AC_CHECK_FUNCS(getpwnam_r getpwuid_r)
|
|||||||
AC_CHECK_FUNCS(initgroups)
|
AC_CHECK_FUNCS(initgroups)
|
||||||
AC_CHECK_FUNCS(fnmatch)
|
AC_CHECK_FUNCS(fnmatch)
|
||||||
AC_CHECK_FUNCS(strndup)
|
AC_CHECK_FUNCS(strndup)
|
||||||
|
AC_CHECK_FUNCS(strcasestr)
|
||||||
|
|
||||||
if test x$host_is_linux = xyes; then
|
if test x$host_is_linux = xyes; then
|
||||||
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
|
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
|
||||||
@@ -992,7 +993,7 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
|
|||||||
dnl --------------------------------- sidplay ---------------------------------
|
dnl --------------------------------- sidplay ---------------------------------
|
||||||
if test x$enable_sidplay != xno; then
|
if test x$enable_sidplay != xno; then
|
||||||
dnl Check for libsidplayfp first
|
dnl Check for libsidplayfp first
|
||||||
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils],
|
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp],
|
||||||
[found_sidplayfp=yes],
|
[found_sidplayfp=yes],
|
||||||
[found_sidplayfp=no])
|
[found_sidplayfp=no])
|
||||||
found_sidplay=$found_sidplayfp
|
found_sidplay=$found_sidplayfp
|
||||||
@@ -1384,6 +1385,11 @@ then
|
|||||||
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
|
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
|
||||||
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
|
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
|
||||||
AX_APPEND_COMPILE_FLAGS([-Wsign-compare])
|
AX_APPEND_COMPILE_FLAGS([-Wsign-compare])
|
||||||
|
|
||||||
|
dnl This GCC8 warning for C++17 ABI compatibility is of no
|
||||||
|
dnl interest for us, because we're not a shared library.
|
||||||
|
AX_APPEND_COMPILE_FLAGS([-Wno-noexcept-type])
|
||||||
|
|
||||||
AC_LANG_POP
|
AC_LANG_POP
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@@ -97,20 +97,20 @@ Foo(const char *abc, int xyz)
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
MPD sources are managed in a git repository on <ulink
|
MPD sources are managed in a git repository on <ulink
|
||||||
url="http://git.musicpd.org/">git.musicpd.org</ulink>.
|
url="https://github.com/MusicPlayerDaemon/">GitHub</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Always write your code against the latest git:
|
Always write your code against the latest git:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>git clone git://git.musicpd.org/master/mpd.git</programlisting>
|
<programlisting>git clone git://github.com/MusicPlayerDaemon/MPD</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
If you already have a clone, update it:
|
If you already have a clone, update it:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>git pull --rebase git://git.musicpd.org/master/mpd.git master</programlisting>
|
<programlisting>git pull --rebase git://github.com/MusicPlayerDaemon/MPD master</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
You can do without "--rebase", but we recommend that you rebase
|
You can do without "--rebase", but we recommend that you rebase
|
||||||
@@ -188,17 +188,7 @@ Foo(const char *abc, int xyz)
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<command>git pull</command> requests are preferred. Regular
|
<command>git pull</command> requests are preferred.
|
||||||
contributors can get <ulink
|
|
||||||
url="http://git.musicpd.org/account-policy.html">an account on
|
|
||||||
git.musicpd.org</ulink>, but any public git repository will do.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
There is <ulink url="https://github.com/MaxKellermann/MPD">a
|
|
||||||
mirror of the <application>MPD</application> git repository on
|
|
||||||
GitHub</ulink>, and you can use that as well to submit pull
|
|
||||||
requests.
|
|
||||||
</para>
|
</para>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
|
@@ -55,7 +55,8 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<varname>track</varname>: the track number within the album.
|
<varname>track</varname>: the decimal track number within the
|
||||||
|
album.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
@@ -103,7 +104,8 @@
|
|||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<varname>disc</varname>: the disc number in a multi-disc album.
|
<varname>disc</varname>: the decimal disc number in a multi-disc
|
||||||
|
album.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
|
|
||||||
|
@@ -48,8 +48,8 @@ mpd.conf(5), mpc(1)
|
|||||||
.SH BUGS
|
.SH BUGS
|
||||||
If you find a bug, please report it at
|
If you find a bug, please report it at
|
||||||
.br
|
.br
|
||||||
<\fBhttp://bugs.musicpd.org/bug_report_page.php\fP>.
|
<\fBhttps://github.com/MusicPlayerDaemon/MPD/issues/\fP>.
|
||||||
.SH AUTHORS
|
.SH AUTHORS
|
||||||
Max Kellermann <max@duempel.org>
|
Max Kellermann <max.kellermann@gmail.com>
|
||||||
|
|
||||||
Special thanks to all the people that provided feedback and patches.
|
Special thanks to all the people that provided feedback and patches.
|
||||||
|
@@ -403,6 +403,15 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Change events accumulate, even while the connection is
|
||||||
|
not in "idle" mode; no events gets lost while the client
|
||||||
|
is doing something else with the connection. If an
|
||||||
|
event had already occurred since the last call, the new
|
||||||
|
<command>idle</command> command will return immediately.
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
While a client is waiting for <command>idle</command>
|
While a client is waiting for <command>idle</command>
|
||||||
results, the server disables timeouts, allowing a client
|
results, the server disables timeouts, allowing a client
|
||||||
@@ -436,7 +445,9 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<varname>volume</varname>:
|
<varname>volume</varname>:
|
||||||
<returnvalue>0-100</returnvalue>
|
<returnvalue>0-100</returnvalue> or
|
||||||
|
<returnvalue>-1</returnvalue> if the volume cannot
|
||||||
|
be determined
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
@@ -573,7 +584,12 @@
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
<varname>audio</varname>:
|
<varname>audio</varname>:
|
||||||
<returnvalue>sampleRate:bits:channels</returnvalue>
|
<returnvalue>
|
||||||
|
The format emitted by the decoder plugin during
|
||||||
|
playback, format:
|
||||||
|
"<replaceable>samplerate:bits:channels</replaceable>".
|
||||||
|
Check the user manual for a detailed explanation.
|
||||||
|
</returnvalue>
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
481
doc/user.xml
481
doc/user.xml
@@ -80,13 +80,40 @@
|
|||||||
cd mpd-version</programlisting>
|
cd mpd-version</programlisting>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Make sure that all the required libraries and build tools are
|
In any case, you need:
|
||||||
installed. The <filename>INSTALL</filename> file has a list.
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
a C++14 compiler (e.g. <ulink
|
||||||
|
url="http://gcc.gnu.org/">gcc 4.9</ulink> or <ulink
|
||||||
|
url="http://clang.llvm.org/">clang 3.9</ulink>)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<ulink url="http://www.boost.org/">Boost 1.46</ulink>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<ulink url="https://www.freedesktop.org/wiki/Software/pkg-config/">pkg-config</ulink>
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Each plugin usually needs a codec library, which you also need
|
||||||
|
to install. Check the plugin reference for details about
|
||||||
|
required libraries.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
For example, the following installs a fairly complete list of
|
For example, the following installs a fairly complete list of
|
||||||
build dependencies on Debian Wheezy:
|
build dependencies on Debian Jessie:
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@@ -98,19 +125,20 @@ apt-get install g++ \
|
|||||||
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 \
|
||||||
libmp3lame-dev \
|
libmp3lame-dev libtwolame-dev libshine-dev \
|
||||||
libsamplerate0-dev libsoxr-dev \
|
libsamplerate0-dev libsoxr-dev \
|
||||||
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
|
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
|
||||||
libzzip-dev \
|
libzzip-dev \
|
||||||
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
|
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
|
||||||
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
|
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
|
||||||
libpulse-dev libroar-dev libshout3-dev \
|
libpulse-dev libroar-dev libshout3-dev \
|
||||||
|
libsndio-dev \
|
||||||
libmpdclient-dev \
|
libmpdclient-dev \
|
||||||
libnfs-dev libsmbclient-dev \
|
libnfs-dev libsmbclient-dev \
|
||||||
libupnp-dev \
|
libupnp-dev \
|
||||||
libavahi-client-dev \
|
libavahi-client-dev \
|
||||||
libsqlite3-dev \
|
libsqlite3-dev \
|
||||||
libsystemd-daemon-dev libwrap0-dev \
|
libsystemd-dev libwrap0-dev \
|
||||||
libcppunit-dev xmlto \
|
libcppunit-dev xmlto \
|
||||||
libboost-dev \
|
libboost-dev \
|
||||||
libicu-dev
|
libicu-dev
|
||||||
@@ -135,6 +163,91 @@ apt-get install g++ \
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<programlisting>make install</programlisting>
|
<programlisting>make install</programlisting>
|
||||||
|
|
||||||
|
<section id="windows_build">
|
||||||
|
<title>Compiling for Windows</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Even though it does not "feel" like a Windows application,
|
||||||
|
<application>MPD</application> works well under Windows.
|
||||||
|
Its build process follows the "Linux style", and may seem
|
||||||
|
awkward for Windows people (who are not used to compiling
|
||||||
|
their software, anyway).
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Basically, there are three ways to compile
|
||||||
|
<application>MPD</application> for Windows:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<orderedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Build on Windows for Windows. All you need to do is
|
||||||
|
described above already: configure and make.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For Windows users, this is kind of unusual, because few
|
||||||
|
Windows users have a GNU toolchain and a UNIX shell
|
||||||
|
installed.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Build on Linux for Windows. This is described above
|
||||||
|
already: configure and make. You need the <ulink
|
||||||
|
url="https://mingw-w64.org/"><application>mingw-w64</application>
|
||||||
|
cross compiler</ulink>. Pass
|
||||||
|
<parameter>--host=i686-w64-mingw32</parameter> (32 bit)
|
||||||
|
or <parameter>--host=x86_64-w64-mingw32</parameter> (64
|
||||||
|
bit) to configure.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This is somewhat natural for Linux users. Many
|
||||||
|
distributions have <application>mingw-w64</application>
|
||||||
|
packages. The remaining difficulty here is installing
|
||||||
|
all the external libraries. And
|
||||||
|
<application>MPD</application> usually needs many,
|
||||||
|
making this method cumbersome for the casual user.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Build on Linux for Windows using the
|
||||||
|
<application>MPD</application>'s library build script.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</orderedlist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This section is about the latter.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Just like with the native build, unpack the
|
||||||
|
<application>MPD</application> source tarball and change
|
||||||
|
into the directory. Then, instead of
|
||||||
|
<command>./configure</command>, type:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<programlisting>./win32/build.py --64</programlisting>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
This downloads various library sources, and then configures
|
||||||
|
and builds <application>MPD</application> (for x64; to build
|
||||||
|
a 32 bit binary, pass <parameter>--32</parameter>). The
|
||||||
|
resulting EXE files is linked statically, i.e. it contains
|
||||||
|
all the libraries already, and you do not need carry DLLs
|
||||||
|
around. It is large, but easy to use. If you wish to have
|
||||||
|
a small <filename>mpd.exe</filename> with DLLs, you need to
|
||||||
|
compile manually, without the <filename>build.py</filename>
|
||||||
|
script.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="systemd_socket">
|
<section id="systemd_socket">
|
||||||
@@ -576,10 +689,11 @@ systemctl start mpd.socket</programlisting>
|
|||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
<para>
|
<para>
|
||||||
Always open the audio output with the specified audio
|
Always open the audio output with the specified
|
||||||
format (samplerate:bits:channels), regardless of the
|
audio format
|
||||||
format of the input file. This is optional for most
|
(<replaceable>samplerate:bits:channels</replaceable>),
|
||||||
plugins.
|
regardless of the format of the input file. This is
|
||||||
|
optional for most plugins.
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Any of the three attributes may be an asterisk to
|
Any of the three attributes may be an asterisk to
|
||||||
@@ -596,7 +710,20 @@ systemctl start mpd.socket</programlisting>
|
|||||||
24 bit integer samples padded to 32 bit),
|
24 bit integer samples padded to 32 bit),
|
||||||
<varname>32</varname> (signed 32 bit integer
|
<varname>32</varname> (signed 32 bit integer
|
||||||
samples), <varname>f</varname> (32 bit floating
|
samples), <varname>f</varname> (32 bit floating
|
||||||
point, -1.0 to 1.0).
|
point, -1.0 to 1.0), "<varname>dsd</varname>" means
|
||||||
|
DSD (Direct Stream Digital). For DSD, there are
|
||||||
|
special cases such as "<varname>dsd64</varname>",
|
||||||
|
which allows you to omit the sample rate
|
||||||
|
(e.g. <parameter>dsd512:2</parameter> for stereo
|
||||||
|
DSD512, i.e. 22.5792 MHz).
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The sample rate is special for DSD:
|
||||||
|
<application>MPD</application> counts the number of
|
||||||
|
bytes, not bits. Thus, a DSD "bit" rate of 22.5792
|
||||||
|
MHz (DSD512) is 2822400 from
|
||||||
|
<application>MPD</application>'s point of view
|
||||||
|
(44100*512/8).
|
||||||
</para>
|
</para>
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
@@ -742,9 +869,11 @@ systemctl start mpd.socket</programlisting>
|
|||||||
<title>Configuring playlist plugins</title>
|
<title>Configuring playlist plugins</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Playlist plugins are used to load remote playlists. This is
|
Playlist plugins are used to load remote playlists (protocol
|
||||||
not related to <application>MPD</application>'s playlist
|
commands <command>load</command>,
|
||||||
directory.
|
<command>listplaylist</command> and
|
||||||
|
<command>listplaylistinfo</command>). This is not related to
|
||||||
|
<application>MPD</application>'s playlist directory.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -934,6 +1063,40 @@ systemctl start mpd.socket</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="stickers">
|
||||||
|
<title>The Sticker Database</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
"Stickers" are pieces of information attached to songs.
|
||||||
|
Some clients use them to store ratings and other volatile
|
||||||
|
data. This feature requires <ulink
|
||||||
|
url="http://www.sqlite.org/">SQLite</ulink>, compile-time
|
||||||
|
configure option <parameter>--enable-sqlite</parameter>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>sticker_file</varname>
|
||||||
|
<parameter>PATH</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
The location of the sticker database.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title>Resource Limitations</title>
|
<title>Resource Limitations</title>
|
||||||
|
|
||||||
@@ -1064,6 +1227,55 @@ systemctl start mpd.socket</programlisting>
|
|||||||
</tgroup>
|
</tgroup>
|
||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="zeroconf">
|
||||||
|
<title>Zeroconf</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If Zeroconf support (<ulink
|
||||||
|
url="http://avahi.org/">Avahi</ulink> or Apple's Bonjour)
|
||||||
|
was enabled at compile time with
|
||||||
|
<parameter>--with-zeroconf=...</parameter>, MPD can announce
|
||||||
|
its presence on the network. The following settings control
|
||||||
|
this feature:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>zeroconf_enabled</varname>
|
||||||
|
<parameter>yes|no</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Enables or disables this feature. Default is
|
||||||
|
<parameter>yes</parameter>.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>zeroconf_name</varname>
|
||||||
|
<parameter>NAME</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
The service name to publish via Zeroconf. The
|
||||||
|
default is "<parameter>Music Player</parameter>".
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
||||||
@@ -1646,7 +1858,7 @@ buffer_size: 16384</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
If you believe you found a bug in
|
If you believe you found a bug in
|
||||||
<application>MPD</application>, report it on <ulink
|
<application>MPD</application>, report it on <ulink
|
||||||
url="https://bugs.musicpd.org/my_view_page.php">the bug
|
url="https://github.com/MusicPlayerDaemon/MPD/issues/">the bug
|
||||||
tracker</ulink>.
|
tracker</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -1800,6 +2012,13 @@ run</programlisting>
|
|||||||
database.
|
database.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
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 ~/.curlrc will be in effect.
|
||||||
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
<tgroup cols="2">
|
<tgroup cols="2">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -1970,7 +2189,9 @@ run</programlisting>
|
|||||||
<title><varname>cdio_paranoia</varname></title>
|
<title><varname>cdio_paranoia</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Plays audio CDs. The URI has the form:
|
Plays audio CDs using <ulink
|
||||||
|
url="http://www.gnu.org/software/libcdio/"><filename>libcdio</filename></ulink>.
|
||||||
|
The URI has the form:
|
||||||
"<filename>cdda://[DEVICE][/TRACK]</filename>". The
|
"<filename>cdda://[DEVICE][/TRACK]</filename>". The
|
||||||
simplest form <filename>cdda://</filename> plays the whole
|
simplest form <filename>cdda://</filename> plays the whole
|
||||||
disc in the default drive.
|
disc in the default drive.
|
||||||
@@ -2006,7 +2227,8 @@ run</programlisting>
|
|||||||
<title><varname>curl</varname></title>
|
<title><varname>curl</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Opens remote files or streams over HTTP.
|
Opens remote files or streams over HTTP using <ulink
|
||||||
|
url="http://curl.haxx.se/"><filename>libcurl</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -2099,7 +2321,8 @@ run</programlisting>
|
|||||||
<title><varname>mms</varname></title>
|
<title><varname>mms</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Plays streams with the MMS protocol.
|
Plays streams with the MMS protocol using <ulink
|
||||||
|
url="https://launchpad.net/libmms"><filename>libmms</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2155,7 +2378,8 @@ run</programlisting>
|
|||||||
<title><varname>adplug</varname></title>
|
<title><varname>adplug</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes AdLib files.
|
Decodes AdLib files using <ulink
|
||||||
|
url="http://adplug.sourceforge.net/">libadplug</ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -2186,8 +2410,8 @@ run</programlisting>
|
|||||||
<title><varname>audiofile</varname></title>
|
<title><varname>audiofile</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WAV and AIFF files using
|
Decodes WAV and AIFF files using <ulink
|
||||||
<filename>libaudiofile</filename>.
|
url="http://audiofile.68k.org/"><filename>libaudiofile</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2195,7 +2419,8 @@ run</programlisting>
|
|||||||
<title><varname>faad</varname></title>
|
<title><varname>faad</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes AAC files using <filename>libfaad</filename>.
|
Decodes AAC files using <ulink
|
||||||
|
url="http://www.audiocoding.com/"><filename>libfaad</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2203,9 +2428,51 @@ run</programlisting>
|
|||||||
<title><varname>ffmpeg</varname></title>
|
<title><varname>ffmpeg</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes various codecs using
|
Decodes various codecs using <ulink
|
||||||
<application>FFmpeg</application>.
|
url="https://ffmpeg.org/"><application>FFmpeg</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>analyzeduration</varname>
|
||||||
|
<parameter>VALUE</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the FFmpeg muxer option
|
||||||
|
<varname>analyzeduration</varname>, which specifies
|
||||||
|
how many microseconds are analyzed to probe the
|
||||||
|
input. The <ulink
|
||||||
|
url="https://ffmpeg.org/ffmpeg-formats.html">FFmpeg
|
||||||
|
formats documentation</ulink> has more information.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>probesize</varname>
|
||||||
|
<parameter>VALUE</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the FFmpeg muxer option
|
||||||
|
<varname>probesize</varname>, which specifies
|
||||||
|
probing size in bytes, i.e. the size of the data to
|
||||||
|
analyze to get stream information. The <ulink
|
||||||
|
url="https://ffmpeg.org/ffmpeg-formats.html">FFmpeg
|
||||||
|
formats documentation</ulink> has more information.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="flac_decoder">
|
<section id="flac_decoder">
|
||||||
@@ -2213,7 +2480,7 @@ run</programlisting>
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes FLAC files using
|
Decodes FLAC files using
|
||||||
<application>libFLAC</application>.
|
<ulink url="https://xiph.org/flac/"><application>libFLAC</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2333,7 +2600,8 @@ run</programlisting>
|
|||||||
<title><varname>mad</varname></title>
|
<title><varname>mad</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes MP3 files using <application>libmad</application>.
|
Decodes MP3 files using <ulink
|
||||||
|
url="http://www.underbit.com/products/mad/"><application>libmad</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2413,8 +2681,8 @@ run</programlisting>
|
|||||||
<title><varname>mpcdec</varname></title>
|
<title><varname>mpcdec</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes Musepack files using
|
Decodes Musepack files using <ulink
|
||||||
<application>libmpcdec</application>.
|
url="http://www.musepack.net/"><application>libmpcdec</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2422,7 +2690,17 @@ run</programlisting>
|
|||||||
<title><varname>mpg123</varname></title>
|
<title><varname>mpg123</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes MP3 files using <application>libmpg123</application>.
|
Decodes MP3 files using <ulink
|
||||||
|
url="http://www.mpg123.de/"><application>libmpg123</application></ulink>.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section id="opus_decoder">
|
||||||
|
<title><varname>opus</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Decodes Opus files using <ulink
|
||||||
|
url="http://www.opus-codec.org/"><application>libopus</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2442,8 +2720,8 @@ run</programlisting>
|
|||||||
<title><varname>sidplay</varname></title>
|
<title><varname>sidplay</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
C64 SID decoder based on
|
C64 SID decoder based on <ulink
|
||||||
<application>libsidplay</application>.
|
url="http://sidplay2.sourceforge.net/"><application>libsidplay</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -2499,8 +2777,8 @@ run</programlisting>
|
|||||||
<title><varname>sndfile</varname></title>
|
<title><varname>sndfile</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WAV and AIFF files using
|
Decodes WAV and AIFF files using <ulink
|
||||||
<filename>libsndfile</filename>.
|
url="http://www.mega-nerd.com/libsndfile/"><filename>libsndfile</filename></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2508,8 +2786,8 @@ run</programlisting>
|
|||||||
<title><varname>vorbis</varname></title>
|
<title><varname>vorbis</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes Ogg-Vorbis files using
|
Decodes Ogg-Vorbis files using <ulink
|
||||||
<application>libvorbis</application>.
|
url="http://www.xiph.org/ogg/vorbis/"><application>libvorbis</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2518,7 +2796,7 @@ run</programlisting>
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Decodes WavPack files using
|
Decodes WavPack files using
|
||||||
<application>libwavpack</application>.
|
<ulink url="http://www.wavpack.com/"><application>libwavpack</application></ulink>.
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -2713,6 +2991,60 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section id="opus_encoder">
|
||||||
|
<title><varname>opus</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Encodes into <ulink
|
||||||
|
url="http://www.opus-codec.org/">Ogg Opus</ulink>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>bitrate</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the data rate in bit per second. The special
|
||||||
|
value "auto" lets <application>libopus</application>
|
||||||
|
choose a rate (which is the default), and "max" uses
|
||||||
|
the maximum possible data rate.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>complexity</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the <ulink
|
||||||
|
url="https://wiki.xiph.org/OpusFAQ#What_is_the_complexity_of_Opus.3F">Opus
|
||||||
|
complexity</ulink>.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>signal</varname>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
Sets the Opus signal type. Valid values are "auto"
|
||||||
|
(the default), "voice" and "music".
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section id="vorbis_encoder">
|
<section id="vorbis_encoder">
|
||||||
<title><varname>vorbis</varname></title>
|
<title><varname>vorbis</varname></title>
|
||||||
|
|
||||||
@@ -2736,8 +3068,8 @@ run</programlisting>
|
|||||||
</entry>
|
</entry>
|
||||||
<entry>
|
<entry>
|
||||||
Sets the quality for VBR. -1 is the lowest quality,
|
Sets the quality for VBR. -1 is the lowest quality,
|
||||||
10 is the highest quality. Cannot be used with
|
10 is the highest quality. Defaults to 3. Cannot
|
||||||
<varname>bitrate</varname>.
|
be used with <varname>bitrate</varname>.
|
||||||
</entry>
|
</entry>
|
||||||
</row>
|
</row>
|
||||||
<row>
|
<row>
|
||||||
@@ -3342,7 +3674,7 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section id="jack_output">
|
||||||
<title><varname>jack</varname></title>
|
<title><varname>jack</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -3622,7 +3954,7 @@ run</programlisting>
|
|||||||
</informaltable>
|
</informaltable>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section id="openal_output">
|
||||||
<title><varname>openal</varname></title>
|
<title><varname>openal</varname></title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -3773,7 +4105,7 @@ run</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
The <varname>pulse</varname> plugin connects to a <ulink
|
The <varname>pulse</varname> plugin connects to a <ulink
|
||||||
url="http://www.freedesktop.org/wiki/Software/PulseAudio/"><application>PulseAudio</application></ulink>
|
url="http://www.freedesktop.org/wiki/Software/PulseAudio/"><application>PulseAudio</application></ulink>
|
||||||
server.
|
server. Requires <filename>libpulse</filename>.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<informaltable>
|
<informaltable>
|
||||||
@@ -3930,7 +4262,7 @@ run</programlisting>
|
|||||||
(logical "and") can be used to select portions of
|
(logical "and") can be used to select portions of
|
||||||
the format string depending on the existing tag
|
the format string depending on the existing tag
|
||||||
values. Example:
|
values. Example:
|
||||||
<parameter>~/.mpd/recorder/[%title|%name%].ogg</parameter>
|
<parameter>~/.mpd/recorder/[%title%|%name%].ogg</parameter>
|
||||||
(use the "name" tag if no title exists)
|
(use the "name" tag if no title exists)
|
||||||
</para>
|
</para>
|
||||||
</entry>
|
</entry>
|
||||||
@@ -3961,7 +4293,8 @@ run</programlisting>
|
|||||||
url="http://www.shoutcast.com/"><application>ShoutCast</application></ulink>
|
url="http://www.shoutcast.com/"><application>ShoutCast</application></ulink>
|
||||||
or <ulink
|
or <ulink
|
||||||
url="http://icecast.org/"><application>IceCast</application></ulink>
|
url="http://icecast.org/"><application>IceCast</application></ulink>
|
||||||
server. It forwards tags to this server.
|
server using <filename>libshout</filename>. It forwards
|
||||||
|
tags to this server.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@@ -4151,6 +4484,22 @@ run</programlisting>
|
|||||||
<section id="playlist_plugins">
|
<section id="playlist_plugins">
|
||||||
<title>Playlist plugins</title>
|
<title>Playlist plugins</title>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title><varname>asx</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Reads <filename>.asx</filename> playlist files.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title><varname>cue</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Reads <filename>.cue</filename> files.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title><varname>embcue</varname></title>
|
<title><varname>embcue</varname></title>
|
||||||
|
|
||||||
@@ -4175,6 +4524,15 @@ run</programlisting>
|
|||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title><varname>flac</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Reads the <varname>cuesheet</varname> metablock from a FLAC
|
||||||
|
file.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title><varname>pls</varname></title>
|
<title><varname>pls</varname></title>
|
||||||
|
|
||||||
@@ -4183,6 +4541,45 @@ run</programlisting>
|
|||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title><varname>rss</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Reads music links from <filename>.rss</filename> files.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<title><varname>soundcloud</varname></title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Download playlist from SoundCloud. It accepts URIs starting
|
||||||
|
with <filename>soundcloud://</filename>.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<informaltable>
|
||||||
|
<tgroup cols="2">
|
||||||
|
<thead>
|
||||||
|
<row>
|
||||||
|
<entry>Setting</entry>
|
||||||
|
<entry>Description</entry>
|
||||||
|
</row>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<row>
|
||||||
|
<entry>
|
||||||
|
<varname>apikey</varname>
|
||||||
|
<parameter>KEY</parameter>
|
||||||
|
</entry>
|
||||||
|
<entry>
|
||||||
|
An API key to access the SoundCloud servers.
|
||||||
|
</entry>
|
||||||
|
</row>
|
||||||
|
</tbody>
|
||||||
|
</tgroup>
|
||||||
|
</informaltable>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
<title><varname>xspf</varname></title>
|
<title><varname>xspf</varname></title>
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# Check if "struct ucred" is available.
|
# Check if "struct ucred" is available.
|
||||||
#
|
#
|
||||||
# Author: Max Kellermann <max@duempel.org>
|
# Author: Max Kellermann <max.kellermann@gmail.com>
|
||||||
|
|
||||||
AC_DEFUN([STRUCT_UCRED],[
|
AC_DEFUN([STRUCT_UCRED],[
|
||||||
AC_MSG_CHECKING([for struct ucred])
|
AC_MSG_CHECKING([for struct ucred])
|
||||||
|
29
python/build/cmdline.py
Normal file
29
python/build/cmdline.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
def concatenate_cmdline_variables(src, names):
|
||||||
|
"""Find duplicate variable declarations on the given source list, and
|
||||||
|
concatenate the values of those in the 'names' list."""
|
||||||
|
|
||||||
|
# the result list being constructed
|
||||||
|
dest = []
|
||||||
|
|
||||||
|
# a map of variable name to destination list index
|
||||||
|
positions = {}
|
||||||
|
|
||||||
|
for item in src:
|
||||||
|
i = item.find('=')
|
||||||
|
if i > 0:
|
||||||
|
# it's a variable
|
||||||
|
name = item[:i]
|
||||||
|
if name in names:
|
||||||
|
# it's a known variable
|
||||||
|
if name in positions:
|
||||||
|
# already specified: concatenate instead of
|
||||||
|
# appending it
|
||||||
|
dest[positions[name]] += ' ' + item[i + 1:]
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# not yet seen: append it and remember the list
|
||||||
|
# index
|
||||||
|
positions[name] = len(dest)
|
||||||
|
dest.append(item)
|
||||||
|
|
||||||
|
return dest
|
@@ -19,8 +19,8 @@ libvorbis = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
opus = AutotoolsProject(
|
opus = AutotoolsProject(
|
||||||
'http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz',
|
'https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz',
|
||||||
'32bbb6b557fe1b6066adc0ae1f08b629',
|
'cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732',
|
||||||
'lib/libopus.a',
|
'lib/libopus.a',
|
||||||
['--disable-shared', '--enable-static'],
|
['--disable-shared', '--enable-static'],
|
||||||
)
|
)
|
||||||
@@ -36,8 +36,8 @@ flac = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
zlib = ZlibProject(
|
zlib = ZlibProject(
|
||||||
'http://zlib.net/zlib-1.2.8.tar.xz',
|
'http://zlib.net/zlib-1.2.11.tar.xz',
|
||||||
'28f1205d8dd2001f26fec1e8c2cebe37',
|
'4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066',
|
||||||
'lib/libz.a',
|
'lib/libz.a',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,9 +57,20 @@ libmad = AutotoolsProject(
|
|||||||
autogen=True,
|
autogen=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
liblame = AutotoolsProject(
|
||||||
|
'http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz',
|
||||||
|
'24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff',
|
||||||
|
'lib/libmp3lame.a',
|
||||||
|
[
|
||||||
|
'--disable-shared', '--enable-static',
|
||||||
|
'--disable-gtktest', '--disable-analyzer-hooks',
|
||||||
|
'--disable-decoder', '--disable-frontend',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
ffmpeg = FfmpegProject(
|
ffmpeg = FfmpegProject(
|
||||||
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz',
|
'http://ffmpeg.org/releases/ffmpeg-3.3.3.tar.xz',
|
||||||
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc',
|
'd2a9002cdc6b533b59728827186c044ad02ba64841f1b7cd6c21779875453a1e',
|
||||||
'lib/libavcodec.a',
|
'lib/libavcodec.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -82,8 +93,8 @@ ffmpeg = FfmpegProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
curl = AutotoolsProject(
|
curl = AutotoolsProject(
|
||||||
'http://curl.haxx.se/download/curl-7.52.1.tar.lzma',
|
'http://curl.haxx.se/download/curl-7.55.1.tar.xz',
|
||||||
'44286d4b825936e2430fc44ad730ce899afb736a5d328cbb8b5d42462f3f2365',
|
'3eafca6e84ecb4af5f35795dee84e643d5428287e88c041122bb8dac18676bb7',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'--disable-shared', '--enable-static',
|
'--disable-shared', '--enable-static',
|
||||||
@@ -103,7 +114,7 @@ curl = AutotoolsProject(
|
|||||||
)
|
)
|
||||||
|
|
||||||
boost = BoostProject(
|
boost = BoostProject(
|
||||||
'http://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.bz2',
|
'http://downloads.sourceforge.net/project/boost/boost/1.65.0/boost_1_65_0.tar.bz2',
|
||||||
'beae2529f759f6b3bf3f4969a19c2e9d6f0c503edcb2de4a61d1428519fcb3b0',
|
'ea26712742e2fb079c2a566a31f3266973b76e38222b9f88b387e3c8b2f9902c',
|
||||||
'include/boost/version.hpp',
|
'include/boost/version.hpp',
|
||||||
)
|
)
|
||||||
|
@@ -18,12 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
|
#include "util/StringBuffer.hxx"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
void
|
void
|
||||||
AudioFormat::ApplyMask(AudioFormat mask)
|
AudioFormat::ApplyMask(AudioFormat mask) noexcept
|
||||||
{
|
{
|
||||||
assert(IsValid());
|
assert(IsValid());
|
||||||
assert(mask.IsMaskValid());
|
assert(mask.IsMaskValid());
|
||||||
@@ -40,46 +41,24 @@ AudioFormat::ApplyMask(AudioFormat mask)
|
|||||||
assert(IsValid());
|
assert(IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
StringBuffer<24>
|
||||||
sample_format_to_string(SampleFormat format)
|
ToString(const AudioFormat af) noexcept
|
||||||
{
|
{
|
||||||
switch (format) {
|
StringBuffer<24> buffer;
|
||||||
case SampleFormat::UNDEFINED:
|
|
||||||
return "?";
|
|
||||||
|
|
||||||
case SampleFormat::S8:
|
if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
|
||||||
return "8";
|
af.sample_rate % 44100 == 0) {
|
||||||
|
/* use shortcuts such as "dsd64" which implies the
|
||||||
case SampleFormat::S16:
|
sample rate */
|
||||||
return "16";
|
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u",
|
||||||
|
af.sample_rate * 8 / 44100,
|
||||||
case SampleFormat::S24_P32:
|
af.channels);
|
||||||
return "24";
|
return buffer;
|
||||||
|
|
||||||
case SampleFormat::S32:
|
|
||||||
return "32";
|
|
||||||
|
|
||||||
case SampleFormat::FLOAT:
|
|
||||||
return "f";
|
|
||||||
|
|
||||||
case SampleFormat::DSD:
|
|
||||||
return "dsd";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* unreachable */
|
snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u",
|
||||||
assert(false);
|
|
||||||
gcc_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *
|
|
||||||
audio_format_to_string(const AudioFormat af,
|
|
||||||
struct audio_format_string *s)
|
|
||||||
{
|
|
||||||
assert(s != nullptr);
|
|
||||||
|
|
||||||
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
|
|
||||||
af.sample_rate, sample_format_to_string(af.format),
|
af.sample_rate, sample_format_to_string(af.format),
|
||||||
af.channels);
|
af.channels);
|
||||||
|
|
||||||
return s->buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@@ -20,47 +20,14 @@
|
|||||||
#ifndef MPD_AUDIO_FORMAT_HXX
|
#ifndef MPD_AUDIO_FORMAT_HXX
|
||||||
#define MPD_AUDIO_FORMAT_HXX
|
#define MPD_AUDIO_FORMAT_HXX
|
||||||
|
|
||||||
|
#include "pcm/SampleFormat.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
template<size_t CAPACITY> class StringBuffer;
|
||||||
/* on WIN32, "FLOAT" is already defined, and this triggers -Wshadow */
|
|
||||||
#pragma GCC diagnostic push
|
|
||||||
#pragma GCC diagnostic ignored "-Wshadow"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum class SampleFormat : uint8_t {
|
|
||||||
UNDEFINED = 0,
|
|
||||||
|
|
||||||
S8,
|
|
||||||
S16,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signed 24 bit integer samples, packed in 32 bit integers
|
|
||||||
* (the most significant byte is filled with the sign bit).
|
|
||||||
*/
|
|
||||||
S24_P32,
|
|
||||||
|
|
||||||
S32,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 32 bit floating point samples in the host's format. The
|
|
||||||
* range is -1.0f to +1.0f.
|
|
||||||
*/
|
|
||||||
FLOAT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direct Stream Digital. 1-bit samples; each frame has one
|
|
||||||
* byte (8 samples) per channel.
|
|
||||||
*/
|
|
||||||
DSD,
|
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static constexpr unsigned MAX_CHANNELS = 8;
|
static constexpr unsigned MAX_CHANNELS = 8;
|
||||||
|
|
||||||
@@ -157,10 +124,10 @@ struct AudioFormat {
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyMask(AudioFormat mask);
|
void ApplyMask(AudioFormat mask) noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
AudioFormat WithMask(AudioFormat mask) const {
|
AudioFormat WithMask(AudioFormat mask) const noexcept {
|
||||||
AudioFormat result = *this;
|
AudioFormat result = *this;
|
||||||
result.ApplyMask(mask);
|
result.ApplyMask(mask);
|
||||||
return result;
|
return result;
|
||||||
@@ -183,13 +150,6 @@ struct AudioFormat {
|
|||||||
double GetTimeToSize() const;
|
double GetTimeToSize() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Buffer for audio_format_string().
|
|
||||||
*/
|
|
||||||
struct audio_format_string {
|
|
||||||
char buffer[24];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the sample rate is valid.
|
* Checks whether the sample rate is valid.
|
||||||
*
|
*
|
||||||
@@ -201,28 +161,6 @@ audio_valid_sample_rate(unsigned sample_rate)
|
|||||||
return sample_rate > 0 && sample_rate < (1 << 30);
|
return sample_rate > 0 && sample_rate < (1 << 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the sample format is valid.
|
|
||||||
*/
|
|
||||||
static inline bool
|
|
||||||
audio_valid_sample_format(SampleFormat format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case SampleFormat::S8:
|
|
||||||
case SampleFormat::S16:
|
|
||||||
case SampleFormat::S24_P32:
|
|
||||||
case SampleFormat::S32:
|
|
||||||
case SampleFormat::FLOAT:
|
|
||||||
case SampleFormat::DSD:
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case SampleFormat::UNDEFINED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the number of channels is valid.
|
* Checks whether the number of channels is valid.
|
||||||
*/
|
*/
|
||||||
@@ -258,34 +196,6 @@ AudioFormat::IsMaskValid() const
|
|||||||
(channels == 0 || audio_valid_channel_count(channels));
|
(channels == 0 || audio_valid_channel_count(channels));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_const
|
|
||||||
static inline unsigned
|
|
||||||
sample_format_size(SampleFormat format)
|
|
||||||
{
|
|
||||||
switch (format) {
|
|
||||||
case SampleFormat::S8:
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SampleFormat::S16:
|
|
||||||
return 2;
|
|
||||||
|
|
||||||
case SampleFormat::S24_P32:
|
|
||||||
case SampleFormat::S32:
|
|
||||||
case SampleFormat::FLOAT:
|
|
||||||
return 4;
|
|
||||||
|
|
||||||
case SampleFormat::DSD:
|
|
||||||
/* each frame has 8 samples per channel */
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SampleFormat::UNDEFINED:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(false);
|
|
||||||
gcc_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned
|
inline unsigned
|
||||||
AudioFormat::GetSampleSize() const
|
AudioFormat::GetSampleSize() const
|
||||||
{
|
{
|
||||||
@@ -304,28 +214,15 @@ AudioFormat::GetTimeToSize() const
|
|||||||
return sample_rate * GetFrameSize();
|
return sample_rate * GetFrameSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders a #SampleFormat enum into a string, e.g. for printing it
|
|
||||||
* in a log file.
|
|
||||||
*
|
|
||||||
* @param format a #SampleFormat enum value
|
|
||||||
* @return the string
|
|
||||||
*/
|
|
||||||
gcc_pure gcc_malloc
|
|
||||||
const char *
|
|
||||||
sample_format_to_string(SampleFormat format);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the #AudioFormat object into a string, e.g. for printing
|
* Renders the #AudioFormat object into a string, e.g. for printing
|
||||||
* it in a log file.
|
* it in a log file.
|
||||||
*
|
*
|
||||||
* @param af the #AudioFormat object
|
* @param af the #AudioFormat object
|
||||||
* @param s a buffer to print into
|
* @return the string buffer
|
||||||
* @return the string, or nullptr if the #AudioFormat object is invalid
|
|
||||||
*/
|
*/
|
||||||
gcc_pure gcc_malloc
|
gcc_const
|
||||||
const char *
|
StringBuffer<24>
|
||||||
audio_format_to_string(AudioFormat af,
|
ToString(AudioFormat af) noexcept;
|
||||||
struct audio_format_string *s);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -137,6 +137,26 @@ ParseAudioFormat(const char *src, bool mask)
|
|||||||
AudioFormat dest;
|
AudioFormat dest;
|
||||||
dest.Clear();
|
dest.Clear();
|
||||||
|
|
||||||
|
if (strncmp(src, "dsd", 3) == 0) {
|
||||||
|
/* allow format specifications such as "dsd64" which
|
||||||
|
implies the sample rate */
|
||||||
|
|
||||||
|
char *endptr;
|
||||||
|
auto dsd = strtoul(src + 3, &endptr, 10);
|
||||||
|
if (endptr > src + 3 && *endptr == ':' &&
|
||||||
|
dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
|
||||||
|
dest.sample_rate = dsd * 44100 / 8;
|
||||||
|
dest.format = SampleFormat::DSD;
|
||||||
|
|
||||||
|
src = endptr + 1;
|
||||||
|
dest.channels = ParseChannelCount(src, mask, &src);
|
||||||
|
if (*src != 0)
|
||||||
|
throw FormatRuntimeError("Extra data after channel count: %s", src);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* parse sample rate */
|
/* parse sample rate */
|
||||||
|
|
||||||
dest.sample_rate = ParseSampleRate(src, mask, &src);
|
dest.sample_rate = ParseSampleRate(src, mask, &src);
|
||||||
|
@@ -25,8 +25,6 @@
|
|||||||
#ifndef MPD_AUDIO_PARSER_HXX
|
#ifndef MPD_AUDIO_PARSER_HXX
|
||||||
#define MPD_AUDIO_PARSER_HXX
|
#define MPD_AUDIO_PARSER_HXX
|
||||||
|
|
||||||
#include "Compiler.h"
|
|
||||||
|
|
||||||
struct AudioFormat;
|
struct AudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +36,6 @@ struct AudioFormat;
|
|||||||
* @param src the input string
|
* @param src the input string
|
||||||
* @param mask if true, then "*" is allowed for any number of items
|
* @param mask if true, then "*" is allowed for any number of items
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
AudioFormat
|
AudioFormat
|
||||||
ParseAudioFormat(const char *src, bool mask);
|
ParseAudioFormat(const char *src, bool mask);
|
||||||
|
|
||||||
|
@@ -107,7 +107,7 @@ static void version(void)
|
|||||||
"\n"
|
"\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||||
"Copyright (C) 2008-2015 Max Kellermann <max@duempel.org>\n"
|
"Copyright 2008-2017 Max Kellermann <max.kellermann@gmail.com>\n"
|
||||||
"This is free software; see the source for copying conditions. There is NO\n"
|
"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"
|
||||||
|
|
||||||
|
@@ -37,19 +37,19 @@ DetachedSong::~DetachedSong()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DetachedSong::IsRemote() const
|
DetachedSong::IsRemote() const noexcept
|
||||||
{
|
{
|
||||||
return uri_has_scheme(GetRealURI());
|
return uri_has_scheme(GetRealURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DetachedSong::IsAbsoluteFile() const
|
DetachedSong::IsAbsoluteFile() const noexcept
|
||||||
{
|
{
|
||||||
return PathTraitsUTF8::IsAbsolute(GetRealURI());
|
return PathTraitsUTF8::IsAbsolute(GetRealURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DetachedSong::IsInDatabase() const
|
DetachedSong::IsInDatabase() const noexcept
|
||||||
{
|
{
|
||||||
/* here, we use GetURI() and not GetRealURI() because
|
/* here, we use GetURI() and not GetRealURI() because
|
||||||
GetRealURI() is never relative */
|
GetRealURI() is never relative */
|
||||||
@@ -59,7 +59,7 @@ DetachedSong::IsInDatabase() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
SignedSongTime
|
SignedSongTime
|
||||||
DetachedSong::GetDuration() const
|
DetachedSong::GetDuration() const noexcept
|
||||||
{
|
{
|
||||||
SongTime a = start_time, b = end_time;
|
SongTime a = start_time, b = end_time;
|
||||||
if (!b.IsPositive()) {
|
if (!b.IsPositive()) {
|
||||||
|
@@ -63,18 +63,18 @@ class DetachedSong {
|
|||||||
|
|
||||||
Tag tag;
|
Tag tag;
|
||||||
|
|
||||||
time_t mtime;
|
time_t mtime = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start of this sub-song within the file.
|
* Start of this sub-song within the file.
|
||||||
*/
|
*/
|
||||||
SongTime start_time;
|
SongTime start_time = SongTime::zero();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* End of this sub-song within the file.
|
* End of this sub-song within the file.
|
||||||
* Unused if zero.
|
* Unused if zero.
|
||||||
*/
|
*/
|
||||||
SongTime end_time;
|
SongTime end_time = SongTime::zero();
|
||||||
|
|
||||||
explicit DetachedSong(const LightSong &other);
|
explicit DetachedSong(const LightSong &other);
|
||||||
|
|
||||||
@@ -82,33 +82,25 @@ public:
|
|||||||
explicit DetachedSong(const DetachedSong &) = default;
|
explicit DetachedSong(const DetachedSong &) = default;
|
||||||
|
|
||||||
explicit DetachedSong(const char *_uri)
|
explicit DetachedSong(const char *_uri)
|
||||||
:uri(_uri),
|
:uri(_uri) {}
|
||||||
mtime(0),
|
|
||||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
|
||||||
|
|
||||||
explicit DetachedSong(const std::string &_uri)
|
explicit DetachedSong(const std::string &_uri)
|
||||||
:uri(_uri),
|
:uri(_uri) {}
|
||||||
mtime(0),
|
|
||||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
|
||||||
|
|
||||||
explicit DetachedSong(std::string &&_uri)
|
explicit DetachedSong(std::string &&_uri)
|
||||||
:uri(std::move(_uri)),
|
:uri(std::move(_uri)) {}
|
||||||
mtime(0),
|
|
||||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
DetachedSong(U &&_uri, Tag &&_tag)
|
DetachedSong(U &&_uri, Tag &&_tag)
|
||||||
:uri(std::forward<U>(_uri)),
|
:uri(std::forward<U>(_uri)),
|
||||||
tag(std::move(_tag)),
|
tag(std::move(_tag)) {}
|
||||||
mtime(0),
|
|
||||||
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
|
|
||||||
|
|
||||||
DetachedSong(DetachedSong &&) = default;
|
DetachedSong(DetachedSong &&) = default;
|
||||||
|
|
||||||
~DetachedSong();
|
~DetachedSong();
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetURI() const {
|
const char *GetURI() const noexcept {
|
||||||
return uri.c_str();
|
return uri.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +114,7 @@ public:
|
|||||||
* displayed URI?
|
* displayed URI?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasRealURI() const {
|
bool HasRealURI() const noexcept {
|
||||||
return !real_uri.empty();
|
return !real_uri.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +123,7 @@ public:
|
|||||||
* GetURI().
|
* GetURI().
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetRealURI() const {
|
const char *GetRealURI() const noexcept {
|
||||||
return (HasRealURI() ? real_uri : uri).c_str();
|
return (HasRealURI() ? real_uri : uri).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,34 +137,36 @@ public:
|
|||||||
* song.
|
* song.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsSame(const DetachedSong &other) const {
|
bool IsSame(const DetachedSong &other) const noexcept {
|
||||||
return uri == other.uri;
|
return uri == other.uri &&
|
||||||
|
start_time == other.start_time &&
|
||||||
|
end_time == other.end_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull_all
|
gcc_pure gcc_nonnull_all
|
||||||
bool IsURI(const char *other_uri) const {
|
bool IsURI(const char *other_uri) const noexcept {
|
||||||
return uri == other_uri;
|
return uri == other_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsRemote() const;
|
bool IsRemote() const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsFile() const {
|
bool IsFile() const noexcept {
|
||||||
return !IsRemote();
|
return !IsRemote();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsAbsoluteFile() const;
|
bool IsAbsoluteFile() const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsInDatabase() const;
|
bool IsInDatabase() const noexcept;
|
||||||
|
|
||||||
const Tag &GetTag() const {
|
const Tag &GetTag() const noexcept {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tag &WritableTag() {
|
Tag &WritableTag() noexcept {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +215,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
SignedSongTime GetDuration() const;
|
SignedSongTime GetDuration() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the #tag and #mtime.
|
* Update the #tag and #mtime.
|
||||||
|
@@ -96,7 +96,7 @@ io_thread_deinit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
EventLoop &
|
EventLoop &
|
||||||
io_thread_get()
|
io_thread_get() noexcept
|
||||||
{
|
{
|
||||||
assert(io.loop != nullptr);
|
assert(io.loop != nullptr);
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ io_thread_get()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
io_thread_inside(void)
|
io_thread_inside() noexcept
|
||||||
{
|
{
|
||||||
return io.thread.IsInside();
|
return io.thread.IsInside();
|
||||||
}
|
}
|
||||||
|
@@ -51,13 +51,13 @@ io_thread_deinit();
|
|||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
EventLoop &
|
EventLoop &
|
||||||
io_thread_get();
|
io_thread_get() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the current thread the I/O thread?
|
* Is the current thread the I/O thread?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool
|
bool
|
||||||
io_thread_inside();
|
io_thread_inside() noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -46,13 +46,13 @@ static const char *const idle_names[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const char*const*
|
const char*const*
|
||||||
idle_get_names(void)
|
idle_get_names() noexcept
|
||||||
{
|
{
|
||||||
return idle_names;
|
return idle_names;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
idle_parse_name(const char *name)
|
idle_parse_name(const char *name) noexcept
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
|
@@ -70,8 +70,9 @@ static constexpr unsigned IDLE_MOUNT = 0x1000;
|
|||||||
/**
|
/**
|
||||||
* Get idle names
|
* Get idle names
|
||||||
*/
|
*/
|
||||||
|
gcc_const
|
||||||
const char*const*
|
const char*const*
|
||||||
idle_get_names();
|
idle_get_names() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an idle name and return its mask. Returns 0 if the given
|
* Parse an idle name and return its mask. Returns 0 if the given
|
||||||
@@ -79,6 +80,6 @@ idle_get_names();
|
|||||||
*/
|
*/
|
||||||
gcc_nonnull_all gcc_pure
|
gcc_nonnull_all gcc_pure
|
||||||
unsigned
|
unsigned
|
||||||
idle_parse_name(const char *name);
|
idle_parse_name(const char *name) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -117,7 +117,6 @@ struct Instance final
|
|||||||
* DatabaseError if this MPD configuration has no database (no
|
* DatabaseError if this MPD configuration has no database (no
|
||||||
* music_directory was configured).
|
* music_directory was configured).
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
47
src/Main.cxx
47
src/Main.cxx
@@ -117,7 +117,21 @@
|
|||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
|
static constexpr size_t KILOBYTE = 1024;
|
||||||
|
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
|
||||||
|
|
||||||
|
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
|
||||||
|
|
||||||
|
static
|
||||||
|
#if GCC_OLDER_THAN(5,0)
|
||||||
|
/* gcc 4.x has no "constexpr" for std::max() */
|
||||||
|
const
|
||||||
|
#else
|
||||||
|
constexpr
|
||||||
|
#endif
|
||||||
|
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
|
||||||
|
64 * KILOBYTE);
|
||||||
|
|
||||||
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@@ -130,7 +144,6 @@ struct Config {
|
|||||||
ReplayGainConfig replay_gain;
|
ReplayGainConfig replay_gain;
|
||||||
};
|
};
|
||||||
|
|
||||||
gcc_const
|
|
||||||
static Config
|
static Config
|
||||||
LoadConfig()
|
LoadConfig()
|
||||||
{
|
{
|
||||||
@@ -203,7 +216,11 @@ glue_db_init_and_load(void)
|
|||||||
"because the database does not need it");
|
"because the database does not need it");
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->database->Open();
|
try {
|
||||||
|
instance->database->Open();
|
||||||
|
} catch (...) {
|
||||||
|
std::throw_with_nested(std::runtime_error("Failed to open database plugin"));
|
||||||
|
}
|
||||||
|
|
||||||
if (!instance->database->IsPlugin(simple_db_plugin))
|
if (!instance->database->IsPlugin(simple_db_plugin))
|
||||||
return true;
|
return true;
|
||||||
@@ -303,12 +320,17 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
|
|||||||
FormatFatalError("buffer size \"%s\" is not a "
|
FormatFatalError("buffer size \"%s\" is not a "
|
||||||
"positive integer, line %i",
|
"positive integer, line %i",
|
||||||
param->value.c_str(), param->line);
|
param->value.c_str(), param->line);
|
||||||
buffer_size = tmp;
|
buffer_size = tmp * KILOBYTE;
|
||||||
|
|
||||||
|
if (buffer_size < MIN_BUFFER_SIZE) {
|
||||||
|
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
|
||||||
|
(unsigned long)buffer_size,
|
||||||
|
(unsigned long)MIN_BUFFER_SIZE);
|
||||||
|
buffer_size = MIN_BUFFER_SIZE;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
buffer_size = DEFAULT_BUFFER_SIZE;
|
buffer_size = DEFAULT_BUFFER_SIZE;
|
||||||
|
|
||||||
buffer_size *= 1024;
|
|
||||||
|
|
||||||
const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
|
const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
|
||||||
|
|
||||||
if (buffered_chunks >= 1 << 15)
|
if (buffered_chunks >= 1 << 15)
|
||||||
@@ -326,6 +348,19 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
|
|||||||
"than 100 percent, line %i",
|
"than 100 percent, line %i",
|
||||||
param->value.c_str(), param->line);
|
param->value.c_str(), param->line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (perc > 80) {
|
||||||
|
/* this upper limit should avoid deadlocks
|
||||||
|
which can occur because the DecoderThread
|
||||||
|
cannot ever fill the music buffer to
|
||||||
|
exactly 100%; a few chunks always need to
|
||||||
|
be available to generate silence in
|
||||||
|
Player::SendSilence() */
|
||||||
|
FormatError(config_domain,
|
||||||
|
"buffer_before_play is too large (%f%%), capping at 80%%; please fix your configuration",
|
||||||
|
perc);
|
||||||
|
perc = 80;
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
||||||
|
|
||||||
|
@@ -59,14 +59,14 @@ mapper_init(AllocatedPath &&_playlist_dir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mapper_finish()
|
mapper_finish() noexcept
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
AllocatedPath
|
AllocatedPath
|
||||||
map_uri_fs(const char *uri)
|
map_uri_fs(const char *uri) noexcept
|
||||||
{
|
{
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
assert(*uri != '/');
|
assert(*uri != '/');
|
||||||
@@ -86,7 +86,7 @@ map_uri_fs(const char *uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
map_fs_to_utf8(Path path_fs)
|
map_fs_to_utf8(Path path_fs) noexcept
|
||||||
{
|
{
|
||||||
if (path_fs.IsAbsolute()) {
|
if (path_fs.IsAbsolute()) {
|
||||||
if (instance->storage == nullptr)
|
if (instance->storage == nullptr)
|
||||||
@@ -109,13 +109,13 @@ map_fs_to_utf8(Path path_fs)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
const AllocatedPath &
|
const AllocatedPath &
|
||||||
map_spl_path()
|
map_spl_path() noexcept
|
||||||
{
|
{
|
||||||
return playlist_dir_fs;
|
return playlist_dir_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocatedPath
|
AllocatedPath
|
||||||
map_spl_utf8_to_fs(const char *name)
|
map_spl_utf8_to_fs(const char *name) noexcept
|
||||||
{
|
{
|
||||||
if (playlist_dir_fs.IsNull())
|
if (playlist_dir_fs.IsNull())
|
||||||
return AllocatedPath::Null();
|
return AllocatedPath::Null();
|
||||||
|
@@ -37,7 +37,7 @@ void
|
|||||||
mapper_init(AllocatedPath &&playlist_dir);
|
mapper_init(AllocatedPath &&playlist_dir);
|
||||||
|
|
||||||
void
|
void
|
||||||
mapper_finish();
|
mapper_finish() noexcept;
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ mapper_finish();
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
AllocatedPath
|
AllocatedPath
|
||||||
map_uri_fs(const char *uri);
|
map_uri_fs(const char *uri) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a file system path (relative to the music directory or
|
* Maps a file system path (relative to the music directory or
|
||||||
@@ -60,7 +60,7 @@ map_uri_fs(const char *uri);
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
std::string
|
std::string
|
||||||
map_fs_to_utf8(Path path_fs);
|
map_fs_to_utf8(Path path_fs) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ map_fs_to_utf8(Path path_fs);
|
|||||||
*/
|
*/
|
||||||
gcc_const
|
gcc_const
|
||||||
const AllocatedPath &
|
const AllocatedPath &
|
||||||
map_spl_path();
|
map_spl_path() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a playlist name (without the ".m3u" suffix) to a file system
|
* Maps a playlist name (without the ".m3u" suffix) to a file system
|
||||||
@@ -79,6 +79,6 @@ map_spl_path();
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
AllocatedPath
|
AllocatedPath
|
||||||
map_spl_utf8_to_fs(const char *name);
|
map_spl_utf8_to_fs(const char *name) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -31,45 +31,45 @@ class MixRampInfo {
|
|||||||
public:
|
public:
|
||||||
MixRampInfo() = default;
|
MixRampInfo() = default;
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
start.clear();
|
start.clear();
|
||||||
end.clear();
|
end.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsDefined() const {
|
bool IsDefined() const noexcept {
|
||||||
return !start.empty() || !end.empty();
|
return !start.empty() || !end.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetStart() const {
|
const char *GetStart() const noexcept {
|
||||||
return start.empty() ? nullptr : start.c_str();
|
return start.empty() ? nullptr : start.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetEnd() const {
|
const char *GetEnd() const noexcept {
|
||||||
return end.empty() ? nullptr : end.c_str();
|
return end.empty() ? nullptr : end.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStart(const char *new_value) {
|
void SetStart(const char *new_value) noexcept {
|
||||||
if (new_value == nullptr)
|
if (new_value == nullptr)
|
||||||
start.clear();
|
start.clear();
|
||||||
else
|
else
|
||||||
start = new_value;
|
start = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStart(std::string &&new_value) {
|
void SetStart(std::string &&new_value) noexcept {
|
||||||
start = std::move(new_value);
|
start = std::move(new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnd(const char *new_value) {
|
void SetEnd(const char *new_value) noexcept {
|
||||||
if (new_value == nullptr)
|
if (new_value == nullptr)
|
||||||
end.clear();
|
end.clear();
|
||||||
else
|
else
|
||||||
end = new_value;
|
end = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEnd(std::string &&new_value) {
|
void SetEnd(std::string &&new_value) noexcept {
|
||||||
end = std::move(new_value);
|
end = std::move(new_value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -23,19 +23,19 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
MusicBuffer::MusicBuffer(unsigned num_chunks) noexcept
|
||||||
:buffer(num_chunks) {
|
:buffer(num_chunks) {
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicChunk *
|
MusicChunk *
|
||||||
MusicBuffer::Allocate()
|
MusicBuffer::Allocate() noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
return buffer.Allocate();
|
return buffer.Allocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MusicBuffer::Return(MusicChunk *chunk)
|
MusicBuffer::Return(MusicChunk *chunk) noexcept
|
||||||
{
|
{
|
||||||
assert(chunk != nullptr);
|
assert(chunk != nullptr);
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ public:
|
|||||||
* @param num_chunks the number of #MusicChunk reserved in
|
* @param num_chunks the number of #MusicChunk reserved in
|
||||||
* this buffer
|
* this buffer
|
||||||
*/
|
*/
|
||||||
MusicBuffer(unsigned num_chunks);
|
MusicBuffer(unsigned num_chunks) noexcept;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +60,7 @@ public:
|
|||||||
* music_buffer_new().
|
* music_buffer_new().
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned GetSize() const {
|
unsigned GetSize() const noexcept {
|
||||||
return buffer.GetCapacity();
|
return buffer.GetCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,13 +71,13 @@ public:
|
|||||||
* @return an empty chunk or nullptr if there are no chunks
|
* @return an empty chunk or nullptr if there are no chunks
|
||||||
* available
|
* available
|
||||||
*/
|
*/
|
||||||
MusicChunk *Allocate();
|
MusicChunk *Allocate() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a chunk to the buffer. It can be reused by
|
* Returns a chunk to the buffer. It can be reused by
|
||||||
* Allocate() then.
|
* Allocate() then.
|
||||||
*/
|
*/
|
||||||
void Return(MusicChunk *chunk);
|
void Return(MusicChunk *chunk) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -31,7 +31,7 @@ MusicChunk::~MusicChunk()
|
|||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool
|
bool
|
||||||
MusicChunk::CheckFormat(const AudioFormat other_format) const
|
MusicChunk::CheckFormat(const AudioFormat other_format) const noexcept
|
||||||
{
|
{
|
||||||
assert(other_format.IsValid());
|
assert(other_format.IsValid());
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ MusicChunk::CheckFormat(const AudioFormat other_format) const
|
|||||||
|
|
||||||
WritableBuffer<void>
|
WritableBuffer<void>
|
||||||
MusicChunk::Write(const AudioFormat af,
|
MusicChunk::Write(const AudioFormat af,
|
||||||
SongTime data_time, uint16_t _bit_rate)
|
SongTime data_time, uint16_t _bit_rate) noexcept
|
||||||
{
|
{
|
||||||
assert(CheckFormat(af));
|
assert(CheckFormat(af));
|
||||||
assert(length == 0 || audio_format.IsValid());
|
assert(length == 0 || audio_format.IsValid());
|
||||||
@@ -64,7 +64,7 @@ MusicChunk::Write(const AudioFormat af,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MusicChunk::Expand(const AudioFormat af, size_t _length)
|
MusicChunk::Expand(const AudioFormat af, size_t _length) noexcept
|
||||||
{
|
{
|
||||||
const size_t frame_size = af.GetFrameSize();
|
const size_t frame_size = af.GetFrameSize();
|
||||||
|
|
||||||
|
@@ -111,7 +111,7 @@ struct MusicChunk {
|
|||||||
* specified audio_format.
|
* specified audio_format.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool CheckFormat(AudioFormat audio_format) const;
|
bool CheckFormat(AudioFormat audio_format) const noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +127,7 @@ struct MusicChunk {
|
|||||||
*/
|
*/
|
||||||
WritableBuffer<void> Write(AudioFormat af,
|
WritableBuffer<void> Write(AudioFormat af,
|
||||||
SongTime data_time,
|
SongTime data_time,
|
||||||
uint16_t bit_rate);
|
uint16_t bit_rate) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increases the length of the chunk after the caller has written to
|
* Increases the length of the chunk after the caller has written to
|
||||||
@@ -138,7 +138,7 @@ struct MusicChunk {
|
|||||||
* @param length the number of bytes which were appended
|
* @param length the number of bytes which were appended
|
||||||
* @return true if the chunk is full
|
* @return true if the chunk is full
|
||||||
*/
|
*/
|
||||||
bool Expand(AudioFormat af, size_t length);
|
bool Expand(AudioFormat af, size_t length) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
bool
|
bool
|
||||||
MusicPipe::Contains(const MusicChunk *chunk) const
|
MusicPipe::Contains(const MusicChunk *chunk) const noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
MusicChunk *
|
MusicChunk *
|
||||||
MusicPipe::Shift()
|
MusicPipe::Shift() noexcept
|
||||||
{
|
{
|
||||||
const std::lock_guard<Mutex> protect(mutex);
|
const std::lock_guard<Mutex> protect(mutex);
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ MusicPipe::Shift()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MusicPipe::Clear(MusicBuffer &buffer)
|
MusicPipe::Clear(MusicBuffer &buffer) noexcept
|
||||||
{
|
{
|
||||||
MusicChunk *chunk;
|
MusicChunk *chunk;
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ MusicPipe::Clear(MusicBuffer &buffer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MusicPipe::Push(MusicChunk *chunk)
|
MusicPipe::Push(MusicChunk *chunk) noexcept
|
||||||
{
|
{
|
||||||
assert(!chunk->IsEmpty());
|
assert(!chunk->IsEmpty());
|
||||||
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
||||||
|
@@ -77,7 +77,7 @@ public:
|
|||||||
* audio_format.
|
* audio_format.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool CheckFormat(AudioFormat other) const {
|
bool CheckFormat(AudioFormat other) const noexcept {
|
||||||
return !audio_format.IsDefined() ||
|
return !audio_format.IsDefined() ||
|
||||||
audio_format == other;
|
audio_format == other;
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ public:
|
|||||||
* Checks if the specified chunk is enqueued in the music pipe.
|
* Checks if the specified chunk is enqueued in the music pipe.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Contains(const MusicChunk *chunk) const;
|
bool Contains(const MusicChunk *chunk) const noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,37 +94,37 @@ public:
|
|||||||
* nullptr if the pipe is empty.
|
* nullptr if the pipe is empty.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const MusicChunk *Peek() const {
|
const MusicChunk *Peek() const noexcept {
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the first chunk from the head, and returns it.
|
* Removes the first chunk from the head, and returns it.
|
||||||
*/
|
*/
|
||||||
MusicChunk *Shift();
|
MusicChunk *Shift() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the whole pipe and returns the chunks to the buffer.
|
* Clears the whole pipe and returns the chunks to the buffer.
|
||||||
*
|
*
|
||||||
* @param buffer the buffer object to return the chunks to
|
* @param buffer the buffer object to return the chunks to
|
||||||
*/
|
*/
|
||||||
void Clear(MusicBuffer &buffer);
|
void Clear(MusicBuffer &buffer) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pushes a chunk to the tail of the pipe.
|
* Pushes a chunk to the tail of the pipe.
|
||||||
*/
|
*/
|
||||||
void Push(MusicChunk *chunk);
|
void Push(MusicChunk *chunk) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of chunks currently in this pipe.
|
* Returns the number of chunks currently in this pipe.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned GetSize() const {
|
unsigned GetSize() const noexcept {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return GetSize() == 0;
|
return GetSize() == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -141,9 +141,9 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
|||||||
void
|
void
|
||||||
Partition::OnGlobalEvent(unsigned mask)
|
Partition::OnGlobalEvent(unsigned mask)
|
||||||
{
|
{
|
||||||
if ((mask & TAG_MODIFIED) != 0)
|
|
||||||
TagModified();
|
|
||||||
|
|
||||||
if ((mask & SYNC_WITH_PLAYER) != 0)
|
if ((mask & SYNC_WITH_PLAYER) != 0)
|
||||||
SyncWithPlayer();
|
SyncWithPlayer();
|
||||||
|
|
||||||
|
if ((mask & TAG_MODIFIED) != 0)
|
||||||
|
TagModified();
|
||||||
}
|
}
|
||||||
|
@@ -200,7 +200,6 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
|
|||||||
*/
|
*/
|
||||||
const Database *GetDatabase() const;
|
const Database *GetDatabase() const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -49,7 +49,6 @@ static std::map<std::string, unsigned> permission_passwords;
|
|||||||
|
|
||||||
static unsigned permission_default;
|
static unsigned permission_default;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
static unsigned
|
static unsigned
|
||||||
ParsePermission(const char *p)
|
ParsePermission(const char *p)
|
||||||
{
|
{
|
||||||
|
@@ -207,13 +207,12 @@ try {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifdef _UNICODE
|
#ifdef _UNICODE
|
||||||
wchar_t buffer[MAX_PATH];
|
/* on Windows, playlists always contain UTF-8, because
|
||||||
auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
|
its "narrow" charset (i.e. CP_ACP) is incapable of
|
||||||
buffer, ARRAY_SIZE(buffer));
|
storing all Unicode paths */
|
||||||
if (result <= 0)
|
const auto path = AllocatedPath::FromUTF8(s);
|
||||||
|
if (path.IsNull())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Path path = Path::FromFS(buffer);
|
|
||||||
#else
|
#else
|
||||||
const Path path = Path::FromFS(s);
|
const Path path = Path::FromFS(s);
|
||||||
#endif
|
#endif
|
||||||
@@ -335,7 +334,7 @@ try {
|
|||||||
const auto path_fs = spl_map_to_fs(utf8path);
|
const auto path_fs = spl_map_to_fs(utf8path);
|
||||||
assert(!path_fs.IsNull());
|
assert(!path_fs.IsNull());
|
||||||
|
|
||||||
FileOutputStream fos(path_fs, FileOutputStream::Mode::APPEND_EXISTING);
|
FileOutputStream fos(path_fs, FileOutputStream::Mode::APPEND_OR_CREATE);
|
||||||
|
|
||||||
if (fos.Tell() / (MPD_PATH_MAX + 1) >= playlist_max_length)
|
if (fos.Tell() / (MPD_PATH_MAX + 1) >= playlist_max_length)
|
||||||
throw PlaylistError(PlaylistResult::TOO_LARGE,
|
throw PlaylistError(PlaylistResult::TOO_LARGE,
|
||||||
|
@@ -28,13 +28,25 @@
|
|||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
#include "fs/FileSystem.hxx"
|
#include "fs/FileSystem.hxx"
|
||||||
#include "fs/NarrowPath.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/UriUtil.hxx"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static void
|
||||||
|
playlist_print_path(BufferedOutputStream &os, const Path path)
|
||||||
|
{
|
||||||
|
#ifdef _UNICODE
|
||||||
|
/* on Windows, playlists always contain UTF-8, because its
|
||||||
|
"narrow" charset (i.e. CP_ACP) is incapable of storing all
|
||||||
|
Unicode paths */
|
||||||
|
os.Format("%s\n", path.ToUTF8().c_str());
|
||||||
|
#else
|
||||||
|
os.Format("%s\n", path.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
||||||
{
|
{
|
||||||
@@ -44,7 +56,7 @@ playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8);
|
const auto uri_fs = AllocatedPath::FromUTF8Throw(uri_utf8);
|
||||||
os.Format("%s\n", NarrowPath(uri_fs).c_str());
|
playlist_print_path(os, uri_fs);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,7 +75,7 @@ playlist_print_uri(BufferedOutputStream &os, const char *uri)
|
|||||||
AllocatedPath::FromUTF8Throw(uri);
|
AllocatedPath::FromUTF8Throw(uri);
|
||||||
|
|
||||||
if (!path.IsNull())
|
if (!path.IsNull())
|
||||||
os.Format("%s\n", NarrowPath(path).c_str());
|
playlist_print_path(os, path);
|
||||||
} catch (const std::runtime_error &) {
|
} catch (const std::runtime_error &) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
float
|
float
|
||||||
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const
|
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
|
||||||
{
|
{
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
|
@@ -40,23 +40,23 @@ struct ReplayGainTuple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
float CalculateScale(const ReplayGainConfig &config) const;
|
float CalculateScale(const ReplayGainConfig &config) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ReplayGainInfo {
|
struct ReplayGainInfo {
|
||||||
ReplayGainTuple track, album;
|
ReplayGainTuple track, album;
|
||||||
|
|
||||||
constexpr bool IsDefined() const {
|
constexpr bool IsDefined() const noexcept {
|
||||||
return track.IsDefined() || album.IsDefined();
|
return track.IsDefined() || album.IsDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReplayGainTuple &Get(ReplayGainMode mode) const {
|
const ReplayGainTuple &Get(ReplayGainMode mode) const noexcept {
|
||||||
return mode == ReplayGainMode::ALBUM
|
return mode == ReplayGainMode::ALBUM
|
||||||
? (album.IsDefined() ? album : track)
|
? (album.IsDefined() ? album : track)
|
||||||
: (track.IsDefined() ? track : album);
|
: (track.IsDefined() ? track : album);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear() {
|
void Clear() noexcept {
|
||||||
track.Clear();
|
track.Clear();
|
||||||
album.Clear();
|
album.Clear();
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
ToString(ReplayGainMode mode)
|
ToString(ReplayGainMode mode) noexcept
|
||||||
{
|
{
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ReplayGainMode::AUTO:
|
case ReplayGainMode::AUTO:
|
||||||
|
@@ -36,13 +36,12 @@ enum class ReplayGainMode : uint8_t {
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *
|
const char *
|
||||||
ToString(ReplayGainMode mode);
|
ToString(ReplayGainMode mode) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string to a #ReplayGainMode. Throws std::runtime_error on
|
* Parse a string to a #ReplayGainMode. Throws std::runtime_error on
|
||||||
* error.
|
* error.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
ReplayGainMode
|
ReplayGainMode
|
||||||
FromString(const char *s);
|
FromString(const char *s);
|
||||||
|
|
||||||
|
@@ -27,7 +27,7 @@
|
|||||||
#include "util/ASCII.hxx"
|
#include "util/ASCII.hxx"
|
||||||
#include "util/TimeParser.hxx"
|
#include "util/TimeParser.hxx"
|
||||||
#include "util/UriUtil.hxx"
|
#include "util/UriUtil.hxx"
|
||||||
#include "lib/icu/Collate.hxx"
|
#include "lib/icu/CaseFold.hxx"
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
#define LOCATE_TAG_ANY_KEY "any"
|
#define LOCATE_TAG_ANY_KEY "any"
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
locate_parse_type(const char *str)
|
locate_parse_type(const char *str) noexcept
|
||||||
{
|
{
|
||||||
if (StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY) ||
|
if (StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY) ||
|
||||||
StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY_OLD))
|
StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY_OLD))
|
||||||
@@ -57,18 +57,10 @@ locate_parse_type(const char *str)
|
|||||||
return tag_name_parse_i(str);
|
return tag_name_parse_i(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
static AllocatedString<>
|
|
||||||
ImportString(const char *p, bool fold_case)
|
|
||||||
{
|
|
||||||
return fold_case
|
|
||||||
? IcuCaseFold(p)
|
|
||||||
: AllocatedString<>::Duplicate(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
|
||||||
:tag(_tag), fold_case(_fold_case),
|
:tag(_tag),
|
||||||
value(ImportString(_value, _fold_case))
|
value(AllocatedString<>::Duplicate(_value)),
|
||||||
|
fold_case(_fold_case ? IcuCompare(value.c_str()) : IcuCompare())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +70,7 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::StringMatch(const char *s) const
|
SongFilter::Item::StringMatch(const char *s) const noexcept
|
||||||
{
|
{
|
||||||
#if !CLANG_CHECK_VERSION(3,6)
|
#if !CLANG_CHECK_VERSION(3,6)
|
||||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||||
@@ -88,23 +80,21 @@ SongFilter::Item::StringMatch(const char *s) const
|
|||||||
assert(tag != LOCATE_TAG_MODIFIED_SINCE);
|
assert(tag != LOCATE_TAG_MODIFIED_SINCE);
|
||||||
|
|
||||||
if (fold_case) {
|
if (fold_case) {
|
||||||
const auto folded = IcuCaseFold(s);
|
return fold_case.IsIn(s);
|
||||||
assert(!folded.IsNull());
|
|
||||||
return StringFind(folded.c_str(), value.c_str()) != nullptr;
|
|
||||||
} else {
|
} else {
|
||||||
return StringIsEqual(s, value.c_str());
|
return StringIsEqual(s, value.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::Match(const TagItem &item) const
|
SongFilter::Item::Match(const TagItem &item) const noexcept
|
||||||
{
|
{
|
||||||
return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
|
return (tag == LOCATE_TAG_ANY_TYPE || (unsigned)item.type == tag) &&
|
||||||
StringMatch(item.value);
|
StringMatch(item.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::Match(const Tag &_tag) const
|
SongFilter::Item::Match(const Tag &_tag) const noexcept
|
||||||
{
|
{
|
||||||
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
|
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
|
||||||
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
|
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
|
||||||
@@ -140,7 +130,7 @@ SongFilter::Item::Match(const Tag &_tag) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::Match(const DetachedSong &song) const
|
SongFilter::Item::Match(const DetachedSong &song) const noexcept
|
||||||
{
|
{
|
||||||
if (tag == LOCATE_TAG_BASE_TYPE)
|
if (tag == LOCATE_TAG_BASE_TYPE)
|
||||||
return uri_is_child_or_same(value.c_str(), song.GetURI());
|
return uri_is_child_or_same(value.c_str(), song.GetURI());
|
||||||
@@ -155,7 +145,7 @@ SongFilter::Item::Match(const DetachedSong &song) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Item::Match(const LightSong &song) const
|
SongFilter::Item::Match(const LightSong &song) const noexcept
|
||||||
{
|
{
|
||||||
if (tag == LOCATE_TAG_BASE_TYPE) {
|
if (tag == LOCATE_TAG_BASE_TYPE) {
|
||||||
const auto uri = song.GetURI();
|
const auto uri = song.GetURI();
|
||||||
@@ -185,7 +175,7 @@ SongFilter::~SongFilter()
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static time_t
|
static time_t
|
||||||
ParseTimeStamp(const char *s)
|
ParseTimeStamp(const char *s) noexcept
|
||||||
{
|
{
|
||||||
assert(s != nullptr);
|
assert(s != nullptr);
|
||||||
|
|
||||||
@@ -246,7 +236,7 @@ SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Match(const DetachedSong &song) const
|
SongFilter::Match(const DetachedSong &song) const noexcept
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (!i.Match(song))
|
if (!i.Match(song))
|
||||||
@@ -256,7 +246,7 @@ SongFilter::Match(const DetachedSong &song) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::Match(const LightSong &song) const
|
SongFilter::Match(const LightSong &song) const noexcept
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (!i.Match(song))
|
if (!i.Match(song))
|
||||||
@@ -266,7 +256,7 @@ SongFilter::Match(const LightSong &song) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SongFilter::HasOtherThanBase() const
|
SongFilter::HasOtherThanBase() const noexcept
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
|
if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
|
||||||
@@ -276,7 +266,7 @@ SongFilter::HasOtherThanBase() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
SongFilter::GetBase() const
|
SongFilter::GetBase() const noexcept
|
||||||
{
|
{
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (i.GetTag() == LOCATE_TAG_BASE_TYPE)
|
if (i.GetTag() == LOCATE_TAG_BASE_TYPE)
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#ifndef MPD_SONG_FILTER_HXX
|
#ifndef MPD_SONG_FILTER_HXX
|
||||||
#define MPD_SONG_FILTER_HXX
|
#define MPD_SONG_FILTER_HXX
|
||||||
|
|
||||||
|
#include "lib/icu/Compare.hxx"
|
||||||
#include "util/AllocatedString.hxx"
|
#include "util/AllocatedString.hxx"
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
@@ -48,10 +49,13 @@ public:
|
|||||||
class Item {
|
class Item {
|
||||||
uint8_t tag;
|
uint8_t tag;
|
||||||
|
|
||||||
bool fold_case;
|
|
||||||
|
|
||||||
AllocatedString<> value;
|
AllocatedString<> value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This value is only set if case folding is enabled.
|
||||||
|
*/
|
||||||
|
IcuCompare fold_case;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For #LOCATE_TAG_MODIFIED_SINCE
|
* For #LOCATE_TAG_MODIFIED_SINCE
|
||||||
*/
|
*/
|
||||||
@@ -80,19 +84,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure gcc_nonnull(2)
|
gcc_pure gcc_nonnull(2)
|
||||||
bool StringMatch(const char *s) const;
|
bool StringMatch(const char *s) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const TagItem &tag_item) const;
|
bool Match(const TagItem &tag_item) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const Tag &tag) const;
|
bool Match(const Tag &tag) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const DetachedSong &song) const;
|
bool Match(const DetachedSong &song) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const LightSong &song) const;
|
bool Match(const LightSong &song) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -112,20 +116,20 @@ public:
|
|||||||
bool Parse(ConstBuffer<const char *> args, bool fold_case=false);
|
bool Parse(ConstBuffer<const char *> args, bool fold_case=false);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const Tag &tag) const;
|
bool Match(const Tag &tag) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const DetachedSong &song) const;
|
bool Match(const DetachedSong &song) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const LightSong &song) const;
|
bool Match(const LightSong &song) const noexcept;
|
||||||
|
|
||||||
const std::list<Item> &GetItems() const {
|
const std::list<Item> &GetItems() const noexcept {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return items.empty();
|
return items.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +137,7 @@ public:
|
|||||||
* Is there at least one item with "fold case" enabled?
|
* Is there at least one item with "fold case" enabled?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasFoldCase() const {
|
bool HasFoldCase() const noexcept {
|
||||||
for (const auto &i : items)
|
for (const auto &i : items)
|
||||||
if (i.GetFoldCase())
|
if (i.GetFoldCase())
|
||||||
return true;
|
return true;
|
||||||
@@ -145,14 +149,14 @@ public:
|
|||||||
* Does this filter contain constraints other than "base"?
|
* Does this filter contain constraints other than "base"?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasOtherThanBase() const;
|
bool HasOtherThanBase() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the "base" specification (if there is one) or
|
* Returns the "base" specification (if there is one) or
|
||||||
* nullptr.
|
* nullptr.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetBase() const;
|
const char *GetBase() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -160,6 +164,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
unsigned
|
unsigned
|
||||||
locate_parse_type(const char *str);
|
locate_parse_type(const char *str) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -50,7 +50,7 @@ StateFile::StateFile(AllocatedPath &&_path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
StateFile::RememberVersions()
|
StateFile::RememberVersions() noexcept
|
||||||
{
|
{
|
||||||
prev_volume_version = sw_volume_state_get_hash();
|
prev_volume_version = sw_volume_state_get_hash();
|
||||||
prev_output_version = audio_output_state_get_version();
|
prev_output_version = audio_output_state_get_version();
|
||||||
@@ -59,7 +59,7 @@ StateFile::RememberVersions()
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
StateFile::IsModified() const
|
StateFile::IsModified() const noexcept
|
||||||
{
|
{
|
||||||
return prev_volume_version != sw_volume_state_get_hash() ||
|
return prev_volume_version != sw_volume_state_get_hash() ||
|
||||||
prev_output_version != audio_output_state_get_version() ||
|
prev_output_version != audio_output_state_get_version() ||
|
||||||
|
@@ -67,14 +67,14 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Save the current state versions for use with IsModified().
|
* Save the current state versions for use with IsModified().
|
||||||
*/
|
*/
|
||||||
void RememberVersions();
|
void RememberVersions() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if MPD's state was modified since the last
|
* Check if MPD's state was modified since the last
|
||||||
* RememberVersions() call.
|
* RememberVersions() call.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsModified() const;
|
bool IsModified() const noexcept;
|
||||||
|
|
||||||
/* virtual methods from TimeoutMonitor */
|
/* virtual methods from TimeoutMonitor */
|
||||||
void OnTimeout() override;
|
void OnTimeout() override;
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
CheckDecoderPlugin(const DecoderPlugin &plugin,
|
CheckDecoderPlugin(const DecoderPlugin &plugin,
|
||||||
const char *suffix, const char *mime)
|
const char *suffix, const char *mime) noexcept
|
||||||
{
|
{
|
||||||
return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
|
return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
|
||||||
(suffix != nullptr && plugin.SupportsSuffix(suffix));
|
(suffix != nullptr && plugin.SupportsSuffix(suffix));
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static char *
|
static char *
|
||||||
FindSlash(char *p, size_t i)
|
FindSlash(char *p, size_t i) noexcept
|
||||||
{
|
{
|
||||||
for (; i > 0; --i)
|
for (; i > 0; --i)
|
||||||
if (p[i] == '/')
|
if (p[i] == '/')
|
||||||
@@ -39,7 +39,7 @@ FindSlash(char *p, size_t i)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static const char *
|
static const char *
|
||||||
FindSuffix(const char *p, const char *i)
|
FindSuffix(const char *p, const char *i) noexcept
|
||||||
{
|
{
|
||||||
for (; i > p; --i) {
|
for (; i > p; --i) {
|
||||||
if (*i == '.')
|
if (*i == '.')
|
||||||
|
@@ -93,7 +93,7 @@ public:
|
|||||||
~Bzip2InputStream();
|
~Bzip2InputStream();
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -205,7 +205,7 @@ Bzip2InputStream::Read(void *ptr, size_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Bzip2InputStream::IsEOF()
|
Bzip2InputStream::IsEOF() noexcept
|
||||||
{
|
{
|
||||||
return eof;
|
return eof;
|
||||||
}
|
}
|
||||||
|
@@ -162,7 +162,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ Iso9660InputStream::Read(void *ptr, size_t read_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Iso9660InputStream::IsEOF()
|
Iso9660InputStream::IsEOF() noexcept
|
||||||
{
|
{
|
||||||
return offset == size;
|
return offset == size;
|
||||||
}
|
}
|
||||||
|
@@ -116,7 +116,7 @@ struct ZzipInputStream final : public InputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* virtual methods from InputStream */
|
/* virtual methods from InputStream */
|
||||||
bool IsEOF() override;
|
bool IsEOF() noexcept override;
|
||||||
size_t Read(void *ptr, size_t size) override;
|
size_t Read(void *ptr, size_t size) override;
|
||||||
void Seek(offset_type offset) override;
|
void Seek(offset_type offset) override;
|
||||||
};
|
};
|
||||||
@@ -147,7 +147,7 @@ ZzipInputStream::Read(void *ptr, size_t read_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ZzipInputStream::IsEOF()
|
ZzipInputStream::IsEOF() noexcept
|
||||||
{
|
{
|
||||||
return offset_type(zzip_tell(file)) == size;
|
return offset_type(zzip_tell(file)) == size;
|
||||||
}
|
}
|
||||||
|
@@ -28,7 +28,7 @@ const Domain client_domain("client");
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
|
||||||
const Database *
|
const Database *
|
||||||
Client::GetDatabase() const
|
Client::GetDatabase() const noexcept
|
||||||
{
|
{
|
||||||
return partition.instance.GetDatabase();
|
return partition.instance.GetDatabase();
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ Client::GetDatabaseOrThrow() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Storage *
|
const Storage *
|
||||||
Client::GetStorage() const
|
Client::GetStorage() const noexcept
|
||||||
{
|
{
|
||||||
return partition.instance.storage;
|
return partition.instance.storage;
|
||||||
}
|
}
|
||||||
|
@@ -100,7 +100,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsExpired() const {
|
bool IsExpired() const noexcept {
|
||||||
return !FullyBufferedSocket::IsDefined();
|
return !FullyBufferedSocket::IsDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsSubscribed(const char *channel_name) const {
|
bool IsSubscribed(const char *channel_name) const noexcept {
|
||||||
return subscriptions.find(channel_name) != subscriptions.end();
|
return subscriptions.find(channel_name) != subscriptions.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,16 +186,15 @@ public:
|
|||||||
* Wrapper for Instance::GetDatabase().
|
* Wrapper for Instance::GetDatabase().
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const Database *GetDatabase() const;
|
const Database *GetDatabase() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for Instance::GetDatabaseOrThrow().
|
* Wrapper for Instance::GetDatabaseOrThrow().
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
const Database &GetDatabaseOrThrow() const;
|
const Database &GetDatabaseOrThrow() const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const Storage *GetStorage() const;
|
const Storage *GetStorage() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* virtual methods from class BufferedSocket */
|
/* virtual methods from class BufferedSocket */
|
||||||
|
@@ -23,14 +23,14 @@
|
|||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static bool
|
static bool
|
||||||
valid_channel_char(const char ch)
|
valid_channel_char(const char ch) noexcept
|
||||||
{
|
{
|
||||||
return IsAlphaNumericASCII(ch) ||
|
return IsAlphaNumericASCII(ch) ||
|
||||||
ch == '_' || ch == '-' || ch == '.' || ch == ':';
|
ch == '_' || ch == '-' || ch == '.' || ch == ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
client_message_valid_channel_name(const char *name)
|
client_message_valid_channel_name(const char *name) noexcept
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
if (!valid_channel_char(*name))
|
if (!valid_channel_char(*name))
|
||||||
|
@@ -53,6 +53,6 @@ public:
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool
|
bool
|
||||||
client_message_valid_channel_name(const char *name);
|
client_message_valid_channel_name(const char *name) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -29,9 +29,32 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define GLIBCXX_490 20140422
|
||||||
|
#define GLIBCXX_491 20140716
|
||||||
|
#define GLIBCXX_492 20141030
|
||||||
|
#define GLIBCXX_492_Debian_9 20141220
|
||||||
|
#define GLIBCXX_493 20150626
|
||||||
|
#define GLIBCXX_494 20160803
|
||||||
|
#define GLIBCXX_49X_NDK_r13b 20150123
|
||||||
|
|
||||||
|
/* the big mess attempts to detect whether we're compiling with
|
||||||
|
libstdc++ 4.9.x; __GLIBCXX__ is a date tag and cannot be used to
|
||||||
|
check the major version; and just checking the compiler version
|
||||||
|
isn't enough, because somebody could use an old libstdc++ with
|
||||||
|
clang - SIGH! */
|
||||||
|
#if GCC_OLDER_THAN(5,0) || (defined(__GLIBCXX__) && \
|
||||||
|
(__GLIBCXX__ == GLIBCXX_490 || __GLIBCXX__ == GLIBCXX_491 || \
|
||||||
|
__GLIBCXX__ == GLIBCXX_492 || \
|
||||||
|
__GLIBCXX__ == GLIBCXX_492_Debian_9 || \
|
||||||
|
__GLIBCXX__ == GLIBCXX_493 || \
|
||||||
|
__GLIBCXX__ == GLIBCXX_494 || \
|
||||||
|
__GLIBCXX__ == GLIBCXX_49X_NDK_r13b))
|
||||||
|
#define GLIBCXX_49X
|
||||||
|
#endif
|
||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static enum ack
|
static enum ack
|
||||||
ToAck(PlaylistResult result)
|
ToAck(PlaylistResult result) noexcept
|
||||||
{
|
{
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case PlaylistResult::SUCCESS:
|
case PlaylistResult::SUCCESS:
|
||||||
@@ -67,7 +90,7 @@ ToAck(PlaylistResult result)
|
|||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
gcc_const
|
gcc_const
|
||||||
static enum ack
|
static enum ack
|
||||||
ToAck(DatabaseErrorCode code)
|
ToAck(DatabaseErrorCode code) noexcept
|
||||||
{
|
{
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case DatabaseErrorCode::DISABLED:
|
case DatabaseErrorCode::DISABLED:
|
||||||
@@ -84,7 +107,7 @@ ToAck(DatabaseErrorCode code)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static enum ack
|
static enum ack
|
||||||
ToAck(std::exception_ptr ep)
|
ToAck(std::exception_ptr ep) noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(ep);
|
std::rethrow_exception(ep);
|
||||||
@@ -100,13 +123,13 @@ ToAck(std::exception_ptr ep)
|
|||||||
return ACK_ERROR_SYSTEM;
|
return ACK_ERROR_SYSTEM;
|
||||||
} catch (const std::invalid_argument &e) {
|
} catch (const std::invalid_argument &e) {
|
||||||
return ACK_ERROR_ARG;
|
return ACK_ERROR_ARG;
|
||||||
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
|
#ifdef GLIBCXX_49X
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
#else
|
#else
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
#endif
|
#endif
|
||||||
try {
|
try {
|
||||||
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
|
#ifdef GLIBCXX_49X
|
||||||
/* workaround for g++ 4.x: no overload for
|
/* workaround for g++ 4.x: no overload for
|
||||||
rethrow_exception(exception_ptr) */
|
rethrow_exception(exception_ptr) */
|
||||||
std::rethrow_if_nested(e);
|
std::rethrow_if_nested(e);
|
||||||
|
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
SkipNameFS(PathTraitsFS::const_pointer_type name_fs)
|
SkipNameFS(PathTraitsFS::const_pointer_type name_fs) noexcept
|
||||||
{
|
{
|
||||||
return name_fs[0] == '.' &&
|
return name_fs[0] == '.' &&
|
||||||
(name_fs[1] == 0 ||
|
(name_fs[1] == 0 ||
|
||||||
@@ -53,7 +53,7 @@ SkipNameFS(PathTraitsFS::const_pointer_type name_fs)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
skip_path(Path name_fs)
|
skip_path(Path name_fs) noexcept
|
||||||
{
|
{
|
||||||
return name_fs.HasNewline();
|
return name_fs.HasNewline();
|
||||||
}
|
}
|
||||||
@@ -107,7 +107,7 @@ handle_listfiles_local(Response &r, Path path_fs)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
IsValidName(const char *p)
|
IsValidName(const char *p) noexcept
|
||||||
{
|
{
|
||||||
if (!IsAlphaASCII(*p))
|
if (!IsAlphaASCII(*p))
|
||||||
return false;
|
return false;
|
||||||
@@ -123,7 +123,7 @@ IsValidName(const char *p)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
IsValidValue(const char *p)
|
IsValidValue(const char *p) noexcept
|
||||||
{
|
{
|
||||||
while (*p) {
|
while (*p) {
|
||||||
const char ch = *p++;
|
const char ch = *p++;
|
||||||
|
@@ -30,7 +30,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
neighbor_commands_available(const Instance &instance)
|
neighbor_commands_available(const Instance &instance) noexcept
|
||||||
{
|
{
|
||||||
return instance.neighbors != nullptr;
|
return instance.neighbors != nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ class Response;
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool
|
bool
|
||||||
neighbor_commands_available(const Instance &instance);
|
neighbor_commands_available(const Instance &instance) noexcept;
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_listneighbors(Client &client, Request request, Response &response);
|
handle_listneighbors(Client &client, Request request, Response &response);
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "Instance.hxx"
|
#include "Instance.hxx"
|
||||||
#include "Idle.hxx"
|
#include "Idle.hxx"
|
||||||
#include "AudioFormat.hxx"
|
#include "AudioFormat.hxx"
|
||||||
|
#include "util/StringBuffer.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
#include "util/Exception.hxx"
|
#include "util/Exception.hxx"
|
||||||
|
|
||||||
@@ -171,13 +172,9 @@ handle_status(Client &client, gcc_unused Request args, Response &r)
|
|||||||
r.Format("duration: %1.3f\n",
|
r.Format("duration: %1.3f\n",
|
||||||
player_status.total_time.ToDoubleS());
|
player_status.total_time.ToDoubleS());
|
||||||
|
|
||||||
if (player_status.audio_format.IsDefined()) {
|
if (player_status.audio_format.IsDefined())
|
||||||
struct audio_format_string af_string;
|
|
||||||
|
|
||||||
r.Format(COMMAND_STATUS_AUDIO ": %s\n",
|
r.Format(COMMAND_STATUS_AUDIO ": %s\n",
|
||||||
audio_format_to_string(player_status.audio_format,
|
ToString(player_status.audio_format).c_str());
|
||||||
&af_string));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_DATABASE
|
#ifdef ENABLE_DATABASE
|
||||||
|
@@ -39,7 +39,7 @@
|
|||||||
#include "util/ConstBuffer.hxx"
|
#include "util/ConstBuffer.hxx"
|
||||||
|
|
||||||
bool
|
bool
|
||||||
playlist_commands_available()
|
playlist_commands_available() noexcept
|
||||||
{
|
{
|
||||||
return !map_spl_path().IsNull();
|
return !map_spl_path().IsNull();
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ class Response;
|
|||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
bool
|
bool
|
||||||
playlist_commands_available();
|
playlist_commands_available() noexcept;
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_save(Client &client, Request request, Response &response);
|
handle_save(Client &client, Request request, Response &response);
|
||||||
|
@@ -45,68 +45,57 @@ public:
|
|||||||
: default_value;
|
: default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseInt(unsigned idx) const {
|
int ParseInt(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgInt(data[idx]);
|
return ParseCommandArgInt(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseInt(unsigned idx, int min_value, int max_value) const {
|
int ParseInt(unsigned idx, int min_value, int max_value) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgInt(data[idx], min_value, max_value);
|
return ParseCommandArgInt(data[idx], min_value, max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseUnsigned(unsigned idx) const {
|
int ParseUnsigned(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgUnsigned(data[idx]);
|
return ParseCommandArgUnsigned(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseUnsigned(unsigned idx, unsigned max_value) const {
|
int ParseUnsigned(unsigned idx, unsigned max_value) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgUnsigned(data[idx], max_value);
|
return ParseCommandArgUnsigned(data[idx], max_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool ParseBool(unsigned idx) const {
|
bool ParseBool(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgBool(data[idx]);
|
return ParseCommandArgBool(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
RangeArg ParseRange(unsigned idx) const {
|
RangeArg ParseRange(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgRange(data[idx]);
|
return ParseCommandArgRange(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
float ParseFloat(unsigned idx) const {
|
float ParseFloat(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgFloat(data[idx]);
|
return ParseCommandArgFloat(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
SongTime ParseSongTime(unsigned idx) const {
|
SongTime ParseSongTime(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgSongTime(data[idx]);
|
return ParseCommandArgSongTime(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
SignedSongTime ParseSignedSongTime(unsigned idx) const {
|
SignedSongTime ParseSignedSongTime(unsigned idx) const {
|
||||||
assert(idx < size);
|
assert(idx < size);
|
||||||
return ParseCommandArgSignedSongTime(data[idx]);
|
return ParseCommandArgSignedSongTime(data[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int ParseOptional(unsigned idx, int default_value) const {
|
int ParseOptional(unsigned idx, int default_value) const {
|
||||||
return idx < size
|
return idx < size
|
||||||
? ParseInt(idx)
|
? ParseInt(idx)
|
||||||
: default_value;
|
: default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
RangeArg ParseOptional(unsigned idx, RangeArg default_value) const {
|
RangeArg ParseOptional(unsigned idx, RangeArg default_value) const {
|
||||||
return idx < size
|
return idx < size
|
||||||
? ParseRange(idx)
|
? ParseRange(idx)
|
||||||
|
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
skip_path(const char *name_utf8)
|
skip_path(const char *name_utf8) noexcept
|
||||||
{
|
{
|
||||||
return strchr(name_utf8, '\n') != nullptr;
|
return strchr(name_utf8, '\n') != nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -68,7 +68,7 @@ ConfigBlock::~ConfigBlock()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BlockParam *
|
const BlockParam *
|
||||||
ConfigBlock::GetBlockParam(const char *name) const
|
ConfigBlock::GetBlockParam(const char *name) const noexcept
|
||||||
{
|
{
|
||||||
for (const auto &i : block_params) {
|
for (const auto &i : block_params) {
|
||||||
if (i.name == name) {
|
if (i.name == name) {
|
||||||
@@ -81,7 +81,8 @@ ConfigBlock::GetBlockParam(const char *name) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
ConfigBlock::GetBlockValue(const char *name, const char *default_value) const
|
ConfigBlock::GetBlockValue(const char *name,
|
||||||
|
const char *default_value) const noexcept
|
||||||
{
|
{
|
||||||
const BlockParam *bp = GetBlockParam(name);
|
const BlockParam *bp = GetBlockParam(name);
|
||||||
if (bp == nullptr)
|
if (bp == nullptr)
|
||||||
@@ -128,7 +129,6 @@ ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
|
|||||||
return bp->GetUnsignedValue();
|
return bp->GetUnsignedValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool
|
bool
|
||||||
ConfigBlock::GetBlockValue(const char *name, bool default_value) const
|
ConfigBlock::GetBlockValue(const char *name, bool default_value) const
|
||||||
{
|
{
|
||||||
|
@@ -44,13 +44,10 @@ struct BlockParam {
|
|||||||
BlockParam(const char *_name, const char *_value, int _line=-1)
|
BlockParam(const char *_name, const char *_value, int _line=-1)
|
||||||
:name(_name), value(_value), line(_line), used(false) {}
|
:name(_name), value(_value), line(_line), used(false) {}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int GetIntValue() const;
|
int GetIntValue() const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
unsigned GetUnsignedValue() const;
|
unsigned GetUnsignedValue() const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool GetBoolValue() const;
|
bool GetBoolValue() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,12 +82,12 @@ struct ConfigBlock {
|
|||||||
* object that was synthesized and not loaded from a
|
* object that was synthesized and not loaded from a
|
||||||
* configuration file.
|
* configuration file.
|
||||||
*/
|
*/
|
||||||
bool IsNull() const {
|
bool IsNull() const noexcept {
|
||||||
return line < 0;
|
return line < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return block_params.empty();
|
return block_params.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,11 +98,11 @@ struct ConfigBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_nonnull_all gcc_pure
|
gcc_nonnull_all gcc_pure
|
||||||
const BlockParam *GetBlockParam(const char *_name) const;
|
const BlockParam *GetBlockParam(const char *_name) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetBlockValue(const char *name,
|
const char *GetBlockValue(const char *name,
|
||||||
const char *default_value=nullptr) const;
|
const char *default_value=nullptr) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Same as config_get_path(), but looks up the setting in the
|
* Same as config_get_path(), but looks up the setting in the
|
||||||
@@ -116,13 +113,10 @@ struct ConfigBlock {
|
|||||||
AllocatedPath GetPath(const char *name,
|
AllocatedPath GetPath(const char *name,
|
||||||
const char *default_value=nullptr) const;
|
const char *default_value=nullptr) const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
int GetBlockValue(const char *name, int default_value) const;
|
int GetBlockValue(const char *name, int default_value) const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
unsigned GetBlockValue(const char *name, unsigned default_value) const;
|
unsigned GetBlockValue(const char *name, unsigned default_value) const;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool GetBlockValue(const char *name, bool default_value) const;
|
bool GetBlockValue(const char *name, bool default_value) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -75,7 +75,7 @@ void config_global_check(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConfigParam *
|
const ConfigParam *
|
||||||
config_get_param(ConfigOption option)
|
config_get_param(ConfigOption option) noexcept
|
||||||
{
|
{
|
||||||
auto *param = config_data.params[unsigned(option)];
|
auto *param = config_data.params[unsigned(option)];
|
||||||
if (param != nullptr)
|
if (param != nullptr)
|
||||||
@@ -84,7 +84,7 @@ config_get_param(ConfigOption option)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ConfigBlock *
|
const ConfigBlock *
|
||||||
config_get_block(ConfigBlockOption option)
|
config_get_block(ConfigBlockOption option) noexcept
|
||||||
{
|
{
|
||||||
ConfigBlock *block = config_data.blocks[unsigned(option)];
|
ConfigBlock *block = config_data.blocks[unsigned(option)];
|
||||||
if (block != nullptr)
|
if (block != nullptr)
|
||||||
@@ -110,7 +110,7 @@ config_find_block(ConfigBlockOption option, const char *key, const char *value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
config_get_string(ConfigOption option, const char *default_value)
|
config_get_string(ConfigOption option, const char *default_value) noexcept
|
||||||
{
|
{
|
||||||
const auto *param = config_get_param(option);
|
const auto *param = config_get_param(option);
|
||||||
|
|
||||||
|
@@ -48,11 +48,11 @@ ReadConfigFile(Path path);
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const ConfigParam *
|
const ConfigParam *
|
||||||
config_get_param(enum ConfigOption option);
|
config_get_param(enum ConfigOption option) noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const ConfigBlock *
|
const ConfigBlock *
|
||||||
config_get_block(enum ConfigBlockOption option);
|
config_get_block(enum ConfigBlockOption option) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a block with a matching attribute.
|
* Find a block with a matching attribute.
|
||||||
@@ -61,20 +61,12 @@ config_get_block(enum ConfigBlockOption option);
|
|||||||
* @param key the attribute name
|
* @param key the attribute name
|
||||||
* @param value the expected attribute value
|
* @param value the expected attribute value
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
const ConfigBlock *
|
const ConfigBlock *
|
||||||
config_find_block(ConfigBlockOption option, const char *key, const char *value);
|
config_find_block(ConfigBlockOption option, const char *key, const char *value);
|
||||||
|
|
||||||
/* Note on gcc_pure: Some of the functions declared pure are not
|
|
||||||
really pure in strict sense. They have side effect such that they
|
|
||||||
validate parameter's value and signal an error if it's invalid.
|
|
||||||
However, if the argument was already validated or we don't care
|
|
||||||
about the argument at all, this may be ignored so in the end, we
|
|
||||||
should be fine with calling those functions pure. */
|
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
const char *
|
const char *
|
||||||
config_get_string(enum ConfigOption option, const char *default_value=nullptr);
|
config_get_string(enum ConfigOption option,
|
||||||
|
const char *default_value=nullptr) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an optional configuration variable which contains an
|
* Returns an optional configuration variable which contains an
|
||||||
@@ -86,11 +78,9 @@ config_get_string(enum ConfigOption option, const char *default_value=nullptr);
|
|||||||
AllocatedPath
|
AllocatedPath
|
||||||
config_get_path(enum ConfigOption option);
|
config_get_path(enum ConfigOption option);
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
unsigned
|
unsigned
|
||||||
config_get_unsigned(enum ConfigOption option, unsigned default_value);
|
config_get_unsigned(enum ConfigOption option, unsigned default_value);
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
static inline std::chrono::steady_clock::duration
|
static inline std::chrono::steady_clock::duration
|
||||||
config_get_unsigned(ConfigOption option,
|
config_get_unsigned(ConfigOption option,
|
||||||
std::chrono::steady_clock::duration default_value)
|
std::chrono::steady_clock::duration default_value)
|
||||||
@@ -100,11 +90,9 @@ config_get_unsigned(ConfigOption option,
|
|||||||
return std::chrono::steady_clock::duration(u);
|
return std::chrono::steady_clock::duration(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
unsigned
|
unsigned
|
||||||
config_get_positive(enum ConfigOption option, unsigned default_value);
|
config_get_positive(enum ConfigOption option, unsigned default_value);
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
static inline std::chrono::steady_clock::duration
|
static inline std::chrono::steady_clock::duration
|
||||||
config_get_positive(ConfigOption option,
|
config_get_positive(ConfigOption option,
|
||||||
std::chrono::steady_clock::duration default_value)
|
std::chrono::steady_clock::duration default_value)
|
||||||
@@ -114,7 +102,6 @@ config_get_positive(ConfigOption option,
|
|||||||
return std::chrono::steady_clock::duration(u);
|
return std::chrono::steady_clock::duration(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
bool config_get_bool(enum ConfigOption option, bool default_value);
|
bool config_get_bool(enum ConfigOption option, bool default_value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -102,13 +102,13 @@ enum class ConfigBlockOption {
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
enum ConfigOption
|
enum ConfigOption
|
||||||
ParseConfigOptionName(const char *name);
|
ParseConfigOptionName(const char *name) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return #ConfigOption::MAX if not found
|
* @return #ConfigOption::MAX if not found
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
enum ConfigBlockOption
|
enum ConfigBlockOption
|
||||||
ParseConfigBlockOptionName(const char *name);
|
ParseConfigBlockOptionName(const char *name) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -101,7 +101,7 @@ static_assert(n_config_block_templates == unsigned(ConfigBlockOption::MAX),
|
|||||||
gcc_pure
|
gcc_pure
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
|
ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
|
||||||
const char *name)
|
const char *name) noexcept
|
||||||
{
|
{
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (; i < count; ++i)
|
for (; i < count; ++i)
|
||||||
@@ -112,7 +112,7 @@ ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigOption
|
ConfigOption
|
||||||
ParseConfigOptionName(const char *name)
|
ParseConfigOptionName(const char *name) noexcept
|
||||||
{
|
{
|
||||||
return ConfigOption(ParseConfigTemplateName(config_param_templates,
|
return ConfigOption(ParseConfigTemplateName(config_param_templates,
|
||||||
n_config_param_templates,
|
n_config_param_templates,
|
||||||
@@ -120,7 +120,7 @@ ParseConfigOptionName(const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ConfigBlockOption
|
ConfigBlockOption
|
||||||
ParseConfigBlockOptionName(const char *name)
|
ParseConfigBlockOptionName(const char *name) noexcept
|
||||||
{
|
{
|
||||||
return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
|
return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
|
||||||
n_config_block_templates,
|
n_config_block_templates,
|
||||||
|
@@ -71,7 +71,6 @@ struct ConfigParam {
|
|||||||
*
|
*
|
||||||
* Throws #std::runtime_error on error.
|
* Throws #std::runtime_error on error.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
AllocatedPath GetPath() const;
|
AllocatedPath GetPath() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -62,7 +62,7 @@ Print(Response &r, TagType group, const TagCountMap &m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
stats_visitor_song(SearchStats &stats, const LightSong &song)
|
stats_visitor_song(SearchStats &stats, const LightSong &song)
|
||||||
{
|
{
|
||||||
stats.n_songs++;
|
stats.n_songs++;
|
||||||
@@ -70,8 +70,6 @@ stats_visitor_song(SearchStats &stats, const LightSong &song)
|
|||||||
const auto duration = song.GetDuration();
|
const auto duration = song.GetDuration();
|
||||||
if (!duration.IsNegative())
|
if (!duration.IsNegative())
|
||||||
stats.total_duration += duration;
|
stats.total_duration += duration;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -94,7 +92,7 @@ CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
|
GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
|
||||||
{
|
{
|
||||||
assert(song.tag != nullptr);
|
assert(song.tag != nullptr);
|
||||||
@@ -103,8 +101,6 @@ GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
|
|||||||
if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST)
|
if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST)
|
||||||
/* fall back to "Artist" if no "AlbumArtist" was found */
|
/* fall back to "Artist" if no "AlbumArtist" was found */
|
||||||
CollectGroupCounts(map, TAG_ARTIST, tag);
|
CollectGroupCounts(map, TAG_ARTIST, tag);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -37,5 +37,10 @@ DatabaseGlobalInit(EventLoop &loop, DatabaseListener &listener,
|
|||||||
throw FormatRuntimeError("No such database plugin: %s",
|
throw FormatRuntimeError("No such database plugin: %s",
|
||||||
plugin_name);
|
plugin_name);
|
||||||
|
|
||||||
return plugin->create(loop, listener, block);
|
try {
|
||||||
|
return plugin->create(loop, listener, block);
|
||||||
|
} catch (...) {
|
||||||
|
std::throw_with_nested(FormatRuntimeError("Failed to initialize database plugin '%s'",
|
||||||
|
plugin_name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,7 @@ extern ThreadId db_mutex_holder;
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static inline bool
|
static inline bool
|
||||||
holding_db_lock(void)
|
holding_db_lock() noexcept
|
||||||
{
|
{
|
||||||
return db_mutex_holder.IsInside();
|
return db_mutex_holder.IsInside();
|
||||||
}
|
}
|
||||||
|
@@ -27,13 +27,12 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
AddSong(const Storage &storage, const char *playlist_path_utf8,
|
AddSong(const Storage &storage, const char *playlist_path_utf8,
|
||||||
const LightSong &song)
|
const LightSong &song)
|
||||||
{
|
{
|
||||||
spl_append_song(playlist_path_utf8,
|
spl_append_song(playlist_path_utf8,
|
||||||
DatabaseDetachSong(storage, song));
|
DatabaseDetachSong(storage, song));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -49,16 +49,14 @@ PrintDirectoryURI(Response &r, bool base, const LightDirectory &directory)
|
|||||||
ApplyBaseFlag(directory.GetPath(), base));
|
ApplyBaseFlag(directory.GetPath(), base));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
|
PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
|
||||||
{
|
{
|
||||||
if (!directory.IsRoot())
|
if (!directory.IsRoot())
|
||||||
PrintDirectoryURI(r, base, directory);
|
PrintDirectoryURI(r, base, directory);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
|
PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
|
||||||
{
|
{
|
||||||
if (!directory.IsRoot()) {
|
if (!directory.IsRoot()) {
|
||||||
@@ -67,8 +65,6 @@ PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
|
|||||||
if (directory.mtime > 0)
|
if (directory.mtime > 0)
|
||||||
time_print(r, "Last-Modified", directory.mtime);
|
time_print(r, "Last-Modified", directory.mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -96,7 +92,7 @@ print_playlist_in_directory(Response &r, bool base,
|
|||||||
directory->GetPath(), name_utf8);
|
directory->GetPath(), name_utf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintSongBrief(Response &r, Partition &partition,
|
PrintSongBrief(Response &r, Partition &partition,
|
||||||
bool base, const LightSong &song)
|
bool base, const LightSong &song)
|
||||||
{
|
{
|
||||||
@@ -106,11 +102,9 @@ PrintSongBrief(Response &r, Partition &partition,
|
|||||||
/* this song file has an embedded CUE sheet */
|
/* this song file has an embedded CUE sheet */
|
||||||
print_playlist_in_directory(r, base,
|
print_playlist_in_directory(r, base,
|
||||||
song.directory, song.uri);
|
song.directory, song.uri);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintSongFull(Response &r, Partition &partition,
|
PrintSongFull(Response &r, Partition &partition,
|
||||||
bool base, const LightSong &song)
|
bool base, const LightSong &song)
|
||||||
{
|
{
|
||||||
@@ -120,21 +114,18 @@ PrintSongFull(Response &r, Partition &partition,
|
|||||||
/* this song file has an embedded CUE sheet */
|
/* this song file has an embedded CUE sheet */
|
||||||
print_playlist_in_directory(r, base,
|
print_playlist_in_directory(r, base,
|
||||||
song.directory, song.uri);
|
song.directory, song.uri);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintPlaylistBrief(Response &r, bool base,
|
PrintPlaylistBrief(Response &r, bool base,
|
||||||
const PlaylistInfo &playlist,
|
const PlaylistInfo &playlist,
|
||||||
const LightDirectory &directory)
|
const LightDirectory &directory)
|
||||||
{
|
{
|
||||||
print_playlist_in_directory(r, base,
|
print_playlist_in_directory(r, base,
|
||||||
&directory, playlist.name.c_str());
|
&directory, playlist.name.c_str());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintPlaylistFull(Response &r, bool base,
|
PrintPlaylistFull(Response &r, bool base,
|
||||||
const PlaylistInfo &playlist,
|
const PlaylistInfo &playlist,
|
||||||
const LightDirectory &directory)
|
const LightDirectory &directory)
|
||||||
@@ -144,8 +135,6 @@ PrintPlaylistFull(Response &r, bool base,
|
|||||||
|
|
||||||
if (playlist.mtime > 0)
|
if (playlist.mtime > 0)
|
||||||
time_print(r, "Last-Modified", playlist.mtime);
|
time_print(r, "Last-Modified", playlist.mtime);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -191,15 +180,13 @@ db_selection_print(Response &r, Partition &partition,
|
|||||||
0, std::numeric_limits<int>::max());
|
0, std::numeric_limits<int>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
|
PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
|
||||||
{
|
{
|
||||||
song_print_uri(r, partition, song);
|
song_print_uri(r, partition, song);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
PrintUniqueTag(Response &r, TagType tag_type,
|
PrintUniqueTag(Response &r, TagType tag_type,
|
||||||
const Tag &tag)
|
const Tag &tag)
|
||||||
{
|
{
|
||||||
@@ -211,8 +198,6 @@ PrintUniqueTag(Response &r, TagType tag_type,
|
|||||||
if (item.type != tag_type)
|
if (item.type != tag_type)
|
||||||
r.Format("%s: %s\n",
|
r.Format("%s: %s\n",
|
||||||
tag_item_names[item.type], item.value);
|
tag_item_names[item.type], item.value);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -27,14 +27,13 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
AddToQueue(Partition &partition, const LightSong &song)
|
AddToQueue(Partition &partition, const LightSong &song)
|
||||||
{
|
{
|
||||||
const Storage &storage = *partition.instance.storage;
|
const Storage &storage = *partition.instance.storage;
|
||||||
partition.playlist.AppendSong(partition.pc,
|
partition.playlist.AppendSong(partition.pc,
|
||||||
DatabaseDetachSong(storage,
|
DatabaseDetachSong(storage,
|
||||||
song));
|
song));
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -31,7 +31,6 @@ class DetachedSong;
|
|||||||
* "Detach" the #Song object, i.e. convert it to a #DetachedSong
|
* "Detach" the #Song object, i.e. convert it to a #DetachedSong
|
||||||
* instance.
|
* instance.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
|
||||||
DetachedSong
|
DetachedSong
|
||||||
DatabaseDetachSong(const Storage &storage, const LightSong &song);
|
DatabaseDetachSong(const Storage &storage, const LightSong &song);
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
struct StringLess {
|
struct StringLess {
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator()(const char *a, const char *b) const {
|
bool operator()(const char *a, const char *b) const noexcept {
|
||||||
return strcmp(a, b) < 0;
|
return strcmp(a, b) < 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -67,15 +67,13 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
|
||||||
const LightSong &song)
|
const LightSong &song)
|
||||||
{
|
{
|
||||||
++stats.song_count;
|
++stats.song_count;
|
||||||
|
|
||||||
StatsVisitTag(stats, artists, albums, *song.tag);
|
StatsVisitTag(stats, artists, albums, *song.tag);
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseStats
|
DatabaseStats
|
||||||
|
@@ -106,7 +106,6 @@ public:
|
|||||||
TagType tag_type, tag_mask_t group_mask,
|
TagType tag_type, tag_mask_t group_mask,
|
||||||
VisitTag visit_tag) const = 0;
|
VisitTag visit_tag) const = 0;
|
||||||
|
|
||||||
gcc_pure
|
|
||||||
virtual DatabaseStats GetStats(const DatabaseSelection &selection) const = 0;
|
virtual DatabaseStats GetStats(const DatabaseSelection &selection) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,7 +126,7 @@ public:
|
|||||||
* Returns 0 if that is not not known/available.
|
* Returns 0 if that is not not known/available.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
virtual time_t GetUpdateStamp() const = 0;
|
virtual time_t GetUpdateStamp() const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -44,16 +44,16 @@ struct LightDirectory {
|
|||||||
constexpr LightDirectory(const char *_uri, time_t _mtime)
|
constexpr LightDirectory(const char *_uri, time_t _mtime)
|
||||||
:uri(_uri), mtime(_mtime) {}
|
:uri(_uri), mtime(_mtime) {}
|
||||||
|
|
||||||
static constexpr LightDirectory Root() {
|
static constexpr LightDirectory Root() noexcept {
|
||||||
return LightDirectory("", 0);
|
return LightDirectory("", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRoot() const {
|
bool IsRoot() const noexcept {
|
||||||
return *uri == 0;
|
return *uri == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetPath() const {
|
const char *GetPath() const noexcept {
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -21,7 +21,7 @@
|
|||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
|
|
||||||
SignedSongTime
|
SignedSongTime
|
||||||
LightSong::GetDuration() const
|
LightSong::GetDuration() const noexcept
|
||||||
{
|
{
|
||||||
SongTime a = start_time, b = end_time;
|
SongTime a = start_time, b = end_time;
|
||||||
if (!b.IsPositive()) {
|
if (!b.IsPositive()) {
|
||||||
|
@@ -76,7 +76,7 @@ struct LightSong {
|
|||||||
SongTime end_time;
|
SongTime end_time;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
std::string GetURI() const {
|
std::string GetURI() const noexcept {
|
||||||
if (directory == nullptr)
|
if (directory == nullptr)
|
||||||
return std::string(uri);
|
return std::string(uri);
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ struct LightSong {
|
|||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
SignedSongTime GetDuration() const;
|
SignedSongTime GetDuration() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -45,7 +45,7 @@ struct PlaylistInfo {
|
|||||||
constexpr CompareName(const char *_name):name(_name) {}
|
constexpr CompareName(const char *_name):name(_name) {}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool operator()(const PlaylistInfo &pi) const {
|
bool operator()(const PlaylistInfo &pi) const noexcept {
|
||||||
return pi.name.compare(name) == 0;
|
return pi.name.compare(name) == 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
PlaylistVector::iterator
|
PlaylistVector::iterator
|
||||||
PlaylistVector::find(const char *name)
|
PlaylistVector::find(const char *name) noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
assert(name != nullptr);
|
assert(name != nullptr);
|
||||||
|
@@ -31,7 +31,7 @@ protected:
|
|||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
iterator find(const char *name);
|
iterator find(const char *name) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using std::list<PlaylistInfo>::empty;
|
using std::list<PlaylistInfo>::empty;
|
||||||
|
@@ -38,7 +38,7 @@ const DatabasePlugin *const database_plugins[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DatabasePlugin *
|
const DatabasePlugin *
|
||||||
GetDatabasePluginByName(const char *name)
|
GetDatabasePluginByName(const char *name) noexcept
|
||||||
{
|
{
|
||||||
for (auto i = database_plugins; *i != nullptr; ++i)
|
for (auto i = database_plugins; *i != nullptr; ++i)
|
||||||
if (strcmp((*i)->name, name) == 0)
|
if (strcmp((*i)->name, name) == 0)
|
||||||
|
@@ -32,6 +32,6 @@ extern const DatabasePlugin *const database_plugins[];
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const DatabasePlugin *
|
const DatabasePlugin *
|
||||||
GetDatabasePluginByName(const char *name);
|
GetDatabasePluginByName(const char *name) noexcept;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
#include "Selection.hxx"
|
#include "Selection.hxx"
|
||||||
#include "SongFilter.hxx"
|
#include "SongFilter.hxx"
|
||||||
|
|
||||||
@@ -34,19 +35,19 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DatabaseSelection::IsEmpty() const
|
DatabaseSelection::IsEmpty() const noexcept
|
||||||
{
|
{
|
||||||
return uri.empty() && (filter == nullptr || filter->IsEmpty());
|
return uri.empty() && (filter == nullptr || filter->IsEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DatabaseSelection::HasOtherThanBase() const
|
DatabaseSelection::HasOtherThanBase() const noexcept
|
||||||
{
|
{
|
||||||
return filter != nullptr && filter->HasOtherThanBase();
|
return filter != nullptr && filter->HasOtherThanBase();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DatabaseSelection::Match(const LightSong &song) const
|
DatabaseSelection::Match(const LightSong &song) const noexcept
|
||||||
{
|
{
|
||||||
return filter == nullptr || filter->Match(song);
|
return filter == nullptr || filter->Match(song);
|
||||||
}
|
}
|
||||||
|
@@ -45,16 +45,16 @@ struct DatabaseSelection {
|
|||||||
const SongFilter *_filter=nullptr);
|
const SongFilter *_filter=nullptr);
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const;
|
bool IsEmpty() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this selection contain constraints other than "base"?
|
* Does this selection contain constraints other than "base"?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool HasOtherThanBase() const;
|
bool HasOtherThanBase() const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool Match(const LightSong &song) const;
|
bool Match(const LightSong &song) const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include "tag/TagBuilder.hxx"
|
#include "tag/TagBuilder.hxx"
|
||||||
#include "tag/Tag.hxx"
|
#include "tag/Tag.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
#include "util/RuntimeError.hxx"
|
||||||
#include "protocol/Ack.hxx"
|
#include "protocol/Ack.hxx"
|
||||||
#include "event/SocketMonitor.hxx"
|
#include "event/SocketMonitor.hxx"
|
||||||
#include "event/IdleMonitor.hxx"
|
#include "event/IdleMonitor.hxx"
|
||||||
@@ -46,7 +47,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
class LibmpdclientError final : std::runtime_error {
|
class LibmpdclientError final : public std::runtime_error {
|
||||||
enum mpd_error code;
|
enum mpd_error code;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -108,8 +109,8 @@ public:
|
|||||||
static Database *Create(EventLoop &loop, DatabaseListener &listener,
|
static Database *Create(EventLoop &loop, DatabaseListener &listener,
|
||||||
const ConfigBlock &block);
|
const ConfigBlock &block);
|
||||||
|
|
||||||
virtual void Open() override;
|
void Open() override;
|
||||||
virtual void Close() override;
|
void Close() override;
|
||||||
const LightSong *GetSong(const char *uri_utf8) const override;
|
const LightSong *GetSong(const char *uri_utf8) const override;
|
||||||
void ReturnSong(const LightSong *song) const override;
|
void ReturnSong(const LightSong *song) const override;
|
||||||
|
|
||||||
@@ -126,7 +127,7 @@ public:
|
|||||||
|
|
||||||
unsigned Update(const char *uri_utf8, bool discard) override;
|
unsigned Update(const char *uri_utf8, bool discard) override;
|
||||||
|
|
||||||
virtual time_t GetUpdateStamp() const override {
|
time_t GetUpdateStamp() const noexcept override {
|
||||||
return update_stamp;
|
return update_stamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +139,10 @@ private:
|
|||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
|
||||||
/* virtual methods from SocketMonitor */
|
/* virtual methods from SocketMonitor */
|
||||||
virtual bool OnSocketReady(unsigned flags) override;
|
bool OnSocketReady(unsigned flags) override;
|
||||||
|
|
||||||
/* virtual methods from IdleMonitor */
|
/* virtual methods from IdleMonitor */
|
||||||
virtual void OnIdle() override;
|
void OnIdle() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr struct {
|
static constexpr struct {
|
||||||
@@ -215,7 +216,7 @@ ProxySong::ProxySong(const mpd_song *song)
|
|||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static enum mpd_tag_type
|
static enum mpd_tag_type
|
||||||
Convert(TagType tag_type)
|
Convert(TagType tag_type) noexcept
|
||||||
{
|
{
|
||||||
for (auto i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
|
for (auto i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
|
||||||
if (i->d == tag_type)
|
if (i->d == tag_type)
|
||||||
@@ -345,9 +346,15 @@ ProxyDatabase::Create(EventLoop &loop, DatabaseListener &listener,
|
|||||||
void
|
void
|
||||||
ProxyDatabase::Open()
|
ProxyDatabase::Open()
|
||||||
{
|
{
|
||||||
Connect();
|
|
||||||
|
|
||||||
update_stamp = 0;
|
update_stamp = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Connect();
|
||||||
|
} catch (const std::runtime_error &error) {
|
||||||
|
/* this error is non-fatal, because this plugin will
|
||||||
|
attempt to reconnect again automatically */
|
||||||
|
LogError(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -371,7 +378,10 @@ ProxyDatabase::Connect()
|
|||||||
mpd_connection_free(connection);
|
mpd_connection_free(connection);
|
||||||
connection = nullptr;
|
connection = nullptr;
|
||||||
|
|
||||||
throw;
|
std::throw_with_nested(host.empty()
|
||||||
|
? std::runtime_error("Failed to connect to remote MPD")
|
||||||
|
: FormatRuntimeError("Failed to connect to remote MPD '%s'",
|
||||||
|
host.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
|
#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
|
||||||
@@ -564,7 +574,7 @@ Visit(struct mpd_connection *connection,
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
Match(const SongFilter *filter, const LightSong &song)
|
Match(const SongFilter *filter, const LightSong &song) noexcept
|
||||||
{
|
{
|
||||||
return filter == nullptr || filter->Match(song);
|
return filter == nullptr || filter->Match(song);
|
||||||
}
|
}
|
||||||
@@ -707,7 +717,7 @@ SearchSongs(struct mpd_connection *connection,
|
|||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
ServerSupportsSearchBase(const struct mpd_connection *connection)
|
ServerSupportsSearchBase(const struct mpd_connection *connection) noexcept
|
||||||
{
|
{
|
||||||
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
|
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
|
||||||
return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0;
|
return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0;
|
||||||
|
@@ -65,7 +65,7 @@ Directory::Delete()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
Directory::GetName() const
|
Directory::GetName() const noexcept
|
||||||
{
|
{
|
||||||
assert(!IsRoot());
|
assert(!IsRoot());
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ Directory::CreateChild(const char *name_utf8)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Directory *
|
const Directory *
|
||||||
Directory::FindChild(const char *name) const
|
Directory::FindChild(const char *name) const noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ Directory::FindChild(const char *name) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Directory::PruneEmpty()
|
Directory::PruneEmpty() noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ Directory::PruneEmpty()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Directory::LookupResult
|
Directory::LookupResult
|
||||||
Directory::LookupDirectory(const char *uri)
|
Directory::LookupDirectory(const char *uri) noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
assert(uri != nullptr);
|
assert(uri != nullptr);
|
||||||
@@ -173,7 +173,7 @@ Directory::AddSong(Song *song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Directory::RemoveSong(Song *song)
|
Directory::RemoveSong(Song *song) noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
assert(song != nullptr);
|
assert(song != nullptr);
|
||||||
@@ -183,7 +183,7 @@ Directory::RemoveSong(Song *song)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Song *
|
const Song *
|
||||||
Directory::FindSong(const char *name_utf8) const
|
Directory::FindSong(const char *name_utf8) const noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
assert(name_utf8 != nullptr);
|
assert(name_utf8 != nullptr);
|
||||||
@@ -200,13 +200,13 @@ Directory::FindSong(const char *name_utf8) const
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static bool
|
static bool
|
||||||
directory_cmp(const Directory &a, const Directory &b)
|
directory_cmp(const Directory &a, const Directory &b) noexcept
|
||||||
{
|
{
|
||||||
return IcuCollate(a.path.c_str(), b.path.c_str()) < 0;
|
return IcuCollate(a.path.c_str(), b.path.c_str()) < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Directory::Sort()
|
Directory::Sort() noexcept
|
||||||
{
|
{
|
||||||
assert(holding_db_lock());
|
assert(holding_db_lock());
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ Directory::Walk(bool recursive, const SongFilter *filter,
|
|||||||
}
|
}
|
||||||
|
|
||||||
LightDirectory
|
LightDirectory
|
||||||
Directory::Export() const
|
Directory::Export() const noexcept
|
||||||
{
|
{
|
||||||
return LightDirectory(GetPath(), mtime);
|
return LightDirectory(GetPath(), mtime);
|
||||||
}
|
}
|
||||||
|
@@ -86,7 +86,7 @@ struct Directory {
|
|||||||
|
|
||||||
Directory *parent;
|
Directory *parent;
|
||||||
time_t mtime;
|
time_t mtime;
|
||||||
unsigned inode, device;
|
uint64_t inode, device;
|
||||||
|
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
@@ -134,10 +134,10 @@ public:
|
|||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const Directory *FindChild(const char *name) const;
|
const Directory *FindChild(const char *name) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
Directory *FindChild(const char *name) {
|
Directory *FindChild(const char *name) noexcept {
|
||||||
const Directory *cthis = this;
|
const Directory *cthis = this;
|
||||||
return const_cast<Directory *>(cthis->FindChild(name));
|
return const_cast<Directory *>(cthis->FindChild(name));
|
||||||
}
|
}
|
||||||
@@ -177,17 +177,17 @@ public:
|
|||||||
* @return the Directory, or nullptr if none was found
|
* @return the Directory, or nullptr if none was found
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
LookupResult LookupDirectory(const char *uri);
|
LookupResult LookupDirectory(const char *uri) noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsEmpty() const {
|
bool IsEmpty() const noexcept {
|
||||||
return children.empty() &&
|
return children.empty() &&
|
||||||
songs.empty() &&
|
songs.empty() &&
|
||||||
playlists.empty();
|
playlists.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetPath() const {
|
const char *GetPath() const noexcept {
|
||||||
return path.c_str();
|
return path.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,13 +195,13 @@ public:
|
|||||||
* Returns the base name of the directory.
|
* Returns the base name of the directory.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const char *GetName() const;
|
const char *GetName() const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this the root directory of the music database?
|
* Is this the root directory of the music database?
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
bool IsRoot() const {
|
bool IsRoot() const noexcept {
|
||||||
return parent == nullptr;
|
return parent == nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,10 +229,10 @@ public:
|
|||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
gcc_pure
|
gcc_pure
|
||||||
const Song *FindSong(const char *name_utf8) const;
|
const Song *FindSong(const char *name_utf8) const noexcept;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
Song *FindSong(const char *name_utf8) {
|
Song *FindSong(const char *name_utf8) noexcept {
|
||||||
const Directory *cthis = this;
|
const Directory *cthis = this;
|
||||||
return const_cast<Song *>(cthis->FindSong(name_utf8));
|
return const_cast<Song *>(cthis->FindSong(name_utf8));
|
||||||
}
|
}
|
||||||
@@ -248,19 +248,19 @@ public:
|
|||||||
* invalidates the song object, because the "parent" attribute becomes
|
* invalidates the song object, because the "parent" attribute becomes
|
||||||
* stale), but does not free it.
|
* stale), but does not free it.
|
||||||
*/
|
*/
|
||||||
void RemoveSong(Song *song);
|
void RemoveSong(Song *song) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
void PruneEmpty();
|
void PruneEmpty() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort all directory entries recursively.
|
* Sort all directory entries recursively.
|
||||||
*
|
*
|
||||||
* Caller must lock the #db_mutex.
|
* Caller must lock the #db_mutex.
|
||||||
*/
|
*/
|
||||||
void Sort();
|
void Sort() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caller must lock #db_mutex.
|
* Caller must lock #db_mutex.
|
||||||
@@ -270,7 +270,7 @@ public:
|
|||||||
VisitPlaylist visit_playlist) const;
|
VisitPlaylist visit_playlist) const;
|
||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
LightDirectory Export() const;
|
LightDirectory Export() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
gcc_const
|
gcc_const
|
||||||
static const char *
|
static const char *
|
||||||
DeviceToTypeString(unsigned device)
|
DeviceToTypeString(unsigned device) noexcept
|
||||||
{
|
{
|
||||||
switch (device) {
|
switch (device) {
|
||||||
case DEVICE_INARCHIVE:
|
case DEVICE_INARCHIVE:
|
||||||
@@ -56,7 +56,7 @@ DeviceToTypeString(unsigned device)
|
|||||||
|
|
||||||
gcc_pure
|
gcc_pure
|
||||||
static unsigned
|
static unsigned
|
||||||
ParseTypeString(const char *type)
|
ParseTypeString(const char *type) noexcept
|
||||||
{
|
{
|
||||||
if (strcmp(type, "archive") == 0)
|
if (strcmp(type, "archive") == 0)
|
||||||
return DEVICE_INARCHIVE;
|
return DEVICE_INARCHIVE;
|
||||||
|
@@ -25,6 +25,13 @@
|
|||||||
#include "db/Interface.hxx"
|
#include "db/Interface.hxx"
|
||||||
#include "fs/Traits.hxx"
|
#include "fs/Traits.hxx"
|
||||||
|
|
||||||
|
#ifdef _LIBCPP_VERSION
|
||||||
|
/* workaround for "error: incomplete type 'PlaylistInfo' used in type
|
||||||
|
trait expression" with libc++ version 3900 (from Android NDK
|
||||||
|
r13b) */
|
||||||
|
#include "db/PlaylistInfo.hxx"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
struct PrefixedLightDirectory : LightDirectory {
|
struct PrefixedLightDirectory : LightDirectory {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user