Compare commits

...

388 Commits

Author SHA1 Message Date
Max Kellermann
975a4ae871 release v0.20.16 2018-02-03 19:55:07 +01:00
Max Kellermann
56aaf3c73e python/build/libs: upgrade CURL to 7.58.0 2018-02-03 19:46:31 +01:00
Max Kellermann
12fd1cad0c archive/iso9660: libcdio 2.0 compatibility
Closes 
2018-02-03 19:32:31 +01:00
Max Kellermann
e573cbf032 db/update/Queue: work around GCC7 -Wuninitialized 2018-02-01 19:53:42 +01:00
Max Kellermann
dead461542 lib/upnp/Init: enable IPv6 2018-01-31 18:15:46 +01:00
Max Kellermann
3d5da1ac73 lib/upnp/Init: use nullptr instead of 0 2018-01-31 18:14:26 +01:00
Max Kellermann
ec408ca6a6 output/pulse: fix crash during auto-detection
The PulseOutput needs to be "enabled" before WaitConnection() may be
called.

Closes 
2018-01-30 10:06:36 +01:00
Max Kellermann
ea66cdd6a5 test/read_mixer: another kludge to work around -Wnull-dereference 2018-01-23 16:42:25 +01:00
Max Kellermann
f762e8034f test/NullMixerListener: new class to fix -Wnull-dereference 2018-01-23 16:28:56 +01:00
Max Kellermann
bb1e369f30 playlist/SoundCloud: fix -Wunused-lambda-capture 2018-01-23 09:57:52 +01:00
Max Kellermann
8376578921 db/simple/Mount: drop mount point prefix from LOCATE_TAG_BASE_TYPE
Fixes search within mount points, resulting in error "No such
directory".

Closes 
2018-01-19 23:52:57 +01:00
Max Kellermann
ed2354cd9d SongFilter: allow copying items 2018-01-19 23:52:03 +01:00
Max Kellermann
386688b87a SongFilter: use std::string instead of AllocatedString 2018-01-19 23:51:42 +01:00
Max Kellermann
38d56dddf1 lib/icu/Compare: allow copying 2018-01-19 23:49:50 +01:00
Max Kellermann
e8975942ec Makefile.am: link libicu.a before libutil.a
libicu.a depends on libutil.a.
2018-01-19 23:38:24 +01:00
Max Kellermann
3ca80a7336 util/RefCount, db/simple/Mount: remove obsolete libc++ workarounds
No longer a problem with NDK r16.
2018-01-19 23:19:46 +01:00
Max Kellermann
d029dae7ad Makefile.am: use Android SDK build-tools 27.0.0 2018-01-19 23:04:54 +01:00
Max Kellermann
9e058732ee android/build.py: add -fpic
Android native code should be position-independent.

The NDK build scripts use "-fpic" instead of "-fPIC" for ARM, but that
doesn't work with FFmpeg's assembly code, because it requires
R_ARM_MOVW_ABS_NC which is unavailable with "-fpic".
2018-01-19 22:40:59 +01:00
Max Kellermann
cad5d11261 android/build.py: simplify libc++ flags
By telling clang which implementation to use, we avoid the dependency
on libstdc++.so.
2018-01-19 22:36:19 +01:00
Max Kellermann
fcaedec2ab {android,win32}/build.py: move "-O* -g" to common_flags 2018-01-19 12:33:28 +01:00
Max Kellermann
ead9d59e88 python/build/libs.py: build only libFLAC, no programs 2018-01-19 12:33:03 +01:00
Max Kellermann
34b8a17ccd python/build/autotools.py: add "subdir" parameter 2018-01-19 11:39:36 +01:00
Max Kellermann
a53d081c39 python/build/libs.py: disable libFLAC API documentation 2018-01-19 11:38:24 +01:00
Max Kellermann
823134e4ba python/build/libs.py: disable Opus documentation and extra programs 2018-01-19 11:32:40 +01:00
Max Kellermann
272167b4fc python/build/libs.py: update LAME to 3.100 2018-01-18 22:07:28 +01:00
Max Kellermann
92f09bba94 Makefile.am: rename JAVA_SOURCES to JAVA_SOURCE_PATHS
Work around automake warning:

    Makefile.am:310: warning: variable 'JAVA_SOURCES' is defined but no program or
    Makefile.am:310: library has 'JAVA' as canonical name (possible typo)

Closes 
2018-01-18 22:05:04 +01:00
Max Kellermann
1f50bdb230 event/Loop: use std::atomic_bool for the "quit" variable
Fixes thread sanitizer warnings.
2018-01-08 10:06:23 +01:00
Max Kellermann
2eef4e6716 thread/Thread: add debug attribute "inside_handle"
This attribute shall be used only for IsInside() to make this safe
against a race condition described in :

> There is no requirement on the implementation that the ID of the
> created thread be available before the newly created thread starts
> executing.

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_create.html):

This means that on some pthread implementations (e.g. Haiku), the
assert(thread.IsInside()) could fail.

Closes 
2018-01-08 09:58:18 +01:00
Max Kellermann
d989dbfec4 thread/Thread: make IsInside() debug-only
This method is only used inside assert().
2018-01-08 09:56:39 +01:00
Max Kellermann
ca9fcec364 thread/Thread: fix indent 2018-01-08 09:49:08 +01:00
Max Kellermann
354104f9a9 thread/{Thread,Id}: use defaul-initialized pthread_t as "undefined" value
Use the "==" operator instead of pthread_equal().

This allows us to eliminate two boolean flags which are there to avoid
race conditions, and made the thing so fragile that I got tons of
(correct) thread sanitizer warnings.
2018-01-07 17:20:26 +01:00
Max Kellermann
8649ea3d6f thread/Thread: use BoundMethod 2018-01-07 17:20:26 +01:00
Max Kellermann
752ff12c37 thread/Thread: move code to Run() 2018-01-07 17:20:26 +01:00
Max Kellermann
4bb89b1755 MusicPipe: lock the mutex in Peek() and GetSize() 2018-01-07 17:20:22 +01:00
Max Kellermann
0ef553d30e increment version number to 0.20.16 2018-01-06 13:15:47 +01:00
Max Kellermann
43a62aef07 android: release 0.20.15 2018-01-05 18:09:56 +01:00
Max Kellermann
ed4d0aa909 release v0.20.15 2018-01-05 17:55:25 +01:00
Max Kellermann
023ce4e720 python/build/libs.py: disable even more FFmpeg modules 2018-01-05 17:41:58 +01:00
Max Kellermann
368d9359dd python/build/libs.py: update libogg to 1.3.3 2018-01-05 17:41:58 +01:00
Max Kellermann
d98c19d561 python/build/libs.py: disable more FFmpeg modules 2018-01-05 16:49:28 +01:00
Max Kellermann
cab77e35e0 queue/PlaylistControl: fix crash after seek failure
This completes the bug fix commit
2065e3290452377b2931f3129b230c8cc536cbc8; if we clear "queued" then we
must clear "queued_song" as well, or another variant of the assertion
fails.
2018-01-05 13:00:24 +01:00
Max Kellermann
e3e90b4b93 python/build/libs.py: disable libcurl SMB support
MPD doesn't use this feature anyway.
2018-01-05 12:00:29 +01:00
Max Kellermann
f8c69893e1 python/build/libs.py: disable lots of useless FFmpeg features 2018-01-05 11:11:20 +01:00
Max Kellermann
49678a0893 python/build/libs.py: suppress "visibility default" in libopus build 2018-01-05 10:33:53 +01:00
Max Kellermann
d667b5b48c python/build/libs.py: work around libid3tag CFLAGS bug 2018-01-05 10:25:16 +01:00
Max Kellermann
9cba55b39c python/build/project.py: add "edits" parameter to edit source files 2018-01-05 10:06:22 +01:00
Max Kellermann
c2cbb7b8ce output/haiku: remove unimplemented Cancel() method 2018-01-05 10:05:14 +01:00
Felix Hädicke
8217d75ca1 build/python: refactoring: introduce new class MakeProject
This introduces a the new class MakeProject, which is used as a base
class for all Makefile based thirdparty libraries.
2018-01-05 08:17:17 +01:00
Max Kellermann
1ca70d9759 build/python/autotools: add properties "ldflags", "libs", "install_target" 2018-01-05 08:17:15 +01:00
Felix Hädicke
4303aaa9b8 build/python: use "glibtoolize", not "libtoolize" when compiling on OS X
On OS X, the "libtoolize" command is some Apple tool. The libtoolize
we want is named "glibtoolize" in Homebrew.
2018-01-05 07:55:59 +01:00
Max Kellermann
7b56bae289 python/build/libs.py: pass --disable-debugging to libid3tag and libmad 2018-01-05 07:30:09 +01:00
Max Kellermann
4183416b3e python/build/libs.py: reindent arrays 2018-01-05 07:27:09 +01:00
Max Kellermann
a60dee57ce python/libs: upgrade Boost to 1.66.0 2018-01-05 07:16:38 +01:00
Max Kellermann
5724656acb android/build.py: enable function/data sections in static libraries
.. and make all library symbols hidden by default.

Saves big amounts of .text section size with --gc-sections, because
only this allows discarding unused functions from those (static)
third-party libraries.
2018-01-04 23:33:07 +01:00
Max Kellermann
329f9cd9fe thread/Util: no ioprio_set() on Android due to seccomp/SIGSYS 2018-01-04 19:33:14 +01:00
Felix Hädicke
fbdb8b406e Makefile.am: build Android APK package without Ant
In current Android SDK releases, Ant support was removed. Move the
necessary build steps from the former Ant build system to our Makefile,
and call the required build tools from the Android SDK (aapt and dx),
Java SDK (javac) and Info-ZIP (zip) directly.

[mk: copied from Felix's commit
e52b906dba971a1173f9e8f83d32b52ee9f89af3 in the XCSoar project)
2018-01-04 18:55:54 +01:00
Max Kellermann
85d0bbd957 Makefile.am: add variable ZIPALIGN 2018-01-04 18:55:45 +01:00
Max Kellermann
414f00d6ae Makefile.am: add variable ANDROID_SDK_PLATFORM 2018-01-04 18:47:52 +01:00
Max Kellermann
17b0add058 filter/Observer: pass Reset() to underlying Filter
Wohooooo, the method Filter::Reset() has been broken because no
implementation of it has ever been called for a loooong time.
And nobody ever noticed it.  WTF.
2018-01-02 22:13:14 +01:00
Max Kellermann
c68ed40661 pcm/SoxrResampler: implement method Reset() 2018-01-02 21:53:09 +01:00
Max Kellermann
ff624075a8 storage/State: check if a CompositeStorage exists; fixes nullptr dereference
Fixes another crash bug caused by commit
64d141f71e
2018-01-02 14:13:26 +01:00
Max Kellermann
08db28469d storage/State: make mount errors non-fatal
Fixes crash bug caused by commit
64d141f71e
2018-01-02 14:07:52 +01:00
Max Kellermann
a20b326807 storage/State: fix memory leak after database mount failure
Caused by commit 64d141f71e

This wasn't a serious memory leak, because after a mount failure, MPD
would abort anyway, which is subject to the next commit.
2018-01-02 14:05:07 +01:00
Max Kellermann
4db1b1b250 storage/State: remove useless #ifdef ENABLE_DATABASE
This source file isn't compiled when the database is disabled.
2018-01-02 13:48:16 +01:00
Max Kellermann
ff6b263b48 increment version number to 0.20.15 2018-01-02 13:46:03 +01:00
Max Kellermann
c0bf052fa9 release v0.20.14 2018-01-01 17:55:38 +01:00
loujine
5419cff925 [doc] Fix outdated MusicBrainz URLs (closes ) 2018-01-01 17:30:24 +01:00
Max Kellermann
eee10ad2ed input/curl: add missing mutex locks to OnEnd(), OnError() 2017-12-26 20:01:13 +01:00
Max Kellermann
98472a8104 pcm/SampleFormat: remove wrong "malloc" attribute 2017-12-23 08:38:22 +01:00
Max Kellermann
d094c168aa archive/{iso9660,zzip}: unlock the mutex during I/O
Similar to commit 31ab78ae8e
2017-12-22 16:09:03 +01:00
Max Kellermann
4b18460bc6 archive/bz2: unlock the archive mutex and lock the file mutex
Fixes deadlock because FileInputStream::Read() unlocks the mutex
(which was not locked) and then locks it, keeping it locked.  This can
result in a deadlock.  This happens because the archive and the file
mutex are different.
2017-12-22 16:02:23 +01:00
Max Kellermann
412c0a965c util/WStringAPI: fix indent 2017-12-21 18:45:26 +01:00
Ilya ilyxa Tyshchenko
2becf79223 correct action for compile on Solaris 11.3 X86 2017-12-21 18:42:36 +01:00
Max Kellermann
43ec96d4a0 command/Error: translate std::{length_error,out_of_range} to ACK_ERROR_ARG 2017-12-21 10:22:04 +01:00
Max Kellermann
3d1d779da7 storage/State: use std::set instead of sorting a std::list 2017-12-21 10:22:00 +01:00
Max Kellermann
c88056ba83 db/simple: fix file corruption in the presence of mount points
If a directory is a mount point, omit the "directory: " as well.

This bug is years old, but has become more visible now that mount
points are persistent in the state file.
2017-12-21 10:16:52 +01:00
Max Kellermann
e769751221 increment version number to 0.20.14 2017-12-21 10:15:16 +01:00
Max Kellermann
49b9a90c3f release v0.20.13 2017-12-18 23:41:56 +01:00
FlashSystems
64d141f71e Save and restore mountpoints within the state file.
Signed-off-by: FlashSystems <developer@flashsystems.de>
2017-12-18 23:39:01 +01:00
FlashSystems
c488d3123f Fix lsinfo and add for mounted databases.
If `SimpleDatabase::Visit` is called on a database that contains a mounted directry the URIs of the elements passed to the callbacks are not prefixed by the mountpoint path. This leads to lsinfo and add not working because they use the wrong URI. This pull request is using the `WalkMount` helper function to create prefixed versions of `VisitDirectory`, `VisitSong` and `VisitPlaylist` to add the correct prefix to the parameters of the callback functions.
2017-12-18 23:33:08 +01:00
Stefano Miccoli
967af60327 rounds alsa HW mixer volume towards ±∞ depending on sgn(∆ vol)
This alleviates a problem in which 'volume +1' cannot be undo by
'volume -1' when using alsa hw mixer.

Closes 
2017-12-18 21:29:03 +01:00
Yue Wang
f1ef9f9d31 OSXOutputPlugin: set the buffer time to be 100ms
[mk: the following text was copied from
https://github.com/MusicPlayerDaemon/MPD/pull/167]

For certain format (hi-res files) and normal buffer size hardware, The
hardware may at once consume most of the buffers. However, in Delay()
function, MPD is supposed to wait for 25 ms after the next try. it
will create a hiccup. The negative impact is much major than
increasing the latency.

I understand larger buffers come at a price. That's why in my earlier
commit last year I significantly reduced it. However, the buffer size
in CoreAudio is set according to the hardware, which is super small
latency. For instance, the system audio of 2015 generation of macbook
pro has maximum buffer size of 4096 samples, which is just 0.09s for
44.1k framerate, or 0.04s for 96k frames --- . compare to the 0.5 sec
latency alsa plugin has, even if we quadruple it, it's still super
tiny.
2017-12-12 10:56:42 +01:00
Max Kellermann
dfaf08743c *: check defined(_WIN32) instead of defined(WIN32)
Only _WIN32 is defined by the compiler, and WIN32 is not standardized
and may be missing.

Closes 
2017-12-12 10:22:20 +01:00
Max Kellermann
d9552d8a6d android/build.py: support NDK r16 2017-12-12 10:01:47 +01:00
Max Kellermann
7586a8ab2c python/build/libs.py: disable the FFmpeg HEVC decoder due to clang build failure 2017-12-12 10:01:47 +01:00
Max Kellermann
e1a942250b python/build/libs.py: disable more FFmpeg features 2017-12-12 09:57:40 +01:00
Max Kellermann
72be0185de python/libs: upgrade Boost to 1.65.1 2017-12-12 09:16:40 +01:00
Max Kellermann
7e4cbce06b python/build/libs: upgrade CURL to 7.57.0 2017-12-12 09:15:24 +01:00
Max Kellermann
177d62f431 python/build/libs: upgrade FFmpeg to 3.4.1 2017-12-11 19:00:22 +01:00
Uwe Kleine-König
5a11e03725 lib/upnp: use include path without upnp/ prefix and honor pkg-config CFLAGS
If libupnp is installed in a non-standard location we must rely on the
include path provided by $(pkg-config --cflags libupnp). Relative to the
path given from that command no prefix must be used to find the respective
files.
2017-12-11 18:58:09 +01:00
Max Kellermann
75d068b7cd Makefile.am: include Windows cross-build script in source tarball 2017-12-05 11:24:52 +01:00
FlashSystems
1208503888 Removing gcc_malloc attribute from Directory::CreateChild to fix
assignment of `mnt->mounted_database` in `SimpleDatabase::Mount`.
2017-12-03 12:34:08 +01:00
Max Kellermann
de90d401d2 MusicChunk: add magic value IGNORE_REPLAY_GAIN
This fixes spurious replay gain logs when the player inserts silence
chunks, because those silence chunks had no replay gain attached,
resetting the ReplayGainFilter state, flipping it forth and back.
2017-12-03 11:39:12 +01:00
Max Kellermann
396defaea9 MusicChunk: initialize replay_gain_serial on demand 2017-12-03 11:39:07 +01:00
Max Kellermann
18f350cd04 player/Thread: initialize MusicChunk::bit_rate in SendSilence()
This attribute is not particularly important, but it was
uninitialized.
2017-12-03 10:54:14 +01:00
Max Kellermann
478180ebe4 queue/PlaylistEdit: shuffle appended songs only within its priority group
Fixes .
2017-12-02 17:17:02 +01:00
Max Kellermann
4a3059f509 queue/PlaylistControl: don't skip highest priority song on "play"
When starting playback with a specific song which does not have the
highest priority, the previous highest priority song was skipped
completely because its order was "swapped".  This commit changes to a
more expensive operation which inserts the selected song into the
order list.

This fixes a small part of 
2017-12-02 16:25:32 +01:00
Max Kellermann
78728138a0 lib/upnp/Compat: disable the 1.8 API emulation with libupnp 1.6.24
libupnp 1.6.24 added a few badly designed macros which break the MPD
build:

 8177a4195a/

To work around this, we disable our emulation functions (from
714011c81e) on this libupnp version.

Closes 
2017-12-02 14:47:27 +01:00
FlashSystems
63fc98591d Fix for "Mount-Points are purged from database on update/rescan."
Signed-off-by: FlashSystems <developer@flashsystems.de>
2017-11-27 22:34:49 +01:00
Max Kellermann
53def9a682 increment version number to 0.20.13 2017-11-27 22:32:55 +01:00
Max Kellermann
323231d1dd release v0.20.12 2017-11-25 19:32:37 +01:00
Max Kellermann
714011c81e lib/upnp: adapt to libupnp 1.8 API changes
Closes 
2017-11-16 11:39:11 +01:00
Max Kellermann
952ff4207b lib/upnp/Callback: make "evp" parameter const 2017-11-16 11:37:58 +01:00
Max Kellermann
150b16ec2c lib/upnp/Discovery: make Upnp_Discovery pointers const 2017-11-16 11:37:04 +01:00
Max Kellermann
c98bc4a243 playlist/PlaylistRegistry: use LockRewind() instead of Rewind()
Fixes a deadlock caused by commit
31ab78ae8e.  That commit was not
actually bad - just these two calls have always been bad, which went
unnoticed for a long time.
2017-11-14 21:19:22 +01:00
Max Kellermann
014f8cd693 output/httpd: flush encoder after tag
Without the flush, ReadPage() may not return any data, or not all
data.  This may result in incomplete ddata the new "header" page,
corrupting streams with some encoders such as Vorbis.

Fixes 
2017-11-14 12:00:14 +01:00
Max Kellermann
aea37e46e3 encoder/vorbis: default to quality 3
Don't require a quality or bitrate setting.  If nothing is set, don't
fail startup - just go with a good default.  A quality setting of 3 is
what "oggenc" defaults to as well.
2017-11-14 11:30:28 +01:00
Max Kellermann
31ab78ae8e input/{cdio,ffmpeg,file,smbclient}: unlock the mutex during blocking I/O
InputStream::Read() and InputStream::Seek() are called with the mutex
locked.  That means the implementation must not block, or unlock the
mutex before calling into blocking code.

Previously, a slow CD drive could stall the whole MPD process,
including the main thread, due to this problem.

Closes 
2017-11-13 17:13:10 +01:00
Max Kellermann
f82e1453e4 input/smbclient: use std::lock_guard 2017-11-13 17:13:10 +01:00
Max Kellermann
a2b77c8813 decoder/ffmpeg, test/test_protocol: catch exceptions by reference
Work around -Werror=catch-value.
2017-11-12 18:54:29 +01:00
Max Kellermann
18add29472 configure.ac: disable -Wnoexcept-type
Workaround for .
2017-11-12 18:54:29 +01:00
cathugger
b111a8fe8d output/Thread: ensure pending tags are flushed in all cases
Fixes hanging playback with soxr resampler.

Closes , 
2017-11-05 17:42:32 +01:00
Marcin Jurkowski
3b23cf0258 decoder/vorbis: scale and clip tremor-decoded samples to 15 bits
Tremor decoder is unusable since commit 2ee43c4. Sound is distorted to
the point where it's nothing but noise.

The data from vorbis_synthesis_pcmout() needs to be scaled and
clipped for 16 bit sample size. For reference see
http://lists.xiph.org/pipermail/tremor/2010-April/001642.html and
http://lists.xiph.org/pipermail/vorbis/2006-October/026513.html.

Signed-off-by: Marcin Jurkowski <marcin1j@gmail.com>
2017-11-03 19:45:41 +01:00
Max Kellermann
28e864e096 player/Thread: log message when decoder is too slow 2017-10-25 20:26:09 +02:00
Max Kellermann
1de19b921a input/curl: call StartRequest() after setting CURLOPT_RANGE
It's not possible to set CURL options after curl_easy_perform(), and
thus the CURLOPT_RANGE had no effect.
2017-10-24 21:43:39 +02:00
Max Kellermann
ff162b5a03 input/curl: move code to StartRequest() 2017-10-24 21:41:17 +02:00
Max Kellermann
d8e4705dd4 input/curl: move the range buffer to the stack
From the CURLOPT_RANGE documentation: "The application does not have
to keep the string around after setting this option."
2017-10-24 21:38:35 +02:00
Max Kellermann
338e1f5926 increment version number to 0.20.12 2017-10-24 17:31:55 +02:00
Max Kellermann
a7fdfa08e1 release v0.20.11 2017-10-18 10:14:46 +02:00
Max Kellermann
9703a401c5 Playlist{File,Save}: always use UTF-8 in playlists on Windows
Turns out that using CP_ACP is a lousy idea, because only very few
Unicode characters can be represented by it.  Instead, switch to UTF-8
(which every sane person on other operating system already uses).

Closes 
2017-10-18 10:05:26 +02:00
Max Kellermann
753a2aa462 PlaylistSave: move code to playlist_print_path() 2017-10-18 09:51:04 +02:00
Max Kellermann
10990a0684 queue/Playlist: call MoveOrderToCurrent() in SeekSongOrder() on song change
Applies the improvements from the previous commit to the "seek"
commands, which are also capable of switching songs.

Closes 
2017-10-18 09:14:27 +02:00
Max Kellermann
91254e9211 queue/PlaylistControl: keep order list consistency in MoveOrderToCurrent()
Our previous use of Queue::SwapOrders() could cause surprising
results:

- sometimes, the old "current" song would be played again (if the
  newly selected song had not been played already)

- sometimes, the old "current" song would not be played again (if the
  newly selected song had already been played)

This is inconsistent, because it should not depend on whether the
newly selected song had already been played.

So instead of Queue::SwapOrders() we now use Queue::MoveOrderAfter()
and Queue::MoveOrderBefore(), which is more expensive, but also more
consistent.  It attempts to retain as much from the previous order
list as possible, and only moves the newly selected song around.
2017-10-18 09:05:47 +02:00
Max Kellermann
0f79287b04 queue/Playlist: move code to MoveOrderToCurrent() 2017-10-18 09:05:24 +02:00
Max Kellermann
f2fac77d8c queue/Queue: add methods MoveOrderBefore() and MoveOrderAfter() 2017-10-18 08:50:01 +02:00
Max Kellermann
81b7373637 queue/Queue: MoveOrder() returns to_order 2017-10-18 08:46:31 +02:00
Max Kellermann
fa67c2548a decoder/Thread: clear the command after catching an exception
If an early exception gets caught (e.g. from
AllocatedPath::FromUTF8Throw()) before
DecoderControl::CommandFinishedLocked() is called, the decoder thread
would go in an endless loop, because DecoderCommand::START is still
set.

Closes 
2017-09-27 17:08:16 +02:00
John Regan
ea80587ddb GME Plugin: fix track numbering
GME starts all track indexes at zero, but subtune prefixes
start at one. This fixes an off-by-one error during track
enumeration.
2017-09-27 11:18:03 +02:00
Max Kellermann
828f5f8384 lib/icu/CaseFold: disable broken strxfrm() callback 2017-09-20 23:55:14 +02:00
Max Kellermann
1295a1272a lib/icu/Compare: add fallback using strcasecmp() and strcasestr()
Our IcuCaseFold() fallback using strxfrm() is not actually case
insensitive.  This commit fixes the problem by switching to
strcasecmp().  That function is not guaranteed to support UTF-8, but
it's the best we can do in this sparse situation.

Closes 
2017-09-20 23:43:27 +02:00
Max Kellermann
66646d9276 SongFilter: use class IcuCompare 2017-09-20 23:43:26 +02:00
Max Kellermann
d0497dba92 lib/icu/Compare: OO wrapper for IcuCaseFold() 2017-09-20 23:32:55 +02:00
Max Kellermann
42914e8227 lib/icu/CaseFold: add "noexcept" 2017-09-20 23:32:54 +02:00
Max Kellermann
59b49b7881 db/Selection: add missing config.h 2017-09-20 23:32:54 +02:00
Max Kellermann
5620f16330 lib/icu/Collate: move IcuCaseFold() to CaseFold.cxx 2017-09-20 23:11:58 +02:00
Max Kellermann
be024d4ad7 lib/icu/Collate: remove unnecessary assert() 2017-09-20 23:05:31 +02:00
Max Kellermann
75c740fe2b output/sndio: fix indent 2017-09-19 18:50:35 +02:00
Max Kellermann
6c8d86bb90 output/sndio: rename the "sio_hdl" variable to avoid clash with struct name 2017-09-19 18:49:33 +02:00
Charlie Waters
b253a6b71e ffmpeg plugin: when decoded stream duration is unavailable, attempt fallback to container duration (fix ) 2017-09-18 10:39:27 +02:00
Max Kellermann
ca7b4df812 doc/user: document the Opus encoder 2017-09-07 14:21:40 +02:00
Max Kellermann
bc8dd57236 doc/protocol.xml: document status/volume=-1
Closes 
2017-09-04 08:15:41 +02:00
Max Kellermann
f4f461b8bb storage/curl: support Content-Type application/xml 2017-09-01 11:32:40 +02:00
Max Kellermann
cbb9b6957f storage/curl: use StringStartsWith() 2017-09-01 11:31:10 +02:00
Max Kellermann
f6b56c9317 storage/curl: move code to IsXmlContentType() 2017-09-01 11:30:30 +02:00
Max Kellermann
3717fb6c8d win32/build.py: add -march=pentium3 to fix 32 bit LAME build
Workaround for the following LAME build failure:

 error: inlining failed in call to always_inline '_mm_sqrt_ps': target
 specific option mismatch

This is because the LAME build scripts do not check whether SSE is
available; they only check for the presence of the "xmmintrin.h"
header.

Requiring a Pentium 3 CPU is reasonable enough, and it's the first CPU
to feature SSE support.
2017-08-31 19:48:59 +02:00
Max Kellermann
f6abbc01bd increment version number to 0.20.11 2017-08-31 19:48:59 +02:00
Max Kellermann
57a71c157d release v0.20.10 2017-08-24 09:15:43 +02:00
Max Kellermann
cc76aeb7bb python/build/libs: upgrade CURL to 7.55.1 2017-08-24 09:06:15 +02:00
Max Kellermann
811cabf8a9 python/libs: upgrade Opus to 1.2.1 2017-08-24 09:06:15 +02:00
Max Kellermann
bf8d2f93d2 python/build/libs: upgrade FFmpeg to 3.3.3 2017-08-24 09:06:15 +02:00
Max Kellermann
07d8259ad6 python/libs: upgrade Boost to 1.65 2017-08-23 17:46:25 +02:00
Max Kellermann
a00d412008 player/Thread: initialize play_audio_format, fixes assertion
This fixes an assertion failure caused by resuming playback before the
decoder has finished startup.
2017-08-23 17:43:49 +02:00
Matthew Leon
5fb39658f1 OSX mixer 2017-08-21 20:05:50 +01:00
Max Kellermann
b0703b92c3 util/FormatString: pass the allocated buffer to AllocatedString::Donate()
.. and not the stack buffer.  This made the AllocatedString destructor
crash.

Closes 
2017-08-03 00:25:30 +02:00
Max Kellermann
dd9fd3d8a7 tag/Aiff: the FORM chunk size is big-endian
Was broken by commit 8a86460b8f

Closes 
2017-07-31 13:46:09 +02:00
Max Kellermann
cf0c59864f doc/protocol.xml: clarify that idle events do not get lost 2017-07-21 09:51:43 +02:00
Matthew Leon
4c0404c70d Check for MusicBrainz id3v2 tags in ffmpeg.
Addresses .

Previously, the ffmpeg decoder only checked for the "generic"
MusicBrainz metadata keys used in other metadata container formats.
2017-07-20 08:28:14 +02:00
Matthew Leon
573a413ee1 move MusicBrainz id3v2 tags to separate file
We will reuse these tags elsewhere.
2017-07-20 08:26:29 +02:00
Max Kellermann
f633e6ca49 python/build/libs: add LAME
Enable it in the Windows build script, closes .

LAME currently doesn't support Android:

 checking host system type... Invalid configuration `arm-linux-androideabi': system `androideabi' not recognized
2017-07-19 20:53:52 +02:00
Max Kellermann
07b06d76be {android,win32}/build.py: concatenate variables from the command line 2017-07-19 20:53:52 +02:00
Max Kellermann
856fe2da15 python/build/libs: upgrade FFmpeg to 3.3.2, CURL to 7.54.1 2017-06-15 21:53:22 +02:00
Max Kellermann
f82aae65cd doc/user: add more Debian build dependencies 2017-06-15 21:37:07 +02:00
Max Kellermann
3fbd11a104 doc/user: update build dependencies for Debian Jessie 2017-06-15 21:37:05 +02:00
Max Kellermann
58a99f1907 increment version number to 0.20.10 2017-06-15 21:35:23 +02:00
Max Kellermann
cf86dfd317 release v0.20.9 2017-06-04 12:51:36 +02:00
Max Kellermann
a057b4f6d8 *: add lost of "noexcept" specifications 2017-06-04 12:46:48 +02:00
Max Kellermann
62b03cfddf storage, db, mixer, command: remove more bogus "pure" attributes
This commit is similar to 788e3b31e1,
and removes more "pure" attributes which were placed on functions that
could throw exceptions, which is illegal according to clang's
understanding of the attribute (but not according to GCC's).  GitHub
issue  was most likely about StorageDirectoryReader::GetInfo() and
Storage::GetInfo(), which still had "pure" attributes.

Closes 
2017-06-03 21:54:24 +02:00
Jörg Raftopoulos
18b827b979 decoder/ffmpeg: add support for adx
Add ffmpeg decoder support for *.adx files (Sega game console)

Closes 
2017-06-03 20:57:20 +02:00
Max Kellermann
0a379fc514 system/ByteOrder: fix byte order detection on FreeBSD/aarch64
Patch from
 https://svnweb.freebsd.org/ports/head/audio/musicpd/files/patch-src_system_ByteOrder.hxx?revision=441921&view=co
(with a tiny modification)

Closes 
2017-05-29 20:37:14 +02:00
Max Kellermann
445c11b8d9 increment version number to 0.20.9 2017-05-29 20:36:08 +02:00
Max Kellermann
8d290ad509 release v0.20.8 2017-05-19 20:10:22 +02:00
Max Kellermann
b90c48b50f .travis.yml: enable Mac OS X 2017-05-19 19:54:27 +02:00
Max Kellermann
d19e7db09e .travis.yml: add shell variable OPTIONS 2017-05-19 19:54:27 +02:00
Max Kellermann
9939904b02 .travis.yml: configure with --disable-silent-rules --disable-dependency-tracking 2017-05-19 19:54:27 +02:00
Max Kellermann
ca23b15f5c test/test_byte_reverse: move "alignas" attribute to the front
Apparently, this makes old clang versions happy ("'alignas' attribute
cannot be applied to types).
2017-05-19 19:45:42 +02:00
Mario Di Raimondo
ffa676f577 playlist/m3u: support for mime-type audio-mpegurl for M3U playlists 2017-05-19 15:25:58 +02:00
Max Kellermann
6d023c4df3 .travis.yml: remove the unnecessary "compiler" setting 2017-05-17 16:22:19 +02:00
Max Kellermann
b31bd37a30 .travis.yml: check $TRAVIS_OS_NAME
Prepare for Mac OS X support by omitting those Ubuntu-specific
commands.
2017-05-17 15:59:25 +02:00
Max Kellermann
78faee8c7c .travis.yml: choose compiler with environment variables
.. and not update-alternatives, which requires "sudo".
2017-05-17 15:56:19 +02:00
Max Kellermann
40e2a703d0 .travis.yml: parallel build 2017-05-17 15:36:59 +02:00
Max Kellermann
b01edcb9bc .travis.yml: indent 2 2017-05-17 15:27:40 +02:00
André Klitzing
f7fffc9be8 Add initial travis configuration 2017-05-16 07:37:46 +02:00
Max Kellermann
50e8634097 python/build/libs: upgrade FFmpeg to 3.3.1 2017-05-16 07:27:08 +02:00
Max Kellermann
e3994e517e INSTALL: merge into doc/user.xml 2017-05-16 07:24:02 +02:00
Max Kellermann
2bb7785189 doc/user.xml: add sticker documentation 2017-05-16 07:23:57 +02:00
Max Kellermann
90c8408111 doc/user.xml: add Zeroconf documentation 2017-05-16 07:23:52 +02:00
Max Kellermann
64786ec12a Main: omit "constexpr" on MIN_BUFFER_SIZE with GCC 4.x 2017-05-16 07:20:47 +02:00
Max Kellermann
b3c82f8886 output/{osx,haiku,pulse,sles}: add missing "noexcept"
Fixes build failure on OS X, closes .  With the other plugins,
that's not critical, because those use the AudioOutputWrapper, which
hides this problem.
2017-05-16 07:12:30 +02:00
Max Kellermann
063259dc52 increment version number to 0.20.8 2017-05-16 07:06:57 +02:00
Max Kellermann
b4c9d9c2a7 release v0.20.7 2017-05-15 22:51:08 +02:00
Max Kellermann
fa2b59df4b Main: cap buffer_before_play at 80% to prevent deadlock
Closes 
2017-05-15 22:49:31 +02:00
Max Kellermann
f41a169460 Main: enforce a reasonable minimum audio_buffer_size setting 2017-05-15 22:44:18 +02:00
Max Kellermann
f567083006 Main: refactor DEFAULT_BUFFER_SIZE to represent bytes 2017-05-15 22:40:23 +02:00
Max Kellermann
a2a677e539 doc/developer.xml: change git URIs to GitHub 2017-05-15 21:49:18 +02:00
Max Kellermann
9123c0b733 doc, README.md: update bug tracker URL
Closes 
2017-05-15 21:48:03 +02:00
Max Kellermann
788e3b31e1 *: remove "pure" and "const" attributes from throwing functions
The "pure" and "const" attributes are not so well-defined, and a
recent clang version implements an optimization which pushes the
definition's boundary beyond what I believed it was.  clang now
assumes that functions declared "pure" cannot throw exceptions, even
if they lack the "noexcept" specification.

When compiled with this new clang version, MPD will crash randomly if
an exception happens to get thrown by such as "pure" function
(https://github.com/MusicPlayerDaemon/MPD/issues/41).

This commit removes all such misplaced "pure" and "const" attributes,
closing .
2017-05-08 17:25:06 +02:00
Max Kellermann
71f0ed8b74 *: add "noexcept" to many, many function prototypes
This eliminates some overhead, because the compiler doesn't need to
consider these functions throwing.
2017-05-08 14:44:49 +02:00
Max Kellermann
ac2e4e593d python/libs: upgrade Boost to 1.64 2017-04-24 20:43:04 +02:00
Max Kellermann
edaa7d7748 python/build/libs: upgrade CURL to 7.54.0 2017-04-24 20:42:28 +02:00
Max Kellermann
3cdf965fba python/build/libs: upgrade FFmpeg to 3.3 2017-04-24 20:41:08 +02:00
Max Kellermann
6b60d1e71f decoder/pcm: add missing nullptr check
Fixes a potential crash bug which is actually unreachable, because the
"pcm" plugin is never invoked when there is no (matching) MIME type.
2017-04-24 20:36:55 +02:00
Max Kellermann
7b7fb5acd5 decoder/pcm: fix potential assertion failure in FillBuffer()
After a seek failure, the buffer may still be full, and then
FillBuffer() aborts with assertion failure.
2017-04-24 11:20:37 +02:00
Bart Nagel
0a7d612f41 Remove some redundant code 2017-04-18 16:10:38 +02:00
Max Kellermann
38da76bbe0 util/ScopeExit: copy enabled tag in move constructor 2017-04-12 13:11:43 +02:00
martinarielhartmann
a13e045742 Update libs.py
upgrade zlib to 1.2.11
2017-04-11 13:31:34 +02:00
cotko
811620c0a0 Fix typo 2017-04-11 13:31:15 +02:00
Max Kellermann
504f5f7bdd storage/FileInfo, db/simple/Directory: use 64 bit for device/inode
An ino_t is usually a 64 bit integer, and some file systems (such as
Linux's kernel NFS client) really uses the upper 32 bit.  This can
lead to false positives in the directory loop detection in
FindAncestorLoop().  Increasing these two attributes (in
StorageFileInfo and Directory) to 64 bit adds little overhead, but
makes the check a lot safer.
2017-04-06 09:58:25 +02:00
Max Kellermann
32bcad51b8 configure.ac: prepare for 0.20.7 2017-03-16 10:50:12 +01:00
Max Kellermann
a40510c241 release v0.20.6 2017-03-10 16:57:59 +01:00
Max Kellermann
ac8dce6599 lib/curl/Request: "ICY 200 OK" is a response boundary header 2017-03-10 16:28:02 +01:00
Max Kellermann
190d525099 lib/curl/Request: move code to IsResponseBoundaryHeader() 2017-03-10 16:24:30 +01:00
Max Kellermann
1b6666fa39 Partition: handle SYNC_WITH_PLAYER before TAG_MODIFIED
The TAG_MODIFIED handler (i.e. playlist::TagModified()) works only if
the modified song is the current song - something that is not updated
until SYNC_WITH_PLAYER is finished.  This fixes tag updates right
after a new song is started.
2017-03-10 16:11:34 +01:00
Max Kellermann
1dd01c99e8 decoder/sidplay: make compatible with libsidplayfp < 1.8
https://bugs.musicpd.org/view.php?id=4665
2017-03-10 13:48:52 +01:00
Thomas Zander
d50b30a498 Add missing include for cstdlib, otherwise free() is undefined 2017-03-07 20:02:36 +01:00
Max Kellermann
42a3a87f13 util/HugeAllocator: paranoid check for sysconf()<0
Just in case.
2017-03-01 21:50:26 +01:00
Ben Boeckel
9dfedbe619 ReusableArray: fix build error on GCC7
GCC7 outputs the following error without this change:

    src/util/ReusableArray.hxx:61:35: error: no matching function for call to ‘swap(size_t&, const size_t&)’
       std::swap(capacity, src.capacity);

which can be resolved by just using an rvalue-reference rather than a
const rvalue-reference.

Signed-off-by: Ben Boeckel <mathstuf@gmail.com>
2017-03-01 19:38:41 +01:00
Max Kellermann
88957b4c9d android/build.py: build with libc++ instead of GNU libstdc++
Android is migrating away from GCC, and libstdc++ will disappear
eventually.
2017-03-01 17:31:26 +01:00
Max Kellermann
b2f2c9322b db/simple/Mount: workaround for libc++ 2017-03-01 17:31:26 +01:00
Max Kellermann
3be2051808 decoder/Thread: check ENABLE_FFMPEG, not HAVE_FFMPEG
This repairs the damage to commit 74dbaade6f done by commit
b3f5b4932c
2017-03-01 17:06:23 +01:00
Max Kellermann
ff32b0dc9b input/curl: use %lu instead of %llu
Fixes a GCC warning because %llu appears to be unsupported by the
Windows standard library.
2017-03-01 16:44:11 +01:00
Max Kellermann
c1869a11af input/curl: format Range offset as unsigned 2017-03-01 16:44:08 +01:00
Max Kellermann
e22a4fdba4 command/Error: improve libstdc++ 4.9.x detection for std::rethrow_if_nested() workaround 2017-03-01 16:38:22 +01:00
Max Kellermann
29a7b2c5b5 decoder/mpcdec: ignore empty frames
https://bugs.musicpd.org/view.php?id=4656 describes a crash due to
division by zero because frame.samples==0.  This should never happen,
but apparently can happen after seeking.  The best we can do is to
just ignore this frame.
2017-03-01 16:13:21 +01:00
Max Kellermann
3b6c285c2a configure.ac: prepare for 0.20.6 2017-03-01 16:13:21 +01:00
Max Kellermann
575d1786af release v0.20.5 2017-02-20 21:51:31 +01:00
Max Kellermann
bc1c927952 util/TimeFormat: suppress -Wunused on Windows 2017-02-20 21:44:01 +01:00
Max Kellermann
f95bc85f91 python/build/libs: upgrade FFmpeg to 3.2.4 2017-02-20 21:13:43 +01:00
Max Kellermann
4015195314 doc/user: instructions to compile the Windows binary 2017-02-20 21:06:43 +01:00
Max Kellermann
c3d883c6cb win32/build.py: default to x64 build 2017-02-20 21:06:43 +01:00
Max Kellermann
097e30321b win32/build.py: add option --32 2017-02-20 21:06:31 +01:00
Max Kellermann
b6ddeaacf2 win32/build.py: convert argument parser to loop
Allow multiple arguments.
2017-02-20 21:06:21 +01:00
Max Kellermann
b0c60ec124 win32/build.py: add variable "x64", assign host_arch later 2017-02-20 21:04:34 +01:00
Max Kellermann
f3b788703e tag/Handler: improve snprintf() return value check 2017-02-19 19:34:13 +01:00
Max Kellermann
4bb83781e8 output/httpd/IcyMetaDataServer: cast length to unsigned
Fixes another buffer overflow: if the stream has a very long title or
URL, resulting in a metadata string of more than 2 kB, icy_string[0]
is a negative value, which gets casted to size_t - ouch!

 https://bugs.musicpd.org/view.php?id=4652
2017-02-19 19:28:52 +01:00
Max Kellermann
a73195b7cc output/httpd/IcyMetaDataServer: pad the string with 15 spaces
Fixes a buffer overflow due to the bad formula rounding the buffer
size up.  At the same time, remove the "+1" from the meta_length
calculation, which takes the padding into account and at the same time
implements proper rounding.
2017-02-19 19:27:37 +01:00
Max Kellermann
1bd00b8a9a output/httpd/IcyMetaDataServer: remove the int cast
Why did this cast exist??
2017-02-19 19:27:37 +01:00
Max Kellermann
d84eaeafc5 doc/include/tags.xml: clarify that track/disc are decimal 2017-02-18 19:01:04 +01:00
Max Kellermann
20ae84bff9 {input,mixer}/alsa: cancel the DeferredMonitor in the destructor
Yet another potential crash bug fix.
2017-02-10 15:05:49 +01:00
Max Kellermann
7372c931b3 event/Loop: make IsInsideOrNull() available in the NDEBUG build
Fixes build breakage by commit 4e5271fcdf7; and this method does make
sense in non-debug builds.
2017-02-09 21:21:49 +01:00
Max Kellermann
29e1b6e465 mixer/alsa: reset the MultiSocketMonitor in the destructor
Fixes potential crash bug.
2017-02-09 21:13:19 +01:00
Max Kellermann
eda06993f8 event/MultiSocketMonitor: add method Reset() 2017-02-09 21:12:23 +01:00
Max Kellermann
4b30ef1cf2 event/MultiSocketMonitor: use C++11 initializer 2017-02-09 21:12:23 +01:00
Max Kellermann
e92e5e8eb8 event/MultiSocketMonitor: more API documentation
Now ClearSocketList() may only be called from PrepareSockets().
Calling it before destroying the object doesn't work properly, because
it doesn't unregister the TimeoutMonitor and the IdleMonitor.  Some of
its callers need to be fixed.
2017-02-09 21:12:23 +01:00
Max Kellermann
4e5271fcdf event/Call: allow usage during shutdown
Change EventLoop::IsInside() call to EventLoop::IsInsideOrNull().
This means that BlockingCall() may be used during shutdown, after the
main EventLoop::Run() has finished.  This is important because mixers
are currently registered in the main EventLoop.
2017-02-09 21:12:23 +01:00
Max Kellermann
3c55487a16 configure.ac: don't require libsidutils when building with libsidplayfp
The libsidplayfp fork has merged libsidutils into the main library.
The libsidutils we used to link with was part of the original
libsidplay project.
2017-02-09 13:09:03 +01:00
Max Kellermann
76a1cae5d8 {input,mixer}/alsa: fix off-by-one bug in count check
Doesn't make a practical difference - but it's more correct this way.
2017-02-09 12:46:49 +01:00
Max Kellermann
81a97315e3 NEWS: mention ID3 memory leak fix 2017-02-08 08:44:47 +01:00
Max Kellermann
53c14d97a6 lib/nfs/FileReader: remove debug line 2017-02-08 08:43:56 +01:00
Max Kellermann
69a82eec17 tag/TagId3: use AtScopeExit() for exception-safety 2017-02-06 23:32:07 +01:00
Max Kellermann
45cadef22f configure.ac: prepare for 0.20.5 2017-02-06 23:28:36 +01:00
Max Kellermann
0a033fb10a release v0.20.4 2017-02-01 21:59:36 +01:00
Max Kellermann
591afa0647 lib/nfs/Connection: detect socket hangup and unregister from epoll
Fixes race condition when epoll_ctl() gets called after the socket has
been closed, which may affect a different socket created by another
thread meanwhile.
2017-02-01 21:44:20 +01:00
Max Kellermann
05eac20ffe lib/nfs/Connection: detect libnfs reconnect
When rpc_reconnect_requeue() gets called from inside nfs_service(),
the NfsInputStream can stall completely because the old socket has
been unregistered from epoll automatically, but the new one has never
been registered.  Therefore, nfs_service() will never be called again.

This kludge attempts to detect this condition by checking
nfs_which_events()==POLLOUT.

https://bugs.musicpd.org/view.php?id=4081
2017-02-01 21:36:58 +01:00
Max Kellermann
38d263ac19 output/sndio: work around a libroar C++ incompatibility
Same as in commit e02d8ad8d2, but this time for the sndio plugin
which can be emulated by libroar.
2017-02-01 19:53:23 +01:00
Thomas Zander
f71c204eef Correct method types to match Interface.hxx 2017-01-31 21:22:02 +01:00
Thomas Zander
51147203be free() require cstdlib to be included 2017-01-31 21:21:37 +01:00
Max Kellermann
a931686317 pcm/SampleFormat: workaround for GCC 4.9 "constexpr" bug
GCC 4.9 has incomplete C++14 support.  Specifically, it doesn't allow
switch/case in "constexpr" functions.
2017-01-27 11:02:58 +01:00
Max Kellermann
5bd322bdcf python/libs: upgrade Opus to 1.1.4 2017-01-27 08:47:58 +01:00
Max Kellermann
bb097109f0 configure.ac: prepare for 0.20.4 2017-01-27 08:47:36 +01:00
Max Kellermann
2ab6c40ff1 release v0.20.3 2017-01-25 08:53:16 +01:00
Max Kellermann
68bb738af2 input/alsa: use snd_pcm_?w_params_alloca() 2017-01-25 08:47:20 +01:00
Max Kellermann
6b968beede output/alsa: convert to class, make attributes private 2017-01-24 23:08:16 +01:00
Max Kellermann
f68dd1bffb output/alsa: make AlsaSetup() an AlsaOutput method 2017-01-24 23:06:33 +01:00
Max Kellermann
f92b71ca99 output/alsa: move code from AlsaSetup() to AlsaSetupSw() 2017-01-24 23:05:29 +01:00
Max Kellermann
2b79fe2d6a output/alsa: move code from AlsaSetup() to AlsaSetupHw() 2017-01-24 22:48:48 +01:00
Max Kellermann
44dd9af276 lib/upnp/Util: pass single delimiter character to stringToTokens() 2017-01-23 19:34:55 +01:00
Max Kellermann
d3013d4f8c lib/upnp/Util: remove parameter "skipinit", always true 2017-01-23 19:28:07 +01:00
Max Kellermann
678524ad21 lib/upnp/WorkQueue: fix race condition
With "ok==false", newly created threads may quit instantly.
2017-01-23 19:25:30 +01:00
Max Kellermann
32a64481f2 lib/upnp: fix bad std::chrono cast
libupnp provides seconds, not whatever time unit is used by
std::chrono::steady_clock.
2017-01-23 19:16:14 +01:00
Max Kellermann
1776015c6c db/simple: drop redundant "virtual" 2017-01-23 18:57:23 +01:00
Max Kellermann
f1c71a26e3 db/proxy: drop redundant "virtual" 2017-01-23 18:56:45 +01:00
Max Kellermann
e78ab767d3 db/proxy: make connect errors during startup non-fatal 2017-01-23 18:55:40 +01:00
Max Kellermann
f01eb2f95d db/proxy: improve Connect() error message 2017-01-23 18:55:18 +01:00
Max Kellermann
1450e45d97 Main, db/Glue: improve error messages 2017-01-23 18:52:16 +01:00
Max Kellermann
ec8cba369c lib/upnp/WorkQueue: disallow copying 2017-01-23 18:35:58 +01:00
Max Kellermann
f4c248f406 lib/upnp/WorkQueue: make constructor explicit 2017-01-23 18:35:47 +01:00
Max Kellermann
f3b2a58646 lib/upnp/WorkQueue: use C++11 initializers 2017-01-23 18:35:22 +01:00
Max Kellermann
c6f89c42b2 db/proxy: make the base class of LibmpdclientError public
If the base class is not accessible, the "catching" the base class
won't work.  This caused the fatal error:

 terminate called after throwing an instance of 'LibmpdclientError'
2017-01-23 18:28:40 +01:00
Max Kellermann
5e93cfdd9e output/Source: reset the ReplayGain serials ion OpenFilter()
Each close/open cycle resets the Filter's state, because a new Filter
instance is being created.  That results in the serials
(replay_gain_serial and other_replay_gain_serial) being out of sync
with the internal ReplayGainFilter state.

So instead of initializing those serials once, we need to initialize
them each time we create new ReplayGainFilter instances, i.e. in
OpenFilter().

 https://bugs.musicpd.org/view.php?id=4632
2017-01-23 17:55:04 +01:00
Max Kellermann
d91d5a3ab5 playlist/SoundCloud: eliminate unnecessary casted variable 2017-01-20 17:16:11 +01:00
Max Kellermann
907c045f33 doc/user: add missing playlist plugins 2017-01-20 17:09:19 +01:00
Max Kellermann
90f189eb54 doc/user: mention which commands are available with playlist plugins 2017-01-20 16:59:07 +01:00
Florian Schlichting
4abd5b2112 doc/user: document effect of http_proxy envvar on curl plugin 2017-01-20 16:52:02 +01:00
Max Kellermann
df9a665994 pcm/Traits: add "SILENCE" attribute 2017-01-20 15:57:09 +01:00
Max Kellermann
7a098ca0ed pcm/Traits: add specialization for SampleFormat::DSD 2017-01-20 15:48:30 +01:00
Max Kellermann
33716732a1 pcm/PcmChannels: silence surround channels when converting from stereo
Previously, there was no special code to convert stereo to
multi-channel.  The generic solution for this was to convert to mono,
and then copy the result to all channels.  That's a pretty bad
solution, but at least something which always renders audio.  MPD does
something, instead of failing.

Now that MPD has proper support for multi-channel (by defining the
channel order), we can do better than that.  It is a (somewhat) common
case to play back stereo music on a DAC which can only do
multi-channel.  The best approach here is to copy the stereo channels
to front-left and front-right, and apply the "silence" pattern to all
other channels.
2017-01-19 10:53:41 +01:00
Max Kellermann
97ae594375 DetachedSong: use C++11 initializers 2017-01-18 13:13:36 +01:00
Max Kellermann
3f321ae9a0 pcm/SampleFormat: make the two inline functions "constexpr" 2017-01-17 22:52:09 +01:00
Max Kellermann
161d32a7e7 AudioFormat: update ToString() API documentatio 2017-01-17 22:48:34 +01:00
Max Kellermann
d7137586a9 Audio{Format,Parser}: use shortcuts such as "dsd64" in log messages 2017-01-17 22:42:23 +01:00
Max Kellermann
cd0c06ba6e doc/protocol: refer to user manual for status/audio 2017-01-17 22:42:23 +01:00
Max Kellermann
899ab63d91 doc/user: document the "dsd" sample format 2017-01-17 22:36:44 +01:00
Max Kellermann
1097820a5a doc/user: add <replaceable> element 2017-01-17 22:36:44 +01:00
Max Kellermann
39114f91a7 AudioFormat: replace struct audio_format_string with class StringBuffer, return it 2017-01-17 22:18:21 +01:00
Max Kellermann
4f01387edf util/StringBuffer: new utility class 2017-01-17 22:03:42 +01:00
Max Kellermann
de3e0585f1 AudioFormat: move enum SampleFormat to pcm/SampleFormat.hxx 2017-01-17 22:01:01 +01:00
Max Kellermann
f85f25ba82 test: add AudioFormat unit test 2017-01-17 12:02:41 +01:00
Max Kellermann
10a2c179f9 Makefile.am: move AudioFormat.cxx to libpcm.a 2017-01-17 12:01:49 +01:00
Max Kellermann
6eea56861b AUTHORS, ...: update my email address 2017-01-17 11:54:55 +01:00
Jörg Krause
21fd2064ae Makefile.am: fix linking xiph with ogg
The internal static xiph library needs to link with libogg. Otherwise
building mpd will fail:

```
/mips-linux-gnu/bin/ld: libxiph.a(libxiph_a-OggVisitor.o): undefined
reference to symbol 'ogg_stream_packetout'
```

Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
2017-01-17 11:24:20 +01:00
Max Kellermann
dcbab8e37a PlaylistFile: "playlistadd" creates new playlist if it does not exist, as documented 2017-01-16 20:55:19 +01:00
Max Kellermann
5677278251 CommandLine: update copyright year 2017-01-16 12:04:04 +01:00
Max Kellermann
a83bee993d configure.ac: prepare for 0.20.3 2017-01-16 12:03:22 +01:00
Max Kellermann
96a31f554a release v0.20.2 2017-01-15 01:28:00 +01:00
Max Kellermann
d14ec6aea5 output/Thread: reconfigure ConvertFilter for its new input AudioFormat
If the input AudioFormat changes but the out_audio_format doesn't
change (e.g. because there is a fixed "format" setting in this
"audio_output" section), the ConvertFilter needs to be reconfigured.
This didn't happen, resulting in awful static noise after changing
songs.
2017-01-15 01:24:17 +01:00
Max Kellermann
917cedf893 output/Thread: move AudioFormat logging code around 2017-01-15 01:23:49 +01:00
Max Kellermann
193dd71600 output/Thread: remember the original filter audio format in local variable 2017-01-15 01:21:14 +01:00
Max Kellermann
6c293a3d7f lib/nfs: add more API documentation 2017-01-15 00:58:49 +01:00
Max Kellermann
e847ddf011 DetachedSong: compare start_time and end_time in IsSame()
This method is used by DecoderControl::IsCurrentSong(), which is used
by the player thread to check whether the current decoder instance can
be reused to seek.  When switching to another song in the same CUE
sheet, previously DetachedSong::IsSame() returned true, and thus the
old decoder instance was used for the new song, not considering the
new end_time.  This led to the old decoder quickly quitting.
2017-01-15 00:54:25 +01:00
Max Kellermann
7e8b448985 input/alsa: set period_size=buffer_size/4
This way, we have four periods instead of the default of two.  With
only two periods, we don't get woken up often enough, and we
frequently encounter buffer overruns.  With four periods, we have more
time to breathe, and the buffer overruns magically disappear.
2017-01-14 21:50:28 +01:00
Max Kellermann
d1f3a87c08 input/alsa: remove the start_threshold setting
This setting is mostly useless for capture devices.  There's no point
in configuring it.
2017-01-14 21:47:37 +01:00
Max Kellermann
9f8145e590 input/alsa: dump buffer/period sizes 2017-01-14 21:09:57 +01:00
Steven O'Brien
791efc171a input/alsa: enable non-blocking mode 2017-01-14 20:59:57 +01:00
Steven O'Brien
144312a525 input/alsa: handle EAGAIN 2017-01-14 20:59:23 +01:00
Max Kellermann
92684112ed input/alsa: call snd_pcm_start() after snd_pcm_prepare()
This is necessary because we'll never get woken up again by
epoll_wait() after a buffer overrun recovery, unless we start the PCM
explicitly before returning to the I/O loop.
2017-01-14 20:58:30 +01:00
Max Kellermann
ef114ee6cb input/alsa: improve logging in Recover()
Copy yet more code from the ALSA output plugin.
2017-01-14 20:52:41 +01:00
Max Kellermann
667f209742 input/alsa: check snd_pcm_state() in Recover()
Copy some good code from the ALSA output plugin.
2017-01-14 20:51:51 +01:00
Max Kellermann
4ad0747c78 output/alsa: explicitly mention all snd_pcm_state() enums
I want a compiler warning when a new state needs to be considered
here.
2017-01-14 20:49:15 +01:00
Max Kellermann
c5cf66402c input/alsa: make two attributes "const" 2017-01-13 20:26:36 +01:00
Max Kellermann
05417049eb input/alsa: clear sockets from within IOThread
Fixes assertion failure in implicit destructor.
2017-01-13 20:17:16 +01:00
Max Kellermann
c7b0c46d9f output/recorder: fix typo in variable name
Fixes the dreaded error "Failed to create : No such file or
directory".

 https://bugs.musicpd.org/view.php?id=4625
2017-01-12 21:36:32 +01:00
Max Kellermann
df578c91ad output/alsa: log DoP mode 2017-01-11 22:50:40 +01:00
Max Kellermann
70008c47c9 output/alsa: support DSD_U16 2017-01-11 22:47:21 +01:00
Max Kellermann
938affef32 pcm/export: support DSD_U16 2017-01-11 22:47:12 +01:00
Max Kellermann
a3c33000ee pcm/Dsd32: include cleanup 2017-01-11 22:47:12 +01:00
Max Kellermann
1e54b7b294 test/test_pcm: fix the DSD_U32 byte order
The unit test was wrong as well.  D'oh!
2017-01-11 22:39:23 +01:00
Max Kellermann
cc0dbcf3f4 pcm/Dsd32: fix the byte order
The byte order of DSD_U32 was wrong from the start.  The oldest bits
must be in the MSB, not in the LSB, according to
snd_pcm_format_descriptions in alsa-lib.
2017-01-11 22:25:54 +01:00
Max Kellermann
c5a2cadccc pcm/Export: convert to class, make members private 2017-01-11 21:48:43 +01:00
Max Kellermann
9aa43416b6 pcm/dop: remove unnecessary assertions 2017-01-11 21:48:43 +01:00
Max Kellermann
8364029db8 output/alsa: move code to PlayRaw() 2017-01-11 21:38:05 +01:00
Max Kellermann
d842d21be0 util/ReusableArray: add method GetCapacity() 2017-01-11 20:37:12 +01:00
Max Kellermann
3514fd2433 util/ReusableArray: add move constructor/operator 2017-01-11 20:37:12 +01:00
Max Kellermann
6778ff27ea util/ReusableArray: use C++11 initializers 2017-01-11 20:33:01 +01:00
Max Kellermann
f32315d699 pcm/Export: remove obsolete gcc warning suppression 2017-01-11 20:31:48 +01:00
Max Kellermann
8b754b24b6 pcm/Buffer: update API documentation 2017-01-11 20:24:32 +01:00
Max Kellermann
b1bee9ff38 test/test_pcm: enable the DSD unit tests
These were disabled by accident.
2017-01-11 20:06:10 +01:00
Max Kellermann
569be2d402 test/test_pcm_export: fix TestDop() sample rate results 2017-01-11 20:06:10 +01:00
Max Kellermann
78a73eac53 pcm/Export: add (dummy) method Cancel()
We'll have some code for it soon.
2017-01-11 15:41:28 +01:00
Max Kellermann
533cb99c33 output/Source: reset all filters in Cancel() 2017-01-11 15:39:18 +01:00
Max Kellermann
79726940dc output/Source: un-inline Cancel() 2017-01-11 15:39:00 +01:00
Max Kellermann
27c7891169 filter/Internal: add method Reset() 2017-01-11 15:34:25 +01:00
Max Kellermann
7a3a793a12 decoder/Bridge: call PcmConvert::Reset() after seeking 2017-01-11 15:32:57 +01:00
Max Kellermann
8088469eca pcm/Convert: add method Reset() 2017-01-11 15:30:30 +01:00
Max Kellermann
3dcb082015 pcm/Resampler: add method Reset()
Hook for src_reset(), not yet used.
2017-01-11 15:26:48 +01:00
Max Kellermann
bece023028 pcm/PcmDsd: move Dsd8To32() to Dsd32.cxx 2017-01-11 15:22:43 +01:00
Max Kellermann
9c4df66925 pcm/Export: halve the sample rate for DoP
Move this sample rate fixup from the ALSA output plugin to PcmExport,
where it belongs.
2017-01-11 10:33:23 +01:00
Max Kellermann
2b43ceb6c6 pcm/Export: DSD_U32 quarters the sample rate
DSD_U32 packs four bytes instead of one large "sample", thus the
sample rate is one quarter of the input sample rate.  This fixes a
rather critical DSD_U32 playback problem.
2017-01-11 10:14:41 +01:00
Max Kellermann
c143adba91 pcm/Export: add CalcOutputSampleRate(), CalcInputSampleRate()
Prepare for DSD sample rate fixups.
2017-01-10 23:48:26 +01:00
Max Kellermann
142fdc8d86 decoder/flac: add options "probesize" and "analyzeduration"
https://bugs.musicpd.org/view.php?id=3876
2017-01-10 23:05:04 +01:00
Max Kellermann
67778dcd3d configure.ac: prepare for 0.20.2 2017-01-10 23:01:42 +01:00
Max Kellermann
ed80863eac release v0.20.1 2017-01-09 18:10:18 +01:00
Max Kellermann
c3fc84de12 input/curl: wake up client thread after seek to end of file
Call SeekDone() to avoid the freeze bug.
2017-01-09 18:08:33 +01:00
Max Kellermann
904f83cd85 doc/developer: add GitHub reference 2017-01-09 17:19:15 +01:00
Max Kellermann
28bf100a50 doc/developer: more code style 2017-01-09 17:13:28 +01:00
Max Kellermann
accbd4e82a doc/developer: change C++11 to C++14 2017-01-09 17:13:28 +01:00
Max Kellermann
d7f478c154 doc/developer: add XML ids 2017-01-09 17:13:28 +01:00
Wieland Hoffmann
8f7f13fea4 doc/user: Replace "It used used" with "It is used" 2017-01-08 18:23:13 +01:00
Max Kellermann
c82b03a74c decoder/wavpack: fix crash bug 2017-01-08 14:54:12 +01:00
Max Kellermann
58fb36bdb9 storage/http: new storage plugin 2017-01-08 14:40:20 +01:00
Max Kellermann
4297a7b0a4 lib/curl/Request: move exception handling out of the WRITEFUNCTION
libcurl's WRITEFUNCTION is pretty fragile; if we destroy the CURL*
instance or even unregister it using curl_multi_remove_handle(),
libcurl will crash instantly.  But still we need to be able to handle
exceptions from inside the WRITEFUNCTION, and call
CurlResponseHandler::OnError(), which may destroy the whole thing.  As
a workaround, I use DeferredMonitor to postpone the OnError() call
into a stack frame which is allowed to destroy the request.
2017-01-08 14:36:27 +01:00
Max Kellermann
1bab6d0dd7 lib/curl/Request: move catch clause out of FinishHeaders
Let the caller decide what to do with the exception.
2017-01-08 14:36:27 +01:00
Max Kellermann
13b85edbe2 lib/curl/Request: postpone the curl_easy_cleanup() call
When the request is done, only unregister the CURL* handle, but do not
delete it yet - it may still be needed for CURLINFO_RESPONSE_CODE.
2017-01-08 13:51:53 +01:00
Max Kellermann
dc53098e43 lib/curl/Request: allow Stop() to be called twice
Convert assertion to runtime check.  This is useful because this is a
public method, and the caller has no chance to check if the object is
still registered.
2017-01-08 13:51:53 +01:00
Max Kellermann
3c66feff5a lib/curl/Global: defer the ReadInfo() call
Fixes a crash that can occur due to recursion from InvalidateSockets()
to ReadInfo() to CurlRequest callbacks.
2017-01-08 12:46:35 +01:00
Max Kellermann
218c3bc0d5 lib/curl/Multi: fix typo 2017-01-08 12:46:35 +01:00
Max Kellermann
9f5eddcd13 lib/curl/Global: move code to UpdateTimeout() 2017-01-08 12:44:07 +01:00
Max Kellermann
3cba76552b lib/curl/Global: drop redundant ">=0" check 2017-01-08 12:44:04 +01:00
Max Kellermann
e98a8b624b lib/curl/Global: drop redundant "virtual" 2017-01-08 12:41:26 +01:00
Max Kellermann
6c6947b01f util/UriUtil: add uri_get_path() 2017-01-08 11:05:58 +01:00
Max Kellermann
78c91e9e5b test/run_storage: don't print unknown time stamps 2017-01-08 10:41:08 +01:00
Max Kellermann
44493ca0c4 util/TimeParser: add "pure" attribute 2017-01-08 10:41:08 +01:00
Max Kellermann
42acf78b09 util/TimeParser: wrapper for strptime()
Move code from SongFilter.cxx.
2017-01-07 22:11:45 +01:00
TermeHansen
3aa9f8af18 Rewrite of AlsaMixerPlugin to use volume_mapping
Changed AlsaMixerPlugin to use the get and set normalized functions from volume_mapping of alsa-utils/alsamixer
Changed volume_mapping set volume to be for all channels and not per channel
added volume_mapping files to Makefile.am
2017-01-07 16:30:19 +01:00
TermeHansen
8a32ee30a5 Adding volume_mapping from alsa-utils/alsamixer
source:
http://git.alsa-project.org/?p=alsa-utils.git;a=blob_plain;f=alsamixer/volume_mapping.c;hb=HEAD
http://git.alsa-project.org/?p=alsa-utils.git;a=blob_plain;f=alsamixer/volume_mapping.h;hb=HEAD
2017-01-07 16:26:36 +01:00
Max Kellermann
981dc0626b lib/expat/ExpatParser: add constructor overload for XML_ParserCreateNS() 2017-01-07 16:17:53 +01:00
Max Kellermann
8986d14e98 lib/expat/ExpatParser: make constructors "explicit" 2017-01-07 16:15:11 +01:00
Max Kellermann
5163b1a624 lib/curl/Request: require the caller to explicitly register the request
This allows constructing an instance in any thread, and register it
inside the IOThread later.
2017-01-07 16:01:58 +01:00
Max Kellermann
860aa9d6d0 lib/expat/ExpatParser: move InputStream overload to separate source file
Eliminate one unnecessary dependency for debug programs which don't
need the InputStream API.
2017-01-07 15:46:36 +01:00
Max Kellermann
64dc5212f9 Makefile.am: add variable CURL_SOURCES 2017-01-07 14:19:24 +01:00
Max Kellermann
6cff3214f3 lib/curl/Slist: new wrapper for curl_slist 2017-01-06 19:37:31 +01:00
Max Kellermann
fd910bd5e9 db/upnp: use "override" instead of "virtual" 2017-01-06 19:35:58 +01:00
Max Kellermann
c6086bed41 filter/Internal: remove the default constructor
Not used.  Force implementations to initialize out_audio_format.
2017-01-06 12:45:52 +01:00
Max Kellermann
1a9dfdfab8 filter/AutoConvert: initialize Filter::out_audio_format 2017-01-06 12:44:55 +01:00
Max Kellermann
5284cd11a9 filter/AutoConvert: remove obsolete NULL check 2017-01-06 12:35:06 +01:00
Max Kellermann
d1a47cffad filter/convert: remove obsolete method prototype 2017-01-06 12:34:39 +01:00
Max Kellermann
f469595eee filter/Internal: remove obsolete doxygen line 2017-01-06 12:34:39 +01:00
Max Kellermann
9cfc52f114 filter/Internal: add assertion to constructor 2017-01-06 11:17:55 +01:00
Max Kellermann
30bfb756c2 configure.ac: prepare for 0.20.1 2017-01-05 19:36:32 +01:00
557 changed files with 7252 additions and 2980 deletions
.travis.ymlAUTHORSINSTALLMakefile.amNEWSREADME.md
android
configure.ac
doc
m4
python/build
src
AudioFormat.cxxAudioFormat.hxxAudioParser.cxxAudioParser.hxxCommandLine.cxxDetachedSong.cxxDetachedSong.hxxIOThread.cxxIOThread.hxxIdleFlags.cxxIdleFlags.hxxInstance.hxxLocateUri.hxxLogBackend.cxxLogInit.cxxLogLevel.hxxMain.cxxMain.hxxMapper.cxxMapper.hxxMixRampInfo.hxxMusicBuffer.cxxMusicBuffer.hxxMusicChunk.cxxMusicChunk.hxxMusicPipe.cxxMusicPipe.hxxPartition.cxxPartition.hxxPermission.cxxPlaylistFile.cxxPlaylistSave.cxxReplayGainInfo.cxxReplayGainInfo.hxxReplayGainMode.cxxReplayGainMode.hxxSongFilter.cxxSongFilter.hxxStateFile.cxxStateFile.hxxStats.cxxTagStream.cxxTimePrint.cxx
archive
client
command
config
db
decoder
encoder
event
filter
fs
input
java
lib
ls.cxxls.hxx
mixer
neighbor
net
output
pcm
player
playlist
protocol
queue
sticker
storage
system
tag
thread
unix
util
win32
test
win32

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

@@ -5,7 +5,7 @@ The following people have contributed code to MPD:
Warren Dukes <warren.dukes@gmail.com>
Avuton Olrich <avuton@gmail.com>
Max Kellermann <max@duempel.org>
Max Kellermann <max.kellermann@gmail.com>
Laszlo Ashin <kodest@gmail.com>
Viliam Mateicka <viliam.mateicka@gmail.com>
Eric Wollesen <encoded@xmtp.net>
@@ -30,3 +30,4 @@ The following people have contributed code to MPD:
Jurgen Kramer <gtmkramer@xs4all.nl>
Jean-Francois Dockes <jf@dockes.org>
Yue Wang <yuleopen@gmail.com>
Matthew Leon Grinshpun <ml@matthewleon.com>

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/

@@ -61,8 +61,8 @@ src_mpd_LDADD = \
libnet.a \
$(FS_LIBS) \
libsystem.a \
libutil.a \
$(ICU_LDADD) \
libutil.a \
$(SYSTEMD_DAEMON_LIBS)
src_mpd_SOURCES = \
@@ -233,7 +233,17 @@ libmpd_a_SOURCES += \
src/db/Selection.cxx src/db/Selection.hxx
endif
CURL_SOURCES = \
src/lib/curl/Version.cxx src/lib/curl/Version.hxx \
src/lib/curl/Global.cxx src/lib/curl/Global.hxx \
src/lib/curl/Request.cxx src/lib/curl/Request.hxx \
src/lib/curl/Handler.hxx \
src/lib/curl/Easy.hxx \
src/lib/curl/Multi.hxx \
src/lib/curl/Slist.hxx
UPNP_SOURCES = \
src/lib/upnp/Compat.hxx \
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
src/lib/upnp/ClientInit.cxx src/lib/upnp/ClientInit.hxx \
src/lib/upnp/Device.cxx src/lib/upnp/Device.hxx \
@@ -275,30 +285,62 @@ libmain_a_CPPFLAGS = $(AM_CPPFLAGS) -Iandroid/build/include
src_mpd_LDADD += libandroid.a libjava.a
all-local: android/build/bin/$(APK_NAME)-debug.apk
all-local: android/build/$(APK_NAME)-debug.apk
clean-local:
rm -rf android/build
libmpd.so: $(filter %.a,$(src_mpd_LDADD)) libmain.a
$(AM_V_CXXLD)$(CXXLD) -shared -Wl,--no-undefined,-shared,-Bsymbolic -llog -lz -o $@ $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) src/libmain_a-Main.o $(src_mpd_LDADD) $(LIBS)
android/build/build.xml: android/AndroidManifest.xml
rm -rf android/build
mkdir -p android/build/include android/build/res android/build/src/org
ln -s $(abs_srcdir)/android/AndroidManifest.xml $(abs_srcdir)/android/custom_rules.xml android/build
ln -s $(abs_srcdir)/android/src android/build/src/org/musicpd
ln -s $(abs_srcdir)/android/res/values $(abs_srcdir)/android/res/layout android/build/res
$(ANDROID_SDK)/tools/android update project --path android/build --target android-17 --name $(APK_NAME)
ANDROID_SDK_BUILD_TOOLS_VERSION = 27.0.0
ANDROID_SDK_PLATFORM = android-17
android/build/bin/classes/org/musicpd/Bridge.class: android/src/Bridge.java android/build/build.xml android/build/res/drawable/icon.png
cd android/build && ant compile-jni-classes
ANDROID_BUILD_TOOLS_DIR = $(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)
ANDROID_SDK_PLATFORM_DIR = $(ANDROID_SDK)/platforms/$(ANDROID_SDK_PLATFORM)
android/build/include/org_musicpd_Bridge.h: android/build/bin/classes/org/musicpd/Bridge.class
javah -classpath $(ANDROID_SDK)/platforms/android-17/android.jar:android/build/bin/classes -d $(@D) org.musicpd.Bridge
JAVAC = javac
AAPT = $(ANDROID_BUILD_TOOLS_DIR)/aapt
DX = $(ANDROID_BUILD_TOOLS_DIR)/dx
ZIPALIGN = $(ANDROID_BUILD_TOOLS_DIR)/zipalign
ANDROID_XML_RES := $(wildcard $(srcdir)/android/res/*/*.xml)
ANDROID_XML_RES_COPIES := $(patsubst $(srcdir)/android/%,android/build/%,$(ANDROID_XML_RES))
JAVA_SOURCE_NAMES = Bridge.java Loader.java Main.java
JAVA_SOURCE_PATHS = $(addprefix $(srcdir)/android/src/,$(JAVA_SOURCE_NAMES))
JAVA_CLASSFILES_DIR = android/build/classes
$(ANDROID_XML_RES_COPIES): $(ANDROID_XML_RES)
@$(MKDIR_P) $(dir $@)
cp $(patsubst android/build/%,$(srcdir)/android/%,$@) $@
android/build/resources.apk: $(ANDROID_XML_RES_COPIES) android/build/res/drawable/icon.png
@$(MKDIR_P) android/build/gen
$(AAPT) package -f -m --auto-add-overlay \
--custom-package org.musicpd \
-M $(srcdir)/android/AndroidManifest.xml \
-S android/build/res \
-J android/build/gen \
-I $(ANDROID_SDK_PLATFORM_DIR)/android.jar \
-F android/build/resources.apk
# R.java is generated by aapt, when resources.apk is generated
android/build/gen/org/musicpd/R.java: android/build/resources.apk
android/build/classes.dex: $(JAVA_SOURCE_PATHS) android/build/gen/org/musicpd/R.java
@$(MKDIR_P) $(JAVA_CLASSFILES_DIR)
$(JAVAC) -source 1.5 -target 1.5 -Xlint:-options \
-cp $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) \
-d $(JAVA_CLASSFILES_DIR) $^
$(DX) --dex --output $@ $(JAVA_CLASSFILES_DIR)
android/build/include/org_musicpd_Bridge.h: android/build/classes.dex
javah -classpath $(ANDROID_SDK_PLATFORM_DIR)/android.jar:$(JAVA_CLASSFILES_DIR) -d $(@D) org.musicpd.Bridge
BUILT_SOURCES = android/build/include/org_musicpd_Bridge.h
android/build/libs/armeabi-v7a/libmpd.so: libmpd.so android/build/build.xml
android/build/lib/armeabi-v7a/libmpd.so: libmpd.so
mkdir -p $(@D)
rm -f $@
$(STRIP) -o $@ $<
@@ -307,24 +349,19 @@ android/build/res/drawable/icon.png: mpd.svg
mkdir -p $(@D)
rsvg-convert --width=48 --height=48 $< -o $@
APK_DEPS = android/build/res/drawable/icon.png \
android/build/libs/armeabi-v7a/libmpd.so \
$(wildcard $(srcdir)/android/src/*.java) \
android/build/build.xml
.DELETE_ON_ERROR: android/build/unsigned.apk
android/build/unsigned.apk: android/build/classes.dex android/build/resources.apk android/build/lib/armeabi-v7a/libmpd.so
cp android/build/resources.apk $@
cd $(dir $@) && zip -q -r $(notdir $@) classes.dex lib
android/build/bin/$(APK_NAME)-debug.apk: $(APK_DEPS)
cd android/build && ant nodeps debug
android/build/$(APK_NAME)-debug.apk: android/build/unsigned.apk
jarsigner -keystore $(HOME)/.android/debug.keystore -storepass android -signedjar $@ $< androiddebugkey
android/build/bin/$(APK_NAME)-release-unsigned.apk: $(APK_DEPS)
cd android/build && ant nodeps release
android/build/bin/$(APK_NAME)-release-unaligned.apk: android/build/bin/$(APK_NAME)-release-unsigned.apk
android/build/$(APK_NAME)-release-unaligned.apk: android/build/unsigned.apk
jarsigner -digestalg SHA1 -sigalg MD5withRSA -storepass:env ANDROID_KEYSTORE_PASS -keystore $(ANDROID_KEYSTORE) -signedjar $@ $< $(ANDROID_KEY_ALIAS)
ANDROID_SDK_BUILD_TOOLS_VERSION = 20.0.0
android/build/bin/$(APK_NAME).apk: android/build/bin/$(APK_NAME)-release-unaligned.apk
$(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)/zipalign -f 4 $< $@
android/build/$(APK_NAME).apk: android/build/$(APK_NAME)-release-unaligned.apk
$(ZIPALIGN) -f 4 $< $@
endif
@@ -406,6 +443,7 @@ libutil_a_SOURCES = \
src/util/CharUtil.hxx \
src/util/NumberParser.hxx \
src/util/MimeType.cxx src/util/MimeType.hxx \
src/util/StringBuffer.hxx \
src/util/StringPointer.hxx \
src/util/StringView.cxx src/util/StringView.hxx \
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
@@ -420,6 +458,7 @@ libutil_a_SOURCES = \
src/util/FormatString.cxx src/util/FormatString.hxx \
src/util/Tokenizer.cxx src/util/Tokenizer.hxx \
src/util/TextFile.hxx \
src/util/TimeParser.cxx src/util/TimeParser.hxx \
src/util/UriUtil.cxx src/util/UriUtil.hxx \
src/util/Manual.hxx \
src/util/RefCount.hxx \
@@ -507,6 +546,8 @@ libevent_a_SOURCES = \
# UTF-8 library
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/Converter.cxx src/lib/icu/Converter.hxx
@@ -529,6 +570,10 @@ ICU_LDADD = libicu.a $(ICU_LIBS)
# PCM library
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/Interleave.cxx src/pcm/Interleave.hxx \
src/pcm/PcmBuffer.cxx src/pcm/PcmBuffer.hxx \
@@ -565,6 +610,8 @@ PCM_LIBS = \
if ENABLE_DSD
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/dsd2pcm/dsd2pcm.c src/pcm/dsd2pcm/dsd2pcm.h
endif
@@ -603,7 +650,8 @@ libxiph_a_SOURCES += \
src/lib/xiph/OggStreamState.hxx
endif
XIPH_LIBS = libxiph.a
XIPH_LIBS = libxiph.a \
$(OGG_LIBS)
endif
@@ -681,6 +729,7 @@ libstorage_a_SOURCES = \
src/storage/MemoryDirectoryReader.cxx src/storage/MemoryDirectoryReader.hxx \
src/storage/Configured.cxx src/storage/Configured.hxx \
src/storage/plugins/LocalStorage.cxx src/storage/plugins/LocalStorage.hxx \
src/storage/StorageState.cxx src/storage/StorageState.hxx \
src/storage/FileInfo.hxx
libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
@@ -689,6 +738,8 @@ libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
STORAGE_LIBS = \
libstorage.a \
$(CURL_LIBS) \
$(EXPAT_LIBS) \
$(NFS_LIBS) \
$(SMBCLIENT_LIBS)
@@ -704,6 +755,12 @@ libstorage_a_SOURCES += \
src/storage/plugins/NfsStorage.cxx src/storage/plugins/NfsStorage.hxx
endif
if ENABLE_WEBDAV
libstorage_a_SOURCES += \
src/lib/expat/ExpatParser.cxx \
src/storage/plugins/CurlStorage.cxx src/storage/plugins/CurlStorage.hxx
endif
endif
# neighbor plugins
@@ -725,6 +782,7 @@ libneighbor_a_SOURCES = \
src/neighbor/NeighborPlugin.hxx
libneighbor_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(UPNP_CFLAGS) \
$(SMBCLIENT_CFLAGS)
if ENABLE_SMBCLIENT
@@ -774,6 +832,8 @@ libdb_plugins_a_SOURCES = \
src/db/plugins/simple/PrefixedLightSong.hxx \
src/db/plugins/simple/SimpleDatabasePlugin.cxx \
src/db/plugins/simple/SimpleDatabasePlugin.hxx
libdb_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(UPNP_CFLAGS)
if ENABLE_LIBMPDCLIENT
libdb_plugins_a_SOURCES += \
@@ -851,9 +911,6 @@ ARCHIVE_LIBS =
endif
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/ReplayGainMode.cxx src/ReplayGainMode.hxx \
src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx
@@ -900,6 +957,7 @@ libtag_a_SOURCES =\
src/tag/ReplayGain.cxx src/tag/ReplayGain.hxx \
src/tag/MixRamp.cxx src/tag/MixRamp.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/ApeReplayGain.cxx src/tag/ApeReplayGain.hxx \
src/tag/ApeTag.cxx src/tag/ApeTag.hxx
@@ -1279,12 +1337,7 @@ if ENABLE_CURL
libinput_a_SOURCES += \
src/input/IcyInputStream.cxx src/input/IcyInputStream.hxx \
src/input/plugins/CurlInputPlugin.cxx src/input/plugins/CurlInputPlugin.hxx \
src/lib/curl/Version.cxx src/lib/curl/Version.hxx \
src/lib/curl/Global.cxx src/lib/curl/Global.hxx \
src/lib/curl/Request.cxx src/lib/curl/Request.hxx \
src/lib/curl/Handler.hxx \
src/lib/curl/Easy.hxx \
src/lib/curl/Multi.hxx \
$(CURL_SOURCES) \
src/IcyMetaDataParser.cxx src/IcyMetaDataParser.hxx
endif
@@ -1382,6 +1435,7 @@ libmixer_plugins_a_SOURCES = \
src/mixer/plugins/NullMixerPlugin.cxx \
src/mixer/plugins/SoftwareMixerPlugin.cxx \
src/mixer/plugins/SoftwareMixerPlugin.hxx
libmixer_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(ALSA_CFLAGS) \
$(PULSE_CFLAGS)
@@ -1390,7 +1444,10 @@ if ENABLE_ALSA
liboutput_plugins_a_SOURCES += \
src/output/plugins/AlsaOutputPlugin.cxx \
src/output/plugins/AlsaOutputPlugin.hxx
libmixer_plugins_a_SOURCES += src/mixer/plugins/AlsaMixerPlugin.cxx
libmixer_plugins_a_SOURCES += \
src/mixer/plugins/volume_mapping.h \
src/mixer/plugins/volume_mapping.c \
src/mixer/plugins/AlsaMixerPlugin.cxx
endif
if ANDROID
@@ -1467,6 +1524,8 @@ liboutput_plugins_a_SOURCES += \
src/output/plugins/OSXOutputPlugin.cxx \
src/output/plugins/OSXOutputPlugin.hxx
endif
libmixer_plugins_a_SOURCES += \
src/mixer/plugins/OSXMixerPlugin.cxx
if ENABLE_PULSE
liboutput_plugins_a_SOURCES += \
@@ -1573,6 +1632,7 @@ endif
if ENABLE_EXPAT
libplaylist_plugins_a_SOURCES += \
src/lib/expat/StreamExpatParser.cxx \
src/lib/expat/ExpatParser.cxx src/lib/expat/ExpatParser.hxx \
src/playlist/plugins/XspfPlaylistPlugin.cxx \
src/playlist/plugins/XspfPlaylistPlugin.hxx \
@@ -1758,6 +1818,10 @@ test_run_storage_SOURCES = \
test/ScopeIOThread.hxx \
test/run_storage.cxx
if ENABLE_WEBDAV
test_run_storage_SOURCES += $(CURL_SOURCES)
endif
endif
test_run_input_LDADD = \
@@ -2095,6 +2159,7 @@ test_run_output_LDADD = $(MPD_LIBS) \
libutil.a
test_run_output_SOURCES = test/run_output.cxx \
test/ScopeIOThread.hxx \
test/NullMixerListener.hxx \
src/Log.cxx src/LogBackend.cxx \
src/IOThread.cxx \
src/output/Domain.cxx \
@@ -2118,6 +2183,7 @@ test_read_mixer_LDADD = \
libsystem.a \
libutil.a
test_read_mixer_SOURCES = test/read_mixer.cxx \
test/NullMixerListener.hxx \
src/Log.cxx src/LogBackend.cxx \
src/mixer/MixerControl.cxx \
src/filter/FilterPlugin.cxx \
@@ -2203,6 +2269,7 @@ test_test_icy_parser_LDADD = \
endif
test_test_pcm_SOURCES = \
test/TestAudioFormat.cxx test/TestAudioFormat.hxx \
test/test_pcm_util.hxx \
test/test_pcm_dither.cxx \
test/test_pcm_pack.cxx \
@@ -2378,6 +2445,7 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
$(wildcard $(srcdir)/doc/include/*.xml) \
systemd/system/mpd.socket \
$(wildcard $(srcdir)/python/build/*.py) \
android/AndroidManifest.xml \
android/build.py \
android/custom_rules.xml \
@@ -2385,5 +2453,6 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
android/src/Bridge.java \
android/src/Loader.java \
android/src/Main.java \
win32/build.py \
win32/res/mpd.rc.in win32/res/mpd.ico \
src/haiku/App_MusicPD

172
NEWS

@@ -1,3 +1,175 @@
ver 0.20.16 (2018/02/03)
* output
- pulse: fix crash during auto-detection
* database
- simple: fix search within mount points
- upnp: enable IPv6
* archive
- iso9660: libcdio 2.0 compatibility
* fix crash in debug build on Haiku and other operating systems
ver 0.20.15 (2018/01/05)
* queue: fix crash after seek failure
* resampler
- soxr: clear internal state after manual song change
* state file
- make mount point restore errors non-fatal
- fix crash when restoring mounts with incompatible database plugin
* Android
- build without Ant
- fix for SIGSYS crash
ver 0.20.14 (2018/01/01)
* database
- simple: fix file corruption in the presence of mount points
* archive
- bz2: fix deadlock
- reduce lock contention, fixing lots of xrun problems
* fix Solaris build failure
ver 0.20.13 (2017/12/18)
* output
- osx: set up ring buffer to hold at least 100ms
* mixer
- alsa: fix rounding errors
* database
- simple: don't purge mount points on update/rescan
- simple: fix "mount" bug caused by bad compiler optimization
- simple: fix "lsinfo" into mount points
- upnp: work around libupnp 1.6.24 API breakage
* queue: fix spuriously misplaced prioritized songs
* save and restore mountpoints within the state file
* include Windows cross-build script in source tarball
* fix Windows build failures
ver 0.20.12 (2017/11/25)
* database
- upnp: adapt to libupnp 1.8 API changes
* input
- cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention,
fixing lots of xrun problems
- curl: fix seeking
* decoder
- ffmpeg: fix GCC 8 warning
- vorbis: fix Tremor support
* player
- log message when decoder is too slow
* encoder
- vorbis: default to quality 3
* output
- fix hanging playback with soxr resampler
- httpd: flush encoder after tag; fixes corrupt Vorbis stream
ver 0.20.11 (2017/10/18)
* storage
- curl: support Content-Type application/xml
* decoder
- ffmpeg: more reliable song duration
- gme: fix track numbering
* improve random song order when switching songs manually
* fix case insensitive search without libicu
* fix Unicode file names in playlists on Windows
* fix endless loop when accessing malformed file names in ZIP files
ver 0.20.10 (2017/08/24)
* decoder
- ffmpeg: support MusicBrainz ID3v2 tags
* tags
- aiff: fix FORM chunk size endianess (is big-endian)
* mixer
- osx: add a mixer for OSX.
* fix crash when resuming playback before decoder is ready
* fix crash on Windows
ver 0.20.9 (2017/06/04)
* decoder
- ffmpeg: support *.adx
* fix byte order detection on FreeBSD/aarch64
* fix more random crashes when compiled with clang
ver 0.20.8 (2017/05/19)
* output
- osx: fix build failure due to missing "noexcept"
* playlist
- m3u: support MIME type `audio/mpegurl`
* fix build failure with GCC 4.x
ver 0.20.7 (2017/05/15)
* database
- simple: fix false positive directory loop detection with NFS
* enforce a reasonable minimum audio_buffer_size setting
* cap buffer_before_play at 80% to prevent deadlock
* fix random crashes when compiled with clang
ver 0.20.6 (2017/03/10)
* input
- curl: fix headers after HTTP redirect to Shoutcast server
* decoder
- ffmpeg: re-enable as fallback
- mpcdec: fix crash (division by zero) after seeking
- sidplay: make compatible with libsidplayfp < 1.8
* fix stream tags after automatic song change
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
ver 0.20.5 (2017/02/20)
* tags
- id3: fix memory leak on corrupt ID3 tags
* decoder
- sidplay: don't require libsidutils when building with libsidplayfp
* output
- httpd: fix two buffer overflows in IcyMetaData length calculation
* mixer
- alsa: fix crash bug
ver 0.20.4 (2017/02/01)
* input
- nfs: fix freeze after reconnect
* output
- sndio: work around a libroar C++ incompatibility
* workaround for GCC 4.9 "constexpr" bug
* fix FreeBSD build failure
ver 0.20.3 (2017/01/25)
* protocol
- "playlistadd" creates new playlist if it does not exist, as documented
* database
- proxy: fix error "terminate called after throwing ..."
- proxy: make connect errors during startup non-fatal
* neighbor
- upnp: fix premature expiry
* replay gain: don't reset ReplayGain levels when unpausing playback
* silence surround channels when converting from stereo
* use shortcuts such as "dsd64" in log messages
ver 0.20.2 (2017/01/15)
* input
- alsa: fix crash bug
- alsa: fix buffer overruns
* decoder
- flac: add options "probesize" and "analyzeduration"
* resampler
- libsamplerate: reset state after seeking
* output
- fix static noise after changing to a different audio format
- alsa: fix the DSD_U32 sample rate
- alsa: fix the DSD_U32 byte order
- alsa: support DSD_U16
- recorder: fix error "Failed to create : No such file or directory"
* playlist
- cue: fix skipping songs
ver 0.20.1 (2017/01/09)
* input
- curl: fix crash bug
- curl: fix freeze bug
* decoder
- wavpack: fix crash bug
* storage
- curl: new storage plugin for WebDAV (work in progress)
* mixer
- alsa: normalize displayed volume according to human perception
* fix crash with volume_normalization enabled
ver 0.20 (2017/01/04)
* protocol
- "commands" returns playlist commands only if playlist_directory configured

@@ -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
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
- [Manual](http://www.musicpd.org/doc/user/)
- [Forum](http://forum.musicpd.org/)
- [IRC](irc://chat.freenode.net/#mpd)
- [Bug tracker](http://bugs.musicpd.org/)
- [Bug tracker](https://github.com/MusicPlayerDaemon/MPD/issues/)
# Developers

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="13"
android:versionName="0.19.9">
android:versionCode="15"
android:versionName="0.20.16">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>

@@ -46,13 +46,14 @@ class AndroidNdkToolchain:
self.ndk_arch = 'arm'
android_abi = 'armeabi-v7a'
ndk_platform = 'android-14'
ndk_platform = 'android-21'
# select the NDK compiler
gcc_version = '4.9'
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
sysroot = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
sysroot = os.path.join(ndk_path, 'sysroot')
target_root = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
install_prefix = os.path.join(arch_path, 'root')
@@ -64,7 +65,9 @@ class AndroidNdkToolchain:
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
llvm_triple = 'armv7-none-linux-androideabi'
common_flags = '-march=armv7-a -mfloat-abi=softfp'
common_flags = '-Os -g'
common_flags += ' -fPIC'
common_flags += ' -march=armv7-a -mfloat-abi=softfp'
toolchain_bin = os.path.join(toolchain_path, 'bin')
llvm_bin = os.path.join(llvm_path, 'bin')
@@ -72,28 +75,40 @@ class AndroidNdkToolchain:
self.cxx = os.path.join(llvm_bin, 'clang++')
common_flags += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + toolchain_path
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
self.ar = os.path.join(toolchain_bin, arch + '-ar')
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
self.nm = os.path.join(toolchain_bin, arch + '-nm')
self.strip = os.path.join(toolchain_bin, arch + '-strip')
self.cflags = '-Os -g ' + common_flags
self.cxxflags = '-Os -g ' + common_flags
self.cppflags = '--sysroot=' + self.sysroot + ' -isystem ' + os.path.join(install_prefix, 'include')
self.ldflags = '--sysroot=' + self.sysroot + ' ' + common_flags + ' -L' + os.path.join(install_prefix, 'lib')
self.cflags = common_flags
self.cxxflags = common_flags
self.cppflags = '--sysroot=' + sysroot + \
' -isystem ' + os.path.join(install_prefix, 'include') + \
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
' -D__ANDROID_API__=21'
self.ldflags = '--sysroot=' + sysroot + \
' -L' + os.path.join(install_prefix, 'lib') + \
' -L' + os.path.join(target_root, 'usr', 'lib') + \
' -B' + os.path.join(target_root, 'usr', 'lib') + \
' ' + common_flags
self.libs = ''
self.is_arm = self.ndk_arch == 'arm'
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
self.is_windows = False
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
libcxx_libs_path = os.path.join(libcxx_path, 'libs', android_abi)
libstdcxx_flags = '-stdlib=libc++'
libstdcxx_cxxflags = libstdcxx_flags + ' -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
libstdcxx_ldflags = libstdcxx_flags + ' -static-libstdc++ -L' + libcxx_libs_path
if use_cxx:
self.libs += ' ' + libstdcxx_ldadd
self.cppflags += ' ' + libstdcxx_cppflags
self.cxxflags += ' ' + libstdcxx_cxxflags
self.ldflags += ' ' + libstdcxx_ldflags
self.env = dict(os.environ)
@@ -149,5 +164,9 @@ configure = [
] + 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(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.20, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.20.16, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=20
VERSION_REVISION=0
VERSION_REVISION=16
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -241,6 +241,7 @@ AC_CHECK_FUNCS(getpwnam_r getpwuid_r)
AC_CHECK_FUNCS(initgroups)
AC_CHECK_FUNCS(fnmatch)
AC_CHECK_FUNCS(strndup)
AC_CHECK_FUNCS(strcasestr)
if test x$host_is_linux = xyes; then
MPD_OPTIONAL_FUNC(eventfd, eventfd, USE_EVENTFD)
@@ -491,7 +492,7 @@ if test x$enable_ipv6 = xyes; then
AC_EGREP_CPP([AP_maGiC_VALUE],
[
#include <sys/types.h>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
@@ -720,6 +721,19 @@ fi
MPD_ENABLE_AUTO_PKG(mms, MMS, [libmms >= 0.4],
[libmms mms:// protocol support], [libmms not found])
dnl ---------------------------------------------------------------------------
dnl Storage Plugins
dnl ---------------------------------------------------------------------------
MPD_ENABLE_AUTO(webdav, WEBDAV, [WebDAV storage plugin],
[WebDAV requires libcurl and libexpat],
[auto],
[if test x$enable_curl = xyes && test x$enable_expat = xyes; then
found_webdav=yes
else
found_webdav=no
fi])
dnl ---------------------------------------------------------------------------
dnl Playlist Plugins
dnl ---------------------------------------------------------------------------
@@ -979,7 +993,7 @@ AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enab
dnl --------------------------------- sidplay ---------------------------------
if test x$enable_sidplay != xno; then
dnl Check for libsidplayfp first
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp libsidutils],
PKG_CHECK_MODULES([SIDPLAY], [libsidplayfp],
[found_sidplayfp=yes],
[found_sidplayfp=no])
found_sidplay=$found_sidplayfp
@@ -1371,6 +1385,11 @@ then
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
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
fi

@@ -5,7 +5,7 @@
<book>
<title>The Music Player Daemon - Developer's Manual</title>
<chapter>
<chapter id="introduction">
<title>Introduction</title>
<para>
@@ -21,7 +21,7 @@
</para>
</chapter>
<chapter>
<chapter id="code_style">
<title>Code Style</title>
<itemizedlist>
@@ -40,21 +40,47 @@
<listitem>
<para>
the code should be C++11 compliant, and must compile with
comment your code, document your APIs
</para>
</listitem>
<listitem>
<para>
the code should be C++14 compliant, and must compile with
<application>GCC</application> 4.9 and
<application>clang</application> 3.4
</para>
</listitem>
<listitem>
<para>
report error conditions with C++ exceptions, preferable
derived from <varname>std::runtime_error</varname>
</para>
</listitem>
<listitem>
<para>
all code must be exception-safe
</para>
</listitem>
<listitem>
<para>
classes and functions names use CamelCase; variables are
lower-case with words separated by underscore
</para>
</listitem>
<listitem>
<para>
Some example code:
</para>
<programlisting lang="C">static inline int
foo(const char *abc, int xyz)
Foo(const char *abc, int xyz)
{
if (abc == NULL) {
if (abc == nullptr) {
LogWarning("Foo happened!");
return -1;
}
@@ -66,25 +92,25 @@ foo(const char *abc, int xyz)
</itemizedlist>
</chapter>
<chapter>
<chapter id="hacking">
<title>Hacking The Source</title>
<para>
MPD sources are managed in a git repository on <ulink
url="http://git.musicpd.org/">git.musicpd.org</ulink>.
url="https://github.com/MusicPlayerDaemon/">GitHub</ulink>.
</para>
<para>
Always write your code against the latest git:
</para>
<programlisting>git clone git://git.musicpd.org/master/mpd.git</programlisting>
<programlisting>git clone git://github.com/MusicPlayerDaemon/MPD</programlisting>
<para>
If you already have a clone, update it:
</para>
<programlisting>git pull --rebase git://git.musicpd.org/master/mpd.git master</programlisting>
<programlisting>git pull --rebase git://github.com/MusicPlayerDaemon/MPD master</programlisting>
<para>
You can do without "--rebase", but we recommend that you rebase
@@ -151,7 +177,7 @@ foo(const char *abc, int xyz)
</section>
</chapter>
<chapter>
<chapter id="submitting_patches">
<title>Submitting Patches</title>
<para>
@@ -162,14 +188,11 @@ foo(const char *abc, int xyz)
</para>
<para>
<command>git pull</command> requests are preferred. Regular
contributors can get <ulink
url="http://git.musicpd.org/account-policy.html">an account on
git.musicpd.org</ulink>, but any public git repository will do.
<command>git pull</command> requests are preferred.
</para>
</chapter>
<chapter>
<chapter id="tools">
<title>Development Tools</title>
<section>

@@ -55,7 +55,8 @@
<listitem>
<para>
<varname>track</varname>: the track number within the album.
<varname>track</varname>: the decimal track number within the
album.
</para>
</listitem>
@@ -103,7 +104,8 @@
<listitem>
<para>
<varname>disc</varname>: the disc number in a multi-disc album.
<varname>disc</varname>: the decimal disc number in a multi-disc
album.
</para>
</listitem>
@@ -111,7 +113,7 @@
<para>
<varname>musicbrainz_artistid</varname>: the artist id in the
<ulink
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
database.
</para>
</listitem>
@@ -120,7 +122,7 @@
<para>
<varname>musicbrainz_albumid</varname>: the album id in the
<ulink
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
database.
</para>
</listitem>
@@ -129,7 +131,7 @@
<para>
<varname>musicbrainz_albumartistid</varname>: the album artist
id in the <ulink
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
database.
</para>
</listitem>
@@ -138,7 +140,7 @@
<para>
<varname>musicbrainz_trackid</varname>: the track id in the
<ulink
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
database.
</para>
</listitem>
@@ -147,7 +149,7 @@
<para>
<varname>musicbrainz_releasetrackid</varname>: the release track
id in the <ulink
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
url="https://picard.musicbrainz.org/docs/mappings/">MusicBrainz</ulink>
database.
</para>
</listitem>

@@ -48,8 +48,8 @@ mpd.conf(5), mpc(1)
.SH BUGS
If you find a bug, please report it at
.br
<\fBhttp://bugs.musicpd.org/bug_report_page.php\fP>.
<\fBhttps://github.com/MusicPlayerDaemon/MPD/issues/\fP>.
.SH AUTHORS
Max Kellermann <max@duempel.org>
Max Kellermann <max.kellermann@gmail.com>
Special thanks to all the people that provided feedback and patches.

@@ -403,6 +403,15 @@
</para>
</listitem>
</itemizedlist>
<para>
Change events accumulate, even while the connection is
not in "idle" mode; no events gets lost while the client
is doing something else with the connection. If an
event had already occurred since the last call, the new
<command>idle</command> command will return immediately.
</para>
<para>
While a client is waiting for <command>idle</command>
results, the server disables timeouts, allowing a client
@@ -436,7 +445,9 @@
<listitem>
<para>
<varname>volume</varname>:
<returnvalue>0-100</returnvalue>
<returnvalue>0-100</returnvalue> or
<returnvalue>-1</returnvalue> if the volume cannot
be determined
</para>
</listitem>
<listitem>
@@ -573,7 +584,12 @@
<listitem>
<para>
<varname>audio</varname>:
<returnvalue>sampleRate:bits:channels</returnvalue>
<returnvalue>
The format emitted by the decoder plugin during
playback, format:
"<replaceable>samplerate:bits:channels</replaceable>".
Check the user manual for a detailed explanation.
</returnvalue>
</para>
</listitem>
<listitem>

@@ -80,13 +80,40 @@
cd mpd-version</programlisting>
<para>
Make sure that all the required libraries and build tools are
installed. The <filename>INSTALL</filename> file has a list.
In any case, you need:
</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>
For example, the following installs a fairly complete list of
build dependencies on Debian Wheezy:
build dependencies on Debian Jessie:
</para>
<programlisting>
@@ -98,19 +125,20 @@ apt-get install g++ \
libmpcdec-dev libwavpack-dev libwildmidi-dev \
libsidplay2-dev libsidutils-dev libresid-builder-dev \
libavcodec-dev libavformat-dev \
libmp3lame-dev \
libmp3lame-dev libtwolame-dev libshine-dev \
libsamplerate0-dev libsoxr-dev \
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
libzzip-dev \
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
libpulse-dev libroar-dev libshout3-dev \
libsndio-dev \
libmpdclient-dev \
libnfs-dev libsmbclient-dev \
libupnp-dev \
libavahi-client-dev \
libsqlite3-dev \
libsystemd-daemon-dev libwrap0-dev \
libsystemd-dev libwrap0-dev \
libcppunit-dev xmlto \
libboost-dev \
libicu-dev
@@ -135,6 +163,91 @@ apt-get install g++ \
</para>
<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 id="systemd_socket">
@@ -576,10 +689,11 @@ systemctl start mpd.socket</programlisting>
</entry>
<entry>
<para>
Always open the audio output with the specified audio
format (samplerate:bits:channels), regardless of the
format of the input file. This is optional for most
plugins.
Always open the audio output with the specified
audio format
(<replaceable>samplerate:bits:channels</replaceable>),
regardless of the format of the input file. This is
optional for most plugins.
</para>
<para>
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),
<varname>32</varname> (signed 32 bit integer
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>
</entry>
</row>
@@ -742,9 +869,11 @@ systemctl start mpd.socket</programlisting>
<title>Configuring playlist plugins</title>
<para>
Playlist plugins are used to load remote playlists. This is
not related to <application>MPD</application>'s playlist
directory.
Playlist plugins are used to load remote playlists (protocol
commands <command>load</command>,
<command>listplaylist</command> and
<command>listplaylistinfo</command>). This is not related to
<application>MPD</application>'s playlist directory.
</para>
<para>
@@ -934,6 +1063,40 @@ systemctl start mpd.socket</programlisting>
</informaltable>
</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>
<title>Resource Limitations</title>
@@ -1064,6 +1227,55 @@ systemctl start mpd.socket</programlisting>
</tgroup>
</informaltable>
</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>
</chapter>
@@ -1646,7 +1858,7 @@ buffer_size: 16384</programlisting>
<para>
If you believe you found a bug in
<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>.
</para>
@@ -1800,6 +2012,13 @@ run</programlisting>
database.
</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>
<tgroup cols="2">
<thead>
@@ -1868,11 +2087,23 @@ run</programlisting>
</para>
</section>
<section id="curl_storage">
<title><varname>curl</varname></title>
<para>
A WebDAV client using <filename>libcurl</filename>. It is
used when <varname>music_directory</varname> contains a
<parameter>http://</parameter> or
<parameter>https://</parameter> URI, for example
"<parameter>https://the.server/dav/</parameter>".
</para>
</section>
<section id="smbclient_storage">
<title><varname>smbclient</varname></title>
<para>
Load music files from a SMB/CIFS server. It used used when
Load music files from a SMB/CIFS server. It is used when
<varname>music_directory</varname> contains a
<parameter>smb://</parameter> URI, for example
"<parameter>smb://myfileserver/Music</parameter>".
@@ -1883,7 +2114,7 @@ run</programlisting>
<title><varname>nfs</varname></title>
<para>
Load music files from a NFS server. It used used when
Load music files from a NFS server. It is used when
<varname>music_directory</varname> contains a
<parameter>nfs://</parameter> URI according to <ulink
url="http://tools.ietf.org/html/rfc2224">RFC2224</ulink>,
@@ -1958,7 +2189,9 @@ run</programlisting>
<title><varname>cdio_paranoia</varname></title>
<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
simplest form <filename>cdda://</filename> plays the whole
disc in the default drive.
@@ -1994,7 +2227,8 @@ run</programlisting>
<title><varname>curl</varname></title>
<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>
@@ -2087,7 +2321,8 @@ run</programlisting>
<title><varname>mms</varname></title>
<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>
</section>
@@ -2143,7 +2378,8 @@ run</programlisting>
<title><varname>adplug</varname></title>
<para>
Decodes AdLib files.
Decodes AdLib files using <ulink
url="http://adplug.sourceforge.net/">libadplug</ulink>.
</para>
<informaltable>
@@ -2174,8 +2410,8 @@ run</programlisting>
<title><varname>audiofile</varname></title>
<para>
Decodes WAV and AIFF files using
<filename>libaudiofile</filename>.
Decodes WAV and AIFF files using <ulink
url="http://audiofile.68k.org/"><filename>libaudiofile</filename></ulink>.
</para>
</section>
@@ -2183,7 +2419,8 @@ run</programlisting>
<title><varname>faad</varname></title>
<para>
Decodes AAC files using <filename>libfaad</filename>.
Decodes AAC files using <ulink
url="http://www.audiocoding.com/"><filename>libfaad</filename></ulink>.
</para>
</section>
@@ -2191,9 +2428,51 @@ run</programlisting>
<title><varname>ffmpeg</varname></title>
<para>
Decodes various codecs using
<application>FFmpeg</application>.
Decodes various codecs using <ulink
url="https://ffmpeg.org/"><application>FFmpeg</application></ulink>.
</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 id="flac_decoder">
@@ -2201,7 +2480,7 @@ run</programlisting>
<para>
Decodes FLAC files using
<application>libFLAC</application>.
<ulink url="https://xiph.org/flac/"><application>libFLAC</application></ulink>.
</para>
</section>
@@ -2321,7 +2600,8 @@ run</programlisting>
<title><varname>mad</varname></title>
<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>
</section>
@@ -2401,8 +2681,8 @@ run</programlisting>
<title><varname>mpcdec</varname></title>
<para>
Decodes Musepack files using
<application>libmpcdec</application>.
Decodes Musepack files using <ulink
url="http://www.musepack.net/"><application>libmpcdec</application></ulink>.
</para>
</section>
@@ -2410,7 +2690,17 @@ run</programlisting>
<title><varname>mpg123</varname></title>
<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>
</section>
@@ -2430,8 +2720,8 @@ run</programlisting>
<title><varname>sidplay</varname></title>
<para>
C64 SID decoder based on
<application>libsidplay</application>.
C64 SID decoder based on <ulink
url="http://sidplay2.sourceforge.net/"><application>libsidplay</application></ulink>.
</para>
<informaltable>
@@ -2487,8 +2777,8 @@ run</programlisting>
<title><varname>sndfile</varname></title>
<para>
Decodes WAV and AIFF files using
<filename>libsndfile</filename>.
Decodes WAV and AIFF files using <ulink
url="http://www.mega-nerd.com/libsndfile/"><filename>libsndfile</filename></ulink>.
</para>
</section>
@@ -2496,8 +2786,8 @@ run</programlisting>
<title><varname>vorbis</varname></title>
<para>
Decodes Ogg-Vorbis files using
<application>libvorbis</application>.
Decodes Ogg-Vorbis files using <ulink
url="http://www.xiph.org/ogg/vorbis/"><application>libvorbis</application></ulink>.
</para>
</section>
@@ -2506,7 +2796,7 @@ run</programlisting>
<para>
Decodes WavPack files using
<application>libwavpack</application>.
<ulink url="http://www.wavpack.com/"><application>libwavpack</application></ulink>.
</para>
</section>
@@ -2701,6 +2991,60 @@ run</programlisting>
</informaltable>
</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">
<title><varname>vorbis</varname></title>
@@ -2724,8 +3068,8 @@ run</programlisting>
</entry>
<entry>
Sets the quality for VBR. -1 is the lowest quality,
10 is the highest quality. Cannot be used with
<varname>bitrate</varname>.
10 is the highest quality. Defaults to 3. Cannot
be used with <varname>bitrate</varname>.
</entry>
</row>
<row>
@@ -3330,7 +3674,7 @@ run</programlisting>
</informaltable>
</section>
<section>
<section id="jack_output">
<title><varname>jack</varname></title>
<para>
@@ -3610,7 +3954,7 @@ run</programlisting>
</informaltable>
</section>
<section>
<section id="openal_output">
<title><varname>openal</varname></title>
<para>
@@ -3761,7 +4105,7 @@ run</programlisting>
<para>
The <varname>pulse</varname> plugin connects to a <ulink
url="http://www.freedesktop.org/wiki/Software/PulseAudio/"><application>PulseAudio</application></ulink>
server.
server. Requires <filename>libpulse</filename>.
</para>
<informaltable>
@@ -3918,7 +4262,7 @@ run</programlisting>
(logical "and") can be used to select portions of
the format string depending on the existing tag
values. Example:
<parameter>~/.mpd/recorder/[%title|%name%].ogg</parameter>
<parameter>~/.mpd/recorder/[%title%|%name%].ogg</parameter>
(use the "name" tag if no title exists)
</para>
</entry>
@@ -3949,7 +4293,8 @@ run</programlisting>
url="http://www.shoutcast.com/"><application>ShoutCast</application></ulink>
or <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>
@@ -4139,6 +4484,22 @@ run</programlisting>
<section id="playlist_plugins">
<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>
<title><varname>embcue</varname></title>
@@ -4163,6 +4524,15 @@ run</programlisting>
</para>
</section>
<section>
<title><varname>flac</varname></title>
<para>
Reads the <varname>cuesheet</varname> metablock from a FLAC
file.
</para>
</section>
<section>
<title><varname>pls</varname></title>
@@ -4171,6 +4541,45 @@ run</programlisting>
</para>
</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>
<title><varname>xspf</varname></title>

@@ -1,6 +1,6 @@
# Check if "struct ucred" is available.
#
# Author: Max Kellermann <max@duempel.org>
# Author: Max Kellermann <max.kellermann@gmail.com>
AC_DEFUN([STRUCT_UCRED],[
AC_MSG_CHECKING([for struct ucred])

@@ -1,21 +1,30 @@
import os.path, subprocess
import os.path, subprocess, sys
from build.project import Project
from build.makeproject import MakeProject
class AutotoolsProject(Project):
class AutotoolsProject(MakeProject):
def __init__(self, url, md5, installed, configure_args=[],
autogen=False,
cppflags='',
ldflags='',
libs='',
subdirs=None,
**kwargs):
Project.__init__(self, url, md5, installed, **kwargs)
MakeProject.__init__(self, url, md5, installed, **kwargs)
self.configure_args = configure_args
self.autogen = autogen
self.cppflags = cppflags
self.ldflags = ldflags
self.libs = libs
self.subdirs = subdirs
def build(self, toolchain):
def configure(self, toolchain):
src = self.unpack(toolchain)
if self.autogen:
subprocess.check_call(['libtoolize', '--force'], cwd=src)
if sys.platform == 'darwin':
subprocess.check_call(['glibtoolize', '--force'], cwd=src)
else:
subprocess.check_call(['libtoolize', '--force'], cwd=src)
subprocess.check_call(['aclocal'], cwd=src)
subprocess.check_call(['automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
subprocess.check_call(['autoconf'], cwd=src)
@@ -29,8 +38,8 @@ class AutotoolsProject(Project):
'CFLAGS=' + toolchain.cflags,
'CXXFLAGS=' + toolchain.cxxflags,
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
'LDFLAGS=' + toolchain.ldflags,
'LIBS=' + toolchain.libs,
'LDFLAGS=' + toolchain.ldflags + ' ' + self.ldflags,
'LIBS=' + toolchain.libs + ' ' + self.libs,
'AR=' + toolchain.ar,
'RANLIB=' + toolchain.ranlib,
'STRIP=' + toolchain.strip,
@@ -40,7 +49,12 @@ class AutotoolsProject(Project):
] + self.configure_args
subprocess.check_call(configure, cwd=build, env=toolchain.env)
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'],
cwd=build, env=toolchain.env)
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'],
cwd=build, env=toolchain.env)
return build
def build(self, toolchain):
build = self.configure(toolchain)
if self.subdirs is not None:
for subdir in self.subdirs:
MakeProject.build(self, toolchain, os.path.join(build, subdir))
else:
MakeProject.build(self, toolchain, build)

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

@@ -1,3 +1,4 @@
import re
from build.project import Project
from build.zlib import ZlibProject
from build.autotools import AutotoolsProject
@@ -5,24 +6,35 @@ from build.ffmpeg import FfmpegProject
from build.boost import BoostProject
libogg = AutotoolsProject(
'http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz',
'5c3a34309d8b98640827e5d0991a4015',
'http://downloads.xiph.org/releases/ogg/libogg-1.3.3.tar.xz',
'4f3fc6178a533d392064f14776b23c397ed4b9f48f5de297aba73b643f955c08',
'lib/libogg.a',
['--disable-shared', '--enable-static'],
[
'--disable-shared', '--enable-static',
],
)
libvorbis = AutotoolsProject(
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz',
'28cb28097c07a735d6af56e598e1c90f',
'lib/libvorbis.a',
['--disable-shared', '--enable-static'],
[
'--disable-shared', '--enable-static',
],
)
opus = AutotoolsProject(
'http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz',
'32bbb6b557fe1b6066adc0ae1f08b629',
'https://archive.mozilla.org/pub/opus/opus-1.2.1.tar.gz',
'cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732',
'lib/libopus.a',
['--disable-shared', '--enable-static'],
[
'--disable-shared', '--enable-static',
'--disable-doc',
'--disable-extra-programs',
],
# suppress "visibility default" from opus_defines.h
cppflags='-DOPUS_EXPORT=',
)
flac = AutotoolsProject(
@@ -32,12 +44,14 @@ flac = AutotoolsProject(
[
'--disable-shared', '--enable-static',
'--disable-xmms-plugin', '--disable-cpplibs',
'--disable-doxygen-docs',
],
subdirs=['include', 'src/libFLAC'],
)
zlib = ZlibProject(
'http://zlib.net/zlib-1.2.8.tar.xz',
'28f1205d8dd2001f26fec1e8c2cebe37',
'http://zlib.net/zlib-1.2.11.tar.xz',
'4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066',
'lib/libz.a',
)
@@ -45,21 +59,47 @@ libid3tag = AutotoolsProject(
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
'e5808ad997ba32c498803822078748c3',
'lib/libid3tag.a',
['--disable-shared', '--enable-static'],
[
'--disable-shared', '--enable-static',
# without this, libid3tag's configure.ac ignores -O* and -f*
'--disable-debugging',
],
autogen=True,
edits={
# fix bug in libid3tag's configure.ac which discards all but the last optimization flag
'configure.ac': lambda data: re.sub(r'optimize="\$1"', r'optimize="$optimize $1"', data, count=1),
}
)
libmad = AutotoolsProject(
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
'1be543bc30c56fb6bea1d7bf6a64e66c',
'lib/libmad.a',
['--disable-shared', '--enable-static'],
[
'--disable-shared', '--enable-static',
# without this, libmad's configure.ac ignores -O* and -f*
'--disable-debugging',
],
autogen=True,
)
liblame = AutotoolsProject(
'http://downloads.sourceforge.net/project/lame/lame/3.100/lame-3.100.tar.gz',
'ddfe36cab873794038ae2c1210557ad34857a4b6bdc515785d1da9e175b1da1e',
'lib/libmp3lame.a',
[
'--disable-shared', '--enable-static',
'--disable-gtktest', '--disable-analyzer-hooks',
'--disable-decoder', '--disable-frontend',
],
)
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz',
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc',
'http://ffmpeg.org/releases/ffmpeg-3.4.1.tar.xz',
'5a77278a63741efa74e26bf197b9bb09ac6381b9757391b922407210f0f991c0',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',
@@ -73,17 +113,234 @@ ffmpeg = FfmpegProject(
'--disable-swscale',
'--disable-postproc',
'--disable-avfilter',
'--disable-lzo',
'--disable-faan',
'--disable-pixelutils',
'--disable-network',
'--disable-encoders',
'--disable-muxers',
'--disable-protocols',
'--disable-outdevs',
'--disable-devices',
'--disable-filters',
'--disable-filters',
'--disable-v4l2_m2m',
'--disable-parser=bmp',
'--disable-parser=cavsvideo',
'--disable-parser=dvbsub',
'--disable-parser=dvdsub',
'--disable-parser=dvd_nav',
'--disable-parser=flac',
'--disable-parser=g729',
'--disable-parser=gsm',
'--disable-parser=h261',
'--disable-parser=h263',
'--disable-parser=h264',
'--disable-parser=hevc',
'--disable-parser=mjpeg',
'--disable-parser=mlp',
'--disable-parser=mpeg4video',
'--disable-parser=mpegaudio',
'--disable-parser=mpegvideo',
'--disable-parser=opus',
'--disable-parser=vc1',
'--disable-parser=vp3',
'--disable-parser=vp8',
'--disable-parser=vp9',
'--disable-parser=png',
'--disable-parser=pnm',
'--disable-parser=xma',
'--disable-demuxer=aqtitle',
'--disable-demuxer=ass',
'--disable-demuxer=bethsoftvid',
'--disable-demuxer=bink',
'--disable-demuxer=cavsvideo',
'--disable-demuxer=cdxl',
'--disable-demuxer=dvbsub',
'--disable-demuxer=dvbtxt',
'--disable-demuxer=h261',
'--disable-demuxer=h263',
'--disable-demuxer=h264',
'--disable-demuxer=ico',
'--disable-demuxer=image2',
'--disable-demuxer=jacosub',
'--disable-demuxer=lrc',
'--disable-demuxer=microdvd',
'--disable-demuxer=mjpeg',
'--disable-demuxer=mjpeg_2000',
'--disable-demuxer=mpegps',
'--disable-demuxer=mpegvideo',
'--disable-demuxer=mpl2',
'--disable-demuxer=mpsub',
'--disable-demuxer=pjs',
'--disable-demuxer=rawvideo',
'--disable-demuxer=realtext',
'--disable-demuxer=sami',
'--disable-demuxer=scc',
'--disable-demuxer=srt',
'--disable-demuxer=stl',
'--disable-demuxer=subviewer',
'--disable-demuxer=subviewer1',
'--disable-demuxer=swf',
'--disable-demuxer=tedcaptions',
'--disable-demuxer=vobsub',
'--disable-demuxer=vplayer',
'--disable-demuxer=webvtt',
'--disable-demuxer=yuv4mpegpipe',
# we don't need these decoders, because we have the dedicated
# libraries
'--disable-decoder=flac',
'--disable-decoder=mp1',
'--disable-decoder=mp1float',
'--disable-decoder=mp2',
'--disable-decoder=mp2float',
'--disable-decoder=mp3',
'--disable-decoder=mp3adu',
'--disable-decoder=mp3adufloat',
'--disable-decoder=mp3float',
'--disable-decoder=mp3on4',
'--disable-decoder=mp3on4float',
'--disable-decoder=opus',
'--disable-decoder=vorbis',
# audio codecs nobody uses
'--disable-decoder=atrac1',
'--disable-decoder=atrac3',
'--disable-decoder=atrac3al',
'--disable-decoder=atrac3p',
'--disable-decoder=atrac3pal',
'--disable-decoder=binkaudio_dct',
'--disable-decoder=binkaudio_rdft',
'--disable-decoder=bmv_audio',
'--disable-decoder=dsicinaudio',
'--disable-decoder=dvaudio',
'--disable-decoder=metasound',
'--disable-decoder=paf_audio',
'--disable-decoder=ra_144',
'--disable-decoder=ra_288',
'--disable-decoder=ralf',
'--disable-decoder=qdm2',
'--disable-decoder=qdmc',
# disable lots of image and video codecs
'--disable-decoder=ass',
'--disable-decoder=asv1',
'--disable-decoder=asv2',
'--disable-decoder=apng',
'--disable-decoder=avrn',
'--disable-decoder=avrp',
'--disable-decoder=bethsoftvid',
'--disable-decoder=bink',
'--disable-decoder=bmp',
'--disable-decoder=bmv_video',
'--disable-decoder=cavs',
'--disable-decoder=ccaption',
'--disable-decoder=cdgraphics',
'--disable-decoder=clearvideo',
'--disable-decoder=dirac',
'--disable-decoder=dsicinvideo',
'--disable-decoder=dvbsub',
'--disable-decoder=dvdsub',
'--disable-decoder=dvvideo',
'--disable-decoder=exr',
'--disable-decoder=ffv1',
'--disable-decoder=ffvhuff',
'--disable-decoder=ffwavesynth',
'--disable-decoder=flic',
'--disable-decoder=flv',
'--disable-decoder=fraps',
'--disable-decoder=gif',
'--disable-decoder=h261',
'--disable-decoder=h263',
'--disable-decoder=h263i',
'--disable-decoder=h263p',
'--disable-decoder=h264',
'--disable-decoder=hevc',
'--disable-decoder=hnm4_video',
'--disable-decoder=hq_hqa',
'--disable-decoder=hqx',
'--disable-decoder=idcin',
'--disable-decoder=iff_ilbm',
'--disable-decoder=indeo2',
'--disable-decoder=indeo3',
'--disable-decoder=indeo4',
'--disable-decoder=indeo5',
'--disable-decoder=interplay_video',
'--disable-decoder=jacosub',
'--disable-decoder=jpeg2000',
'--disable-decoder=jpegls',
'--disable-decoder=microdvd',
'--disable-decoder=mimic',
'--disable-decoder=mjpeg',
'--disable-decoder=mmvideo',
'--disable-decoder=mpl2',
'--disable-decoder=motionpixels',
'--disable-decoder=mpeg1video',
'--disable-decoder=mpeg2video',
'--disable-decoder=mpeg4',
'--disable-decoder=mpegvideo',
'--disable-decoder=mscc',
'--disable-decoder=msmpeg4_crystalhd',
'--disable-decoder=msmpeg4v1',
'--disable-decoder=msmpeg4v2',
'--disable-decoder=msmpeg4v3',
'--disable-decoder=msvideo1',
'--disable-decoder=mszh',
'--disable-decoder=mvc1',
'--disable-decoder=mvc2',
'--disable-decoder=on2avc',
'--disable-decoder=paf_video',
'--disable-decoder=png',
'--disable-decoder=qdraw',
'--disable-decoder=qpeg',
'--disable-decoder=rawvideo',
'--disable-decoder=realtext',
'--disable-decoder=roq',
'--disable-decoder=roq_dpcm',
'--disable-decoder=rscc',
'--disable-decoder=rv10',
'--disable-decoder=rv20',
'--disable-decoder=rv30',
'--disable-decoder=rv40',
'--disable-decoder=sami',
'--disable-decoder=sheervideo',
'--disable-decoder=snow',
'--disable-decoder=srt',
'--disable-decoder=stl',
'--disable-decoder=subrip',
'--disable-decoder=subviewer',
'--disable-decoder=subviewer1',
'--disable-decoder=svq1',
'--disable-decoder=svq3',
'--disable-decoder=tiff',
'--disable-decoder=mottiertexseqvideo',
'--disable-decoder=truemotion1',
'--disable-decoder=truemotion2',
'--disable-decoder=truemotion2rt',
'--disable-decoder=twinvq',
'--disable-decoder=utvideo',
'--disable-decoder=vc1',
'--disable-decoder=vmdvideo',
'--disable-decoder=vp3',
'--disable-decoder=vp5',
'--disable-decoder=vp6',
'--disable-decoder=vp7',
'--disable-decoder=vp8',
'--disable-decoder=vp9',
'--disable-decoder=vqa',
'--disable-decoder=webvtt',
'--disable-decoder=wmv1',
'--disable-decoder=wmv2',
'--disable-decoder=wmv3',
'--disable-decoder=yuv4',
],
)
curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.52.1.tar.lzma',
'44286d4b825936e2430fc44ad730ce899afb736a5d328cbb8b5d42462f3f2365',
'http://curl.haxx.se/download/curl-7.58.0.tar.xz',
'6a813875243609eb75f37fa72044e4ad618b55ec15a4eafdac2df6a7e800e3e3',
'lib/libcurl.a',
[
'--disable-shared', '--enable-static',
@@ -94,6 +351,7 @@ curl = AutotoolsProject(
'--disable-ldap', '--disable-ldaps',
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
'--disable-smb',
'--disable-gopher',
'--disable-manual',
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
@@ -103,7 +361,7 @@ curl = AutotoolsProject(
)
boost = BoostProject(
'http://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.bz2',
'beae2529f759f6b3bf3f4969a19c2e9d6f0c503edcb2de4a61d1428519fcb3b0',
'http://downloads.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.bz2',
'5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9',
'include/boost/version.hpp',
)

@@ -0,0 +1,28 @@
import subprocess
from build.project import Project
class MakeProject(Project):
def __init__(self, url, md5, installed,
install_target='install',
**kwargs):
Project.__init__(self, url, md5, installed, **kwargs)
self.install_target = install_target
def get_simultaneous_jobs(self):
return 12
def get_make_args(self, toolchain):
return ['--quiet', '-j' + str(self.get_simultaneous_jobs())]
def get_make_install_args(self, toolchain):
return ['--quiet', self.install_target]
def make(self, toolchain, wd, args):
subprocess.check_call(['/usr/bin/make'] + args,
cwd=wd, env=toolchain.env)
def build(self, toolchain, wd, install=True):
self.make(toolchain, wd, self.get_make_args(toolchain))
if install:
self.make(toolchain, wd, self.get_make_install_args(toolchain))

@@ -7,6 +7,7 @@ from build.tar import untar
class Project:
def __init__(self, url, md5, installed, name=None, version=None,
base=None,
edits=None,
use_cxx=False):
if base is None:
basename = os.path.basename(url)
@@ -28,6 +29,7 @@ class Project:
self.md5 = md5
self.installed = installed
self.edits = edits
self.use_cxx = use_cxx
def download(self, toolchain):
@@ -47,7 +49,18 @@ class Project:
parent_path = toolchain.src_path
else:
parent_path = toolchain.build_path
return untar(self.download(toolchain), parent_path, self.base)
path = untar(self.download(toolchain), parent_path, self.base)
if self.edits is not None:
for filename, function in self.edits.items():
with open(os.path.join(path, filename), 'r+t') as f:
old_data = f.read()
new_data = function(old_data)
f.seek(0)
f.truncate(0)
f.write(new_data)
return path
def make_build_path(self, toolchain):
path = os.path.join(toolchain.build_path, self.base)

@@ -18,12 +18,13 @@
*/
#include "AudioFormat.hxx"
#include "util/StringBuffer.hxx"
#include <assert.h>
#include <stdio.h>
void
AudioFormat::ApplyMask(AudioFormat mask)
AudioFormat::ApplyMask(AudioFormat mask) noexcept
{
assert(IsValid());
assert(mask.IsMaskValid());
@@ -40,46 +41,24 @@ AudioFormat::ApplyMask(AudioFormat mask)
assert(IsValid());
}
const char *
sample_format_to_string(SampleFormat format)
StringBuffer<24>
ToString(const AudioFormat af) noexcept
{
switch (format) {
case SampleFormat::UNDEFINED:
return "?";
StringBuffer<24> buffer;
case SampleFormat::S8:
return "8";
case SampleFormat::S16:
return "16";
case SampleFormat::S24_P32:
return "24";
case SampleFormat::S32:
return "32";
case SampleFormat::FLOAT:
return "f";
case SampleFormat::DSD:
return "dsd";
if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
af.sample_rate % 44100 == 0) {
/* use shortcuts such as "dsd64" which implies the
sample rate */
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u",
af.sample_rate * 8 / 44100,
af.channels);
return buffer;
}
/* unreachable */
assert(false);
gcc_unreachable();
}
const char *
audio_format_to_string(const AudioFormat af,
struct audio_format_string *s)
{
assert(s != nullptr);
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u",
af.sample_rate, sample_format_to_string(af.format),
af.channels);
return s->buffer;
return buffer;
}

@@ -20,47 +20,14 @@
#ifndef MPD_AUDIO_FORMAT_HXX
#define MPD_AUDIO_FORMAT_HXX
#include "pcm/SampleFormat.hxx"
#include "Compiler.h"
#include <stdint.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
/* on WIN32, "FLOAT" is already defined, and this triggers -Wshadow */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#endif
enum class SampleFormat : uint8_t {
UNDEFINED = 0,
S8,
S16,
/**
* Signed 24 bit integer samples, packed in 32 bit integers
* (the most significant byte is filled with the sign bit).
*/
S24_P32,
S32,
/**
* 32 bit floating point samples in the host's format. The
* range is -1.0f to +1.0f.
*/
FLOAT,
/**
* Direct Stream Digital. 1-bit samples; each frame has one
* byte (8 samples) per channel.
*/
DSD,
};
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif
template<size_t CAPACITY> class StringBuffer;
static constexpr unsigned MAX_CHANNELS = 8;
@@ -157,10 +124,10 @@ struct AudioFormat {
return !(*this == other);
}
void ApplyMask(AudioFormat mask);
void ApplyMask(AudioFormat mask) noexcept;
gcc_pure
AudioFormat WithMask(AudioFormat mask) const {
AudioFormat WithMask(AudioFormat mask) const noexcept {
AudioFormat result = *this;
result.ApplyMask(mask);
return result;
@@ -183,13 +150,6 @@ struct AudioFormat {
double GetTimeToSize() const;
};
/**
* Buffer for audio_format_string().
*/
struct audio_format_string {
char buffer[24];
};
/**
* Checks whether the sample rate is valid.
*
@@ -201,28 +161,6 @@ audio_valid_sample_rate(unsigned sample_rate)
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.
*/
@@ -258,34 +196,6 @@ AudioFormat::IsMaskValid() const
(channels == 0 || audio_valid_channel_count(channels));
}
gcc_const
static inline unsigned
sample_format_size(SampleFormat format)
{
switch (format) {
case SampleFormat::S8:
return 1;
case SampleFormat::S16:
return 2;
case SampleFormat::S24_P32:
case SampleFormat::S32:
case SampleFormat::FLOAT:
return 4;
case SampleFormat::DSD:
/* each frame has 8 samples per channel */
return 1;
case SampleFormat::UNDEFINED:
return 0;
}
assert(false);
gcc_unreachable();
}
inline unsigned
AudioFormat::GetSampleSize() const
{
@@ -304,28 +214,15 @@ AudioFormat::GetTimeToSize() const
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
* it in a log file.
*
* @param af the #AudioFormat object
* @param s a buffer to print into
* @return the string, or nullptr if the #AudioFormat object is invalid
* @return the string buffer
*/
gcc_pure gcc_malloc
const char *
audio_format_to_string(AudioFormat af,
struct audio_format_string *s);
gcc_const
StringBuffer<24>
ToString(AudioFormat af) noexcept;
#endif

@@ -137,6 +137,26 @@ ParseAudioFormat(const char *src, bool mask)
AudioFormat dest;
dest.Clear();
if (strncmp(src, "dsd", 3) == 0) {
/* allow format specifications such as "dsd64" which
implies the sample rate */
char *endptr;
auto dsd = strtoul(src + 3, &endptr, 10);
if (endptr > src + 3 && *endptr == ':' &&
dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
dest.sample_rate = dsd * 44100 / 8;
dest.format = SampleFormat::DSD;
src = endptr + 1;
dest.channels = ParseChannelCount(src, mask, &src);
if (*src != 0)
throw FormatRuntimeError("Extra data after channel count: %s", src);
return dest;
}
}
/* parse sample rate */
dest.sample_rate = ParseSampleRate(src, mask, &src);

@@ -25,8 +25,6 @@
#ifndef MPD_AUDIO_PARSER_HXX
#define MPD_AUDIO_PARSER_HXX
#include "Compiler.h"
struct AudioFormat;
/**
@@ -38,7 +36,6 @@ struct AudioFormat;
* @param src the input string
* @param mask if true, then "*" is allowed for any number of items
*/
gcc_pure
AudioFormat
ParseAudioFormat(const char *src, bool mask);

@@ -67,7 +67,7 @@
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#ifdef _WIN32
#define CONFIG_FILE_LOCATION PATH_LITERAL("mpd\\mpd.conf")
#define APP_CONFIG_FILE_LOCATION PATH_LITERAL("conf\\mpd.conf")
#else
@@ -107,7 +107,7 @@ static void version(void)
"\n"
"\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"
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -389,7 +389,7 @@ ParseCommandLine(int argc, char **argv, struct options *options)
ConfigLoader loader;
bool found =
#ifdef WIN32
#ifdef _WIN32
loader.TryFile(GetUserConfigDir(), CONFIG_FILE_LOCATION) ||
loader.TryFile(GetSystemConfigDir(), CONFIG_FILE_LOCATION) ||
loader.TryFile(GetAppBaseDir(), APP_CONFIG_FILE_LOCATION);

@@ -37,19 +37,19 @@ DetachedSong::~DetachedSong()
}
bool
DetachedSong::IsRemote() const
DetachedSong::IsRemote() const noexcept
{
return uri_has_scheme(GetRealURI());
}
bool
DetachedSong::IsAbsoluteFile() const
DetachedSong::IsAbsoluteFile() const noexcept
{
return PathTraitsUTF8::IsAbsolute(GetRealURI());
}
bool
DetachedSong::IsInDatabase() const
DetachedSong::IsInDatabase() const noexcept
{
/* here, we use GetURI() and not GetRealURI() because
GetRealURI() is never relative */
@@ -59,7 +59,7 @@ DetachedSong::IsInDatabase() const
}
SignedSongTime
DetachedSong::GetDuration() const
DetachedSong::GetDuration() const noexcept
{
SongTime a = start_time, b = end_time;
if (!b.IsPositive()) {

@@ -63,18 +63,18 @@ class DetachedSong {
Tag tag;
time_t mtime;
time_t mtime = 0;
/**
* Start of this sub-song within the file.
*/
SongTime start_time;
SongTime start_time = SongTime::zero();
/**
* End of this sub-song within the file.
* Unused if zero.
*/
SongTime end_time;
SongTime end_time = SongTime::zero();
explicit DetachedSong(const LightSong &other);
@@ -82,33 +82,25 @@ public:
explicit DetachedSong(const DetachedSong &) = default;
explicit DetachedSong(const char *_uri)
:uri(_uri),
mtime(0),
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
:uri(_uri) {}
explicit DetachedSong(const std::string &_uri)
:uri(_uri),
mtime(0),
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
:uri(_uri) {}
explicit DetachedSong(std::string &&_uri)
:uri(std::move(_uri)),
mtime(0),
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
:uri(std::move(_uri)) {}
template<typename U>
DetachedSong(U &&_uri, Tag &&_tag)
:uri(std::forward<U>(_uri)),
tag(std::move(_tag)),
mtime(0),
start_time(SongTime::zero()), end_time(SongTime::zero()) {}
tag(std::move(_tag)) {}
DetachedSong(DetachedSong &&) = default;
~DetachedSong();
gcc_pure
const char *GetURI() const {
const char *GetURI() const noexcept {
return uri.c_str();
}
@@ -122,7 +114,7 @@ public:
* displayed URI?
*/
gcc_pure
bool HasRealURI() const {
bool HasRealURI() const noexcept {
return !real_uri.empty();
}
@@ -131,7 +123,7 @@ public:
* GetURI().
*/
gcc_pure
const char *GetRealURI() const {
const char *GetRealURI() const noexcept {
return (HasRealURI() ? real_uri : uri).c_str();
}
@@ -145,34 +137,36 @@ public:
* song.
*/
gcc_pure
bool IsSame(const DetachedSong &other) const {
return uri == other.uri;
bool IsSame(const DetachedSong &other) const noexcept {
return uri == other.uri &&
start_time == other.start_time &&
end_time == other.end_time;
}
gcc_pure gcc_nonnull_all
bool IsURI(const char *other_uri) const {
bool IsURI(const char *other_uri) const noexcept {
return uri == other_uri;
}
gcc_pure
bool IsRemote() const;
bool IsRemote() const noexcept;
gcc_pure
bool IsFile() const {
bool IsFile() const noexcept {
return !IsRemote();
}
gcc_pure
bool IsAbsoluteFile() const;
bool IsAbsoluteFile() const noexcept;
gcc_pure
bool IsInDatabase() const;
bool IsInDatabase() const noexcept;
const Tag &GetTag() const {
const Tag &GetTag() const noexcept {
return tag;
}
Tag &WritableTag() {
Tag &WritableTag() noexcept {
return tag;
}
@@ -221,7 +215,7 @@ public:
}
gcc_pure
SignedSongTime GetDuration() const;
SignedSongTime GetDuration() const noexcept;
/**
* Update the #tag and #mtime.

@@ -27,12 +27,17 @@
#include <assert.h>
static struct {
static struct IOThread {
Mutex mutex;
Cond cond;
EventLoop *loop;
Thread thread;
IOThread():thread(BIND_THIS_METHOD(Run)) {}
private:
void Run() noexcept;
} io;
void
@@ -44,15 +49,15 @@ io_thread_run(void)
io.loop->Run();
}
static void
io_thread_func(gcc_unused void *arg)
inline void
IOThread::Run() noexcept
{
SetThreadName("io");
/* lock+unlock to synchronize with io_thread_start(), to be
sure that io.thread is set */
io.mutex.lock();
io.mutex.unlock();
mutex.lock();
mutex.unlock();
io_thread_run();
}
@@ -73,7 +78,7 @@ io_thread_start()
assert(!io.thread.IsDefined());
const std::lock_guard<Mutex> protect(io.mutex);
io.thread.Start(io_thread_func, nullptr);
io.thread.Start();
}
void
@@ -96,15 +101,19 @@ io_thread_deinit(void)
}
EventLoop &
io_thread_get()
io_thread_get() noexcept
{
assert(io.loop != nullptr);
return *io.loop;
}
#ifndef NDEBUG
bool
io_thread_inside(void)
io_thread_inside() noexcept
{
return io.thread.IsInside();
}
#endif

@@ -20,6 +20,7 @@
#ifndef MPD_IO_THREAD_HXX
#define MPD_IO_THREAD_HXX
#include "check.h"
#include "Compiler.h"
class EventLoop;
@@ -51,13 +52,17 @@ io_thread_deinit();
gcc_const
EventLoop &
io_thread_get();
io_thread_get() noexcept;
#ifndef NDEBUG
/**
* Is the current thread the I/O thread?
*/
gcc_pure
bool
io_thread_inside();
io_thread_inside() noexcept;
#endif
#endif

@@ -46,13 +46,13 @@ static const char *const idle_names[] = {
};
const char*const*
idle_get_names(void)
idle_get_names() noexcept
{
return idle_names;
}
unsigned
idle_parse_name(const char *name)
idle_parse_name(const char *name) noexcept
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */

@@ -70,8 +70,9 @@ static constexpr unsigned IDLE_MOUNT = 0x1000;
/**
* Get idle names
*/
gcc_const
const char*const*
idle_get_names();
idle_get_names() noexcept;
/**
* 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
unsigned
idle_parse_name(const char *name);
idle_parse_name(const char *name) noexcept;
#endif

@@ -117,7 +117,6 @@ struct Instance final
* DatabaseError if this MPD configuration has no database (no
* music_directory was configured).
*/
gcc_pure
const Database &GetDatabaseOrThrow() const;
#endif

@@ -24,7 +24,7 @@
#include "Compiler.h"
#include "fs/AllocatedPath.hxx"
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ABSOLUTE

@@ -162,7 +162,7 @@ FileLog(const Domain &domain, const char *message)
domain.GetName(),
chomp_length(message), message);
#ifdef WIN32
#ifdef _WIN32
/* force-flush the log file, because setvbuf() does not seem
to have an effect on WIN32 */
fflush(stderr);

@@ -72,7 +72,7 @@ log_init_file(int line)
out_fd = open_log_file();
if (out_fd < 0) {
#ifdef WIN32
#ifdef _WIN32
const std::string out_path_utf8 = out_path.ToUTF8();
throw FormatRuntimeError("failed to open log file \"%s\" (config line %d)",
out_path_utf8.c_str(), line);
@@ -182,7 +182,7 @@ void setup_log_output()
fflush(nullptr);
if (out_fd < 0) {
#ifdef WIN32
#ifdef _WIN32
return;
#else
out_fd = open("/dev/null", O_WRONLY);

@@ -20,7 +20,7 @@
#ifndef MPD_LOG_LEVEL_HXX
#define MPD_LOG_LEVEL_HXX
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ERROR

@@ -106,7 +106,7 @@
#include <locale.h>
#endif
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
@@ -117,7 +117,21 @@
#include <limits.h>
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
static constexpr size_t KILOBYTE = 1024;
static constexpr size_t MEGABYTE = 1024 * KILOBYTE;
static constexpr size_t DEFAULT_BUFFER_SIZE = 4 * MEGABYTE;
static
#if GCC_OLDER_THAN(5,0)
/* gcc 4.x has no "constexpr" for std::max() */
const
#else
constexpr
#endif
size_t MIN_BUFFER_SIZE = std::max(CHUNK_SIZE * 32,
64 * KILOBYTE);
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
#ifdef ANDROID
@@ -130,7 +144,6 @@ struct Config {
ReplayGainConfig replay_gain;
};
gcc_const
static Config
LoadConfig()
{
@@ -203,7 +216,11 @@ glue_db_init_and_load(void)
"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))
return true;
@@ -272,7 +289,7 @@ glue_state_file_init()
*/
static void winsock_init(void)
{
#ifdef WIN32
#ifdef _WIN32
WSADATA sockinfo;
int retval = WSAStartup(MAKEWORD(2, 2), &sockinfo);
@@ -303,12 +320,17 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
FormatFatalError("buffer size \"%s\" is not a "
"positive integer, line %i",
param->value.c_str(), param->line);
buffer_size = tmp;
buffer_size = tmp * KILOBYTE;
if (buffer_size < MIN_BUFFER_SIZE) {
FormatWarning(config_domain, "buffer size %lu is too small, using %lu bytes instead",
(unsigned long)buffer_size,
(unsigned long)MIN_BUFFER_SIZE);
buffer_size = MIN_BUFFER_SIZE;
}
} else
buffer_size = DEFAULT_BUFFER_SIZE;
buffer_size *= 1024;
const unsigned buffered_chunks = buffer_size / CHUNK_SIZE;
if (buffered_chunks >= 1 << 15)
@@ -326,6 +348,19 @@ initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
"than 100 percent, line %i",
param->value.c_str(), param->line);
}
if (perc > 80) {
/* this upper limit should avoid deadlocks
which can occur because the DecoderThread
cannot ever fill the music buffer to
exactly 100%; a few chunks always need to
be available to generate silence in
Player::SendSilence() */
FormatError(config_domain,
"buffer_before_play is too large (%f%%), capping at 80%%; please fix your configuration",
perc);
perc = 80;
}
} else
perc = DEFAULT_BUFFER_BEFORE_PLAY;
@@ -383,7 +418,7 @@ Instance::OnIdle(unsigned flags)
int main(int argc, char *argv[])
{
#ifdef WIN32
#ifdef _WIN32
return win32_main(argc, argv);
#else
return mpd_main(argc, argv);
@@ -580,7 +615,7 @@ try {
playlist_state_restore() */
instance->partition->pc.LockUpdateAudio();
#ifdef WIN32
#ifdef _WIN32
win32_app_started();
#endif
@@ -595,7 +630,7 @@ try {
/* run the main loop */
instance->event_loop.Run();
#ifdef WIN32
#ifdef _WIN32
win32_app_stopping();
#endif
@@ -667,7 +702,7 @@ try {
daemonize_finish();
#endif
#ifdef WIN32
#ifdef _WIN32
WSACleanup();
#endif

@@ -42,7 +42,7 @@ int mpd_main(int argc, char *argv[]);
#endif
#ifdef WIN32
#ifdef _WIN32
/**
* If program is run as windows service performs nessesary initialization

@@ -59,14 +59,14 @@ mapper_init(AllocatedPath &&_playlist_dir)
}
void
mapper_finish()
mapper_finish() noexcept
{
}
#ifdef ENABLE_DATABASE
AllocatedPath
map_uri_fs(const char *uri)
map_uri_fs(const char *uri) noexcept
{
assert(uri != nullptr);
assert(*uri != '/');
@@ -86,7 +86,7 @@ map_uri_fs(const char *uri)
}
std::string
map_fs_to_utf8(Path path_fs)
map_fs_to_utf8(Path path_fs) noexcept
{
if (path_fs.IsAbsolute()) {
if (instance->storage == nullptr)
@@ -109,13 +109,13 @@ map_fs_to_utf8(Path path_fs)
#endif
const AllocatedPath &
map_spl_path()
map_spl_path() noexcept
{
return playlist_dir_fs;
}
AllocatedPath
map_spl_utf8_to_fs(const char *name)
map_spl_utf8_to_fs(const char *name) noexcept
{
if (playlist_dir_fs.IsNull())
return AllocatedPath::Null();

@@ -37,7 +37,7 @@ void
mapper_init(AllocatedPath &&playlist_dir);
void
mapper_finish();
mapper_finish() noexcept;
#ifdef ENABLE_DATABASE
@@ -48,7 +48,7 @@ mapper_finish();
*/
gcc_pure
AllocatedPath
map_uri_fs(const char *uri);
map_uri_fs(const char *uri) noexcept;
/**
* Maps a file system path (relative to the music directory or
@@ -60,7 +60,7 @@ map_uri_fs(const char *uri);
*/
gcc_pure
std::string
map_fs_to_utf8(Path path_fs);
map_fs_to_utf8(Path path_fs) noexcept;
#endif
@@ -69,7 +69,7 @@ map_fs_to_utf8(Path path_fs);
*/
gcc_const
const AllocatedPath &
map_spl_path();
map_spl_path() noexcept;
/**
* Maps a playlist name (without the ".m3u" suffix) to a file system
@@ -79,6 +79,6 @@ map_spl_path();
*/
gcc_pure
AllocatedPath
map_spl_utf8_to_fs(const char *name);
map_spl_utf8_to_fs(const char *name) noexcept;
#endif

@@ -31,45 +31,45 @@ class MixRampInfo {
public:
MixRampInfo() = default;
void Clear() {
void Clear() noexcept {
start.clear();
end.clear();
}
gcc_pure
bool IsDefined() const {
bool IsDefined() const noexcept {
return !start.empty() || !end.empty();
}
gcc_pure
const char *GetStart() const {
const char *GetStart() const noexcept {
return start.empty() ? nullptr : start.c_str();
}
gcc_pure
const char *GetEnd() const {
const char *GetEnd() const noexcept {
return end.empty() ? nullptr : end.c_str();
}
void SetStart(const char *new_value) {
void SetStart(const char *new_value) noexcept {
if (new_value == nullptr)
start.clear();
else
start = new_value;
}
void SetStart(std::string &&new_value) {
void SetStart(std::string &&new_value) noexcept {
start = std::move(new_value);
}
void SetEnd(const char *new_value) {
void SetEnd(const char *new_value) noexcept {
if (new_value == nullptr)
end.clear();
else
end = new_value;
}
void SetEnd(std::string &&new_value) {
void SetEnd(std::string &&new_value) noexcept {
end = std::move(new_value);
}
};

@@ -23,19 +23,19 @@
#include <assert.h>
MusicBuffer::MusicBuffer(unsigned num_chunks)
MusicBuffer::MusicBuffer(unsigned num_chunks) noexcept
:buffer(num_chunks) {
}
MusicChunk *
MusicBuffer::Allocate()
MusicBuffer::Allocate() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
return buffer.Allocate();
}
void
MusicBuffer::Return(MusicChunk *chunk)
MusicBuffer::Return(MusicChunk *chunk) noexcept
{
assert(chunk != nullptr);

@@ -41,7 +41,7 @@ public:
* @param num_chunks the number of #MusicChunk reserved in
* this buffer
*/
MusicBuffer(unsigned num_chunks);
MusicBuffer(unsigned num_chunks) noexcept;
#ifndef NDEBUG
/**
@@ -60,7 +60,7 @@ public:
* music_buffer_new().
*/
gcc_pure
unsigned GetSize() const {
unsigned GetSize() const noexcept {
return buffer.GetCapacity();
}
@@ -71,13 +71,13 @@ public:
* @return an empty chunk or nullptr if there are no chunks
* available
*/
MusicChunk *Allocate();
MusicChunk *Allocate() noexcept;
/**
* Returns a chunk to the buffer. It can be reused by
* Allocate() then.
*/
void Return(MusicChunk *chunk);
void Return(MusicChunk *chunk) noexcept;
};
#endif

@@ -31,7 +31,7 @@ MusicChunk::~MusicChunk()
#ifndef NDEBUG
bool
MusicChunk::CheckFormat(const AudioFormat other_format) const
MusicChunk::CheckFormat(const AudioFormat other_format) const noexcept
{
assert(other_format.IsValid());
@@ -41,7 +41,7 @@ MusicChunk::CheckFormat(const AudioFormat other_format) const
WritableBuffer<void>
MusicChunk::Write(const AudioFormat af,
SongTime data_time, uint16_t _bit_rate)
SongTime data_time, uint16_t _bit_rate) noexcept
{
assert(CheckFormat(af));
assert(length == 0 || audio_format.IsValid());
@@ -64,7 +64,7 @@ MusicChunk::Write(const AudioFormat af,
}
bool
MusicChunk::Expand(const AudioFormat af, size_t _length)
MusicChunk::Expand(const AudioFormat af, size_t _length) noexcept
{
const size_t frame_size = af.GetFrameSize();

@@ -79,12 +79,20 @@ struct MusicChunk {
*/
ReplayGainInfo replay_gain_info;
/**
* A magic value for #replay_gain_serial which omits updating
* the #ReplayGainFilter. This is used by "silence" chunks
* (see PlayerThread::SendSilence()) so they don't affect the
* replay gain.
*/
static constexpr unsigned IGNORE_REPLAY_GAIN = ~0u;
/**
* A serial number for checking if replay gain info has
* changed since the last chunk. The magic value 0 indicates
* that there is no replay gain info available.
*/
unsigned replay_gain_serial = 0;
unsigned replay_gain_serial;
/** the data (probably PCM) */
uint8_t data[CHUNK_SIZE];
@@ -111,7 +119,7 @@ struct MusicChunk {
* specified audio_format.
*/
gcc_pure
bool CheckFormat(AudioFormat audio_format) const;
bool CheckFormat(AudioFormat audio_format) const noexcept;
#endif
/**
@@ -127,7 +135,7 @@ struct MusicChunk {
*/
WritableBuffer<void> Write(AudioFormat af,
SongTime data_time,
uint16_t bit_rate);
uint16_t bit_rate) noexcept;
/**
* Increases the length of the chunk after the caller has written to
@@ -138,7 +146,7 @@ struct MusicChunk {
* @param length the number of bytes which were appended
* @return true if the chunk is full
*/
bool Expand(AudioFormat af, size_t length);
bool Expand(AudioFormat af, size_t length) noexcept;
};
#endif

@@ -25,7 +25,7 @@
#ifndef NDEBUG
bool
MusicPipe::Contains(const MusicChunk *chunk) const
MusicPipe::Contains(const MusicChunk *chunk) const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
@@ -39,7 +39,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const
#endif
MusicChunk *
MusicPipe::Shift()
MusicPipe::Shift() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
@@ -73,7 +73,7 @@ MusicPipe::Shift()
}
void
MusicPipe::Clear(MusicBuffer &buffer)
MusicPipe::Clear(MusicBuffer &buffer) noexcept
{
MusicChunk *chunk;
@@ -82,7 +82,7 @@ MusicPipe::Clear(MusicBuffer &buffer)
}
void
MusicPipe::Push(MusicChunk *chunk)
MusicPipe::Push(MusicChunk *chunk) noexcept
{
assert(!chunk->IsEmpty());
assert(chunk->length == 0 || chunk->audio_format.IsValid());

@@ -77,7 +77,7 @@ public:
* audio_format.
*/
gcc_pure
bool CheckFormat(AudioFormat other) const {
bool CheckFormat(AudioFormat other) const noexcept {
return !audio_format.IsDefined() ||
audio_format == other;
}
@@ -86,7 +86,7 @@ public:
* Checks if the specified chunk is enqueued in the music pipe.
*/
gcc_pure
bool Contains(const MusicChunk *chunk) const;
bool Contains(const MusicChunk *chunk) const noexcept;
#endif
/**
@@ -94,37 +94,39 @@ public:
* nullptr if the pipe is empty.
*/
gcc_pure
const MusicChunk *Peek() const {
const MusicChunk *Peek() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
return head;
}
/**
* 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.
*
* @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.
*/
void Push(MusicChunk *chunk);
void Push(MusicChunk *chunk) noexcept;
/**
* Returns the number of chunks currently in this pipe.
*/
gcc_pure
unsigned GetSize() const {
unsigned GetSize() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
return size;
}
gcc_pure
bool IsEmpty() const {
bool IsEmpty() const noexcept {
return GetSize() == 0;
}
};

@@ -141,9 +141,9 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
void
Partition::OnGlobalEvent(unsigned mask)
{
if ((mask & TAG_MODIFIED) != 0)
TagModified();
if ((mask & SYNC_WITH_PLAYER) != 0)
SyncWithPlayer();
if ((mask & TAG_MODIFIED) != 0)
TagModified();
}

@@ -200,7 +200,6 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
*/
const Database *GetDatabase() const;
gcc_pure
const Database &GetDatabaseOrThrow() const;
/**

@@ -49,7 +49,6 @@ static std::map<std::string, unsigned> permission_passwords;
static unsigned permission_default;
gcc_pure
static unsigned
ParsePermission(const char *p)
{

@@ -207,13 +207,12 @@ try {
continue;
#ifdef _UNICODE
wchar_t buffer[MAX_PATH];
auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
buffer, ARRAY_SIZE(buffer));
if (result <= 0)
/* on Windows, playlists always contain UTF-8, because
its "narrow" charset (i.e. CP_ACP) is incapable of
storing all Unicode paths */
const auto path = AllocatedPath::FromUTF8(s);
if (path.IsNull())
continue;
const Path path = Path::FromFS(buffer);
#else
const Path path = Path::FromFS(s);
#endif
@@ -335,7 +334,7 @@ try {
const auto path_fs = spl_map_to_fs(utf8path);
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)
throw PlaylistError(PlaylistResult::TOO_LARGE,

@@ -28,13 +28,25 @@
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
#include "fs/NarrowPath.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "util/UriUtil.hxx"
#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
playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
{
@@ -44,7 +56,7 @@ playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
try {
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 &) {
}
}
@@ -63,7 +75,7 @@ playlist_print_uri(BufferedOutputStream &os, const char *uri)
AllocatedPath::FromUTF8Throw(uri);
if (!path.IsNull())
os.Format("%s\n", NarrowPath(path).c_str());
playlist_print_path(os, path);
} catch (const std::runtime_error &) {
}
}

@@ -24,7 +24,7 @@
#include <math.h>
float
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const
ReplayGainTuple::CalculateScale(const ReplayGainConfig &config) const noexcept
{
float scale;

@@ -40,23 +40,23 @@ struct ReplayGainTuple {
}
gcc_pure
float CalculateScale(const ReplayGainConfig &config) const;
float CalculateScale(const ReplayGainConfig &config) const noexcept;
};
struct ReplayGainInfo {
ReplayGainTuple track, album;
constexpr bool IsDefined() const {
constexpr bool IsDefined() const noexcept {
return track.IsDefined() || album.IsDefined();
}
const ReplayGainTuple &Get(ReplayGainMode mode) const {
const ReplayGainTuple &Get(ReplayGainMode mode) const noexcept {
return mode == ReplayGainMode::ALBUM
? (album.IsDefined() ? album : track)
: (track.IsDefined() ? track : album);
}
void Clear() {
void Clear() noexcept {
track.Clear();
album.Clear();
}

@@ -25,7 +25,7 @@
#include <string.h>
const char *
ToString(ReplayGainMode mode)
ToString(ReplayGainMode mode) noexcept
{
switch (mode) {
case ReplayGainMode::AUTO:

@@ -36,13 +36,12 @@ enum class ReplayGainMode : uint8_t {
*/
gcc_pure
const char *
ToString(ReplayGainMode mode);
ToString(ReplayGainMode mode) noexcept;
/**
* Parse a string to a #ReplayGainMode. Throws std::runtime_error on
* error.
*/
gcc_pure
ReplayGainMode
FromString(const char *s);

@@ -24,9 +24,14 @@
#include "tag/Tag.hxx"
#include "util/ConstBuffer.hxx"
#include "util/StringAPI.hxx"
#include "util/StringCompare.hxx"
#include "util/StringView.hxx"
#include "util/ASCII.hxx"
#include "util/TimeParser.hxx"
#include "util/UriUtil.hxx"
#include "lib/icu/Collate.hxx"
#include "lib/icu/CaseFold.hxx"
#include <stdexcept>
#include <assert.h>
#include <stdlib.h>
@@ -36,7 +41,7 @@
#define LOCATE_TAG_ANY_KEY "any"
unsigned
locate_parse_type(const char *str)
locate_parse_type(const char *str) noexcept
{
if (StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY) ||
StringEqualsCaseASCII(str, LOCATE_TAG_FILE_KEY_OLD))
@@ -54,18 +59,10 @@ locate_parse_type(const char *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)
:tag(_tag), fold_case(_fold_case),
value(ImportString(_value, _fold_case))
:tag(_tag),
value(_value),
fold_case(_fold_case ? IcuCompare(value.c_str()) : IcuCompare())
{
}
@@ -75,7 +72,7 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
}
bool
SongFilter::Item::StringMatch(const char *s) const
SongFilter::Item::StringMatch(const char *s) const noexcept
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
@@ -85,23 +82,21 @@ SongFilter::Item::StringMatch(const char *s) const
assert(tag != LOCATE_TAG_MODIFIED_SINCE);
if (fold_case) {
const auto folded = IcuCaseFold(s);
assert(!folded.IsNull());
return StringFind(folded.c_str(), value.c_str()) != nullptr;
return fold_case.IsIn(s);
} else {
return StringIsEqual(s, value.c_str());
}
}
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) &&
StringMatch(item.value);
}
bool
SongFilter::Item::Match(const Tag &_tag) const
SongFilter::Item::Match(const Tag &_tag) const noexcept
{
bool visited_types[TAG_NUM_OF_ITEM_TYPES];
std::fill_n(visited_types, size_t(TAG_NUM_OF_ITEM_TYPES), false);
@@ -137,7 +132,7 @@ SongFilter::Item::Match(const Tag &_tag) const
}
bool
SongFilter::Item::Match(const DetachedSong &song) const
SongFilter::Item::Match(const DetachedSong &song) const noexcept
{
if (tag == LOCATE_TAG_BASE_TYPE)
return uri_is_child_or_same(value.c_str(), song.GetURI());
@@ -152,7 +147,7 @@ SongFilter::Item::Match(const DetachedSong &song) const
}
bool
SongFilter::Item::Match(const LightSong &song) const
SongFilter::Item::Match(const LightSong &song) const noexcept
{
if (tag == LOCATE_TAG_BASE_TYPE) {
const auto uri = song.GetURI();
@@ -180,27 +175,9 @@ SongFilter::~SongFilter()
/* this destructor exists here just so it won't get inlined */
}
#if !defined(__GLIBC__) && !defined(WIN32)
/**
* Determine the time zone offset in a portable way.
*/
gcc_const
static time_t
GetTimeZoneOffset()
{
time_t t = 1234567890;
struct tm tm;
tm.tm_isdst = 0;
gmtime_r(&t, &tm);
return t - mktime(&tm);
}
#endif
gcc_pure
static time_t
ParseTimeStamp(const char *s)
ParseTimeStamp(const char *s) noexcept
{
assert(s != nullptr);
@@ -210,26 +187,13 @@ ParseTimeStamp(const char *s)
/* it's an integral UNIX time stamp */
return (time_t)value;
#ifdef WIN32
/* TODO: emulate strptime()? */
return 0;
#else
/* try ISO 8601 */
struct tm tm;
const char *end = strptime(s, "%FT%TZ", &tm);
if (end == nullptr || *end != 0)
try {
/* try ISO 8601 */
const auto t = ParseTimePoint(s, "%FT%TZ");
return std::chrono::system_clock::to_time_t(t);
} catch (const std::runtime_error &) {
return 0;
#ifdef __GLIBC__
/* timegm() is a GNU extension */
return timegm(&tm);
#else
tm.tm_isdst = 0;
return mktime(&tm) + GetTimeZoneOffset();
#endif /* !__GLIBC__ */
#endif /* !WIN32 */
}
}
bool
@@ -274,7 +238,7 @@ SongFilter::Parse(ConstBuffer<const char *> args, bool fold_case)
}
bool
SongFilter::Match(const DetachedSong &song) const
SongFilter::Match(const DetachedSong &song) const noexcept
{
for (const auto &i : items)
if (!i.Match(song))
@@ -284,7 +248,7 @@ SongFilter::Match(const DetachedSong &song) const
}
bool
SongFilter::Match(const LightSong &song) const
SongFilter::Match(const LightSong &song) const noexcept
{
for (const auto &i : items)
if (!i.Match(song))
@@ -294,7 +258,7 @@ SongFilter::Match(const LightSong &song) const
}
bool
SongFilter::HasOtherThanBase() const
SongFilter::HasOtherThanBase() const noexcept
{
for (const auto &i : items)
if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
@@ -304,7 +268,7 @@ SongFilter::HasOtherThanBase() const
}
const char *
SongFilter::GetBase() const
SongFilter::GetBase() const noexcept
{
for (const auto &i : items)
if (i.GetTag() == LOCATE_TAG_BASE_TYPE)
@@ -312,3 +276,33 @@ SongFilter::GetBase() const
return nullptr;
}
SongFilter
SongFilter::WithoutBasePrefix(const char *_prefix) const noexcept
{
const StringView prefix(_prefix);
SongFilter result;
for (const auto &i : items) {
if (i.GetTag() == LOCATE_TAG_BASE_TYPE) {
const char *s = StringAfterPrefix(i.GetValue(), prefix);
if (s != nullptr) {
if (*s == 0)
continue;
if (*s == '/') {
++s;
if (*s != 0)
result.items.emplace_back(LOCATE_TAG_BASE_TYPE, s);
continue;
}
}
}
result.items.emplace_back(i);
}
return result;
}

@@ -20,9 +20,10 @@
#ifndef MPD_SONG_FILTER_HXX
#define MPD_SONG_FILTER_HXX
#include "util/AllocatedString.hxx"
#include "lib/icu/Compare.hxx"
#include "Compiler.h"
#include <string>
#include <list>
#include <stdint.h>
@@ -48,9 +49,12 @@ public:
class Item {
uint8_t tag;
bool fold_case;
std::string value;
AllocatedString<> value;
/**
* This value is only set if case folding is enabled.
*/
IcuCompare fold_case;
/**
* For #LOCATE_TAG_MODIFIED_SINCE
@@ -62,11 +66,6 @@ public:
Item(unsigned tag, const char *value, bool fold_case=false);
Item(unsigned tag, time_t time);
Item(const Item &other) = delete;
Item(Item &&) = default;
Item &operator=(const Item &other) = delete;
unsigned GetTag() const {
return tag;
}
@@ -80,19 +79,19 @@ public:
}
gcc_pure gcc_nonnull(2)
bool StringMatch(const char *s) const;
bool StringMatch(const char *s) const noexcept;
gcc_pure
bool Match(const TagItem &tag_item) const;
bool Match(const TagItem &tag_item) const noexcept;
gcc_pure
bool Match(const Tag &tag) const;
bool Match(const Tag &tag) const noexcept;
gcc_pure
bool Match(const DetachedSong &song) const;
bool Match(const DetachedSong &song) const noexcept;
gcc_pure
bool Match(const LightSong &song) const;
bool Match(const LightSong &song) const noexcept;
};
private:
@@ -112,20 +111,20 @@ public:
bool Parse(ConstBuffer<const char *> args, bool fold_case=false);
gcc_pure
bool Match(const Tag &tag) const;
bool Match(const Tag &tag) const noexcept;
gcc_pure
bool Match(const DetachedSong &song) const;
bool Match(const DetachedSong &song) const noexcept;
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;
}
gcc_pure
bool IsEmpty() const {
bool IsEmpty() const noexcept {
return items.empty();
}
@@ -133,7 +132,7 @@ public:
* Is there at least one item with "fold case" enabled?
*/
gcc_pure
bool HasFoldCase() const {
bool HasFoldCase() const noexcept {
for (const auto &i : items)
if (i.GetFoldCase())
return true;
@@ -145,14 +144,21 @@ public:
* Does this filter contain constraints other than "base"?
*/
gcc_pure
bool HasOtherThanBase() const;
bool HasOtherThanBase() const noexcept;
/**
* Returns the "base" specification (if there is one) or
* nullptr.
*/
gcc_pure
const char *GetBase() const;
const char *GetBase() const noexcept;
/**
* Create a copy of the filter with the given prefix stripped
* from all #LOCATE_TAG_BASE_TYPE items. This is used to
* filter songs in mounted databases.
*/
SongFilter WithoutBasePrefix(const char *prefix) const noexcept;
};
/**
@@ -160,6 +166,6 @@ public:
*/
gcc_pure
unsigned
locate_parse_type(const char *str);
locate_parse_type(const char *str) noexcept;
#endif

@@ -24,6 +24,7 @@
#include "fs/io/TextFile.hxx"
#include "fs/io/FileOutputStream.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "storage/StorageState.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "mixer/Volume.hxx"
@@ -50,21 +51,28 @@ StateFile::StateFile(AllocatedPath &&_path,
}
void
StateFile::RememberVersions()
StateFile::RememberVersions() noexcept
{
prev_volume_version = sw_volume_state_get_hash();
prev_output_version = audio_output_state_get_version();
prev_playlist_version = playlist_state_get_hash(partition.playlist,
partition.pc);
#ifdef ENABLE_DATABASE
prev_storage_version = storage_state_get_hash(partition.instance);
#endif
}
bool
StateFile::IsModified() const
StateFile::IsModified() const noexcept
{
return prev_volume_version != sw_volume_state_get_hash() ||
prev_output_version != audio_output_state_get_version() ||
prev_playlist_version != playlist_state_get_hash(partition.playlist,
partition.pc);
partition.pc)
#ifdef ENABLE_DATABASE
|| prev_storage_version != storage_state_get_hash(partition.instance)
#endif
;
}
inline void
@@ -72,6 +80,11 @@ StateFile::Write(BufferedOutputStream &os)
{
save_sw_volume_state(os);
audio_output_state_save(os, partition.outputs);
#ifdef ENABLE_DATABASE
storage_state_save(os, partition.instance);
#endif
playlist_state_save(os, partition.playlist, partition.pc);
}
@@ -123,6 +136,10 @@ try {
playlist_state_restore(line, file, song_loader,
partition.playlist,
partition.pc);
#ifdef ENABLE_DATABASE
success = success || storage_state_restore(line, file, partition.instance);
#endif
if (!success)
FormatError(state_file_domain,
"Unrecognized line in state file: %s",

@@ -46,6 +46,10 @@ class StateFile final : private TimeoutMonitor {
unsigned prev_volume_version = 0, prev_output_version = 0,
prev_playlist_version = 0;
#ifdef ENABLE_DATABASE
unsigned prev_storage_version = 0;
#endif
public:
static constexpr std::chrono::steady_clock::duration DEFAULT_INTERVAL = std::chrono::minutes(2);
@@ -67,14 +71,14 @@ private:
/**
* Save the current state versions for use with IsModified().
*/
void RememberVersions();
void RememberVersions() noexcept;
/**
* Check if MPD's state was modified since the last
* RememberVersions() call.
*/
gcc_pure
bool IsModified() const;
bool IsModified() const noexcept;
/* virtual methods from TimeoutMonitor */
void OnTimeout() override;

@@ -31,7 +31,7 @@
#include <chrono>
#ifndef WIN32
#ifndef _WIN32
/**
* The monotonic time stamp when MPD was started. It is used to
* calculate the uptime.
@@ -114,7 +114,7 @@ stats_print(Response &r, const Partition &partition)
{
r.Format("uptime: %u\n"
"playtime: %lu\n",
#ifdef WIN32
#ifdef _WIN32
GetProcessUptimeS(),
#else
(unsigned)std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start_time).count(),

@@ -40,7 +40,7 @@
gcc_pure
static bool
CheckDecoderPlugin(const DecoderPlugin &plugin,
const char *suffix, const char *mime)
const char *suffix, const char *mime) noexcept
{
return (mime != nullptr && plugin.SupportsMimeType(mime)) ||
(suffix != nullptr && plugin.SupportsSuffix(suffix));

@@ -24,7 +24,7 @@
void
time_print(Response &r, const char *name, time_t t)
{
#ifdef WIN32
#ifdef _WIN32
const struct tm *tm2 = gmtime(&t);
#else
struct tm tm;
@@ -35,7 +35,7 @@ time_print(Response &r, const char *name, time_t t)
char buffer[32];
strftime(buffer, sizeof(buffer),
#ifdef WIN32
#ifdef _WIN32
"%Y-%m-%dT%H:%M:%SZ",
#else
"%FT%TZ",

@@ -28,7 +28,7 @@
gcc_pure
static char *
FindSlash(char *p, size_t i)
FindSlash(char *p, size_t i) noexcept
{
for (; i > 0; --i)
if (p[i] == '/')
@@ -39,7 +39,7 @@ FindSlash(char *p, size_t i)
gcc_pure
static const char *
FindSuffix(const char *p, const char *i)
FindSuffix(const char *p, const char *i) noexcept
{
for (; i > p; --i) {
if (*i == '.')

@@ -93,7 +93,7 @@ public:
~Bzip2InputStream();
/* virtual methods from InputStream */
bool IsEOF() override;
bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override;
private:
@@ -162,7 +162,7 @@ Bzip2InputStream::FillBuffer()
if (bzstream.avail_in > 0)
return true;
size_t count = archive->istream->Read(buffer, sizeof(buffer));
size_t count = archive->istream->LockRead(buffer, sizeof(buffer));
if (count == 0)
return false;
@@ -174,6 +174,8 @@ Bzip2InputStream::FillBuffer()
size_t
Bzip2InputStream::Read(void *ptr, size_t length)
{
const ScopeUnlock unlock(mutex);
int bz_result;
size_t nbytes = 0;
@@ -205,7 +207,7 @@ Bzip2InputStream::Read(void *ptr, size_t length)
}
bool
Bzip2InputStream::IsEOF()
Bzip2InputStream::IsEOF() noexcept
{
return eof;
}
@@ -224,4 +226,3 @@ const ArchivePlugin bz2_archive_plugin = {
bz2_open,
bz2_extensions,
};

@@ -115,7 +115,12 @@ Iso9660ArchiveFile::Visit(char *path, size_t length, size_t capacity,
visitor.VisitArchiveEntry(path + 1);
}
}
#if LIBCDIO_VERSION_NUM >= 20000
iso9660_filelist_free(entlist);
#else
_cdio_list_free (entlist, true);
#endif
}
static ArchiveFile *
@@ -162,7 +167,7 @@ public:
}
/* virtual methods from InputStream */
bool IsEOF() override;
bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override;
};
@@ -182,6 +187,8 @@ Iso9660ArchiveFile::OpenStream(const char *pathname,
size_t
Iso9660InputStream::Read(void *ptr, size_t read_size)
{
const ScopeUnlock unlock(mutex);
int readed = 0;
int no_blocks, cur_block;
size_t left_bytes = statbuf->size - offset;
@@ -213,7 +220,7 @@ Iso9660InputStream::Read(void *ptr, size_t read_size)
}
bool
Iso9660InputStream::IsEOF()
Iso9660InputStream::IsEOF() noexcept
{
return offset == size;
}

@@ -116,7 +116,7 @@ struct ZzipInputStream final : public InputStream {
}
/* virtual methods from InputStream */
bool IsEOF() override;
bool IsEOF() noexcept override;
size_t Read(void *ptr, size_t size) override;
void Seek(offset_type offset) override;
};
@@ -138,6 +138,8 @@ ZzipArchiveFile::OpenStream(const char *pathname,
size_t
ZzipInputStream::Read(void *ptr, size_t read_size)
{
const ScopeUnlock unlock(mutex);
int ret = zzip_file_read(file, ptr, read_size);
if (ret < 0)
throw std::runtime_error("zzip_file_read() has failed");
@@ -147,7 +149,7 @@ ZzipInputStream::Read(void *ptr, size_t read_size)
}
bool
ZzipInputStream::IsEOF()
ZzipInputStream::IsEOF() noexcept
{
return offset_type(zzip_tell(file)) == size;
}
@@ -155,6 +157,8 @@ ZzipInputStream::IsEOF()
void
ZzipInputStream::Seek(offset_type new_offset)
{
const ScopeUnlock unlock(mutex);
zzip_off_t ofs = zzip_seek(file, new_offset, SEEK_SET);
if (ofs < 0)
throw std::runtime_error("zzip_seek() has failed");

@@ -28,7 +28,7 @@ const Domain client_domain("client");
#ifdef ENABLE_DATABASE
const Database *
Client::GetDatabase() const
Client::GetDatabase() const noexcept
{
return partition.instance.GetDatabase();
}
@@ -40,7 +40,7 @@ Client::GetDatabaseOrThrow() const
}
const Storage *
Client::GetStorage() const
Client::GetStorage() const noexcept
{
return partition.instance.storage;
}

@@ -100,7 +100,7 @@ public:
}
gcc_pure
bool IsExpired() const {
bool IsExpired() const noexcept {
return !FullyBufferedSocket::IsDefined();
}
@@ -160,7 +160,7 @@ public:
};
gcc_pure
bool IsSubscribed(const char *channel_name) const {
bool IsSubscribed(const char *channel_name) const noexcept {
return subscriptions.find(channel_name) != subscriptions.end();
}
@@ -186,16 +186,15 @@ public:
* Wrapper for Instance::GetDatabase().
*/
gcc_pure
const Database *GetDatabase() const;
const Database *GetDatabase() const noexcept;
/**
* Wrapper for Instance::GetDatabaseOrThrow().
*/
gcc_pure
const Database &GetDatabaseOrThrow() const;
gcc_pure
const Storage *GetStorage() const;
const Storage *GetStorage() const noexcept;
private:
/* virtual methods from class BufferedSocket */

@@ -28,7 +28,7 @@
void
Client::AllowFile(Path path_fs) const
{
#ifdef WIN32
#ifdef _WIN32
(void)path_fs;
throw ProtocolError(ACK_ERROR_PERMISSION, "Access denied");

@@ -23,14 +23,14 @@
gcc_const
static bool
valid_channel_char(const char ch)
valid_channel_char(const char ch) noexcept
{
return IsAlphaNumericASCII(ch) ||
ch == '_' || ch == '-' || ch == '.' || ch == ':';
}
bool
client_message_valid_channel_name(const char *name)
client_message_valid_channel_name(const char *name) noexcept
{
do {
if (!valid_channel_char(*name))

@@ -24,7 +24,7 @@
#include <string>
#ifdef WIN32
#ifdef _WIN32
/* fuck WIN32! */
#include <windows.h>
#undef GetMessage
@@ -53,6 +53,6 @@ public:
gcc_pure
bool
client_message_valid_channel_name(const char *name);
client_message_valid_channel_name(const char *name) noexcept;
#endif

@@ -29,7 +29,7 @@
#include "Log.hxx"
#include <assert.h>
#ifdef WIN32
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>

@@ -29,9 +29,32 @@
#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
static enum ack
ToAck(PlaylistResult result)
ToAck(PlaylistResult result) noexcept
{
switch (result) {
case PlaylistResult::SUCCESS:
@@ -67,7 +90,7 @@ ToAck(PlaylistResult result)
#ifdef ENABLE_DATABASE
gcc_const
static enum ack
ToAck(DatabaseErrorCode code)
ToAck(DatabaseErrorCode code) noexcept
{
switch (code) {
case DatabaseErrorCode::DISABLED:
@@ -84,7 +107,7 @@ ToAck(DatabaseErrorCode code)
gcc_pure
static enum ack
ToAck(std::exception_ptr ep)
ToAck(std::exception_ptr ep) noexcept
{
try {
std::rethrow_exception(ep);
@@ -100,13 +123,17 @@ ToAck(std::exception_ptr ep)
return ACK_ERROR_SYSTEM;
} catch (const std::invalid_argument &e) {
return ACK_ERROR_ARG;
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
} catch (const std::length_error &e) {
return ACK_ERROR_ARG;
} catch (const std::out_of_range &e) {
return ACK_ERROR_ARG;
#ifdef GLIBCXX_49X
} catch (const std::exception &e) {
#else
} catch (...) {
#endif
try {
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
#ifdef GLIBCXX_49X
/* workaround for g++ 4.x: no overload for
rethrow_exception(exception_ptr) */
std::rethrow_if_nested(e);

@@ -20,7 +20,7 @@
#ifndef MPD_COMMAND_RESULT_HXX
#define MPD_COMMAND_RESULT_HXX
#ifdef WIN32
#ifdef _WIN32
#include <windows.h>
/* damn you, windows.h! */
#ifdef ERROR

@@ -44,7 +44,7 @@
gcc_pure
static bool
SkipNameFS(PathTraitsFS::const_pointer_type name_fs)
SkipNameFS(PathTraitsFS::const_pointer_type name_fs) noexcept
{
return name_fs[0] == '.' &&
(name_fs[1] == 0 ||
@@ -53,12 +53,12 @@ SkipNameFS(PathTraitsFS::const_pointer_type name_fs)
gcc_pure
static bool
skip_path(Path name_fs)
skip_path(Path name_fs) noexcept
{
return name_fs.HasNewline();
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
/* PRIu64 causes bogus compiler warning */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
@@ -101,13 +101,13 @@ handle_listfiles_local(Response &r, Path path_fs)
return CommandResult::OK;
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif
gcc_pure
static bool
IsValidName(const char *p)
IsValidName(const char *p) noexcept
{
if (!IsAlphaASCII(*p))
return false;
@@ -123,7 +123,7 @@ IsValidName(const char *p)
gcc_pure
static bool
IsValidValue(const char *p)
IsValidValue(const char *p) noexcept
{
while (*p) {
const char ch = *p++;

@@ -30,7 +30,7 @@
#include <string>
bool
neighbor_commands_available(const Instance &instance)
neighbor_commands_available(const Instance &instance) noexcept
{
return instance.neighbors != nullptr;
}

@@ -30,7 +30,7 @@ class Response;
gcc_pure
bool
neighbor_commands_available(const Instance &instance);
neighbor_commands_available(const Instance &instance) noexcept;
CommandResult
handle_listneighbors(Client &client, Request request, Response &response);

@@ -30,6 +30,7 @@
#include "Instance.hxx"
#include "Idle.hxx"
#include "AudioFormat.hxx"
#include "util/StringBuffer.hxx"
#include "util/ScopeExit.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",
player_status.total_time.ToDoubleS());
if (player_status.audio_format.IsDefined()) {
struct audio_format_string af_string;
if (player_status.audio_format.IsDefined())
r.Format(COMMAND_STATUS_AUDIO ": %s\n",
audio_format_to_string(player_status.audio_format,
&af_string));
}
ToString(player_status.audio_format).c_str());
}
#ifdef ENABLE_DATABASE

@@ -39,7 +39,7 @@
#include "util/ConstBuffer.hxx"
bool
playlist_commands_available()
playlist_commands_available() noexcept
{
return !map_spl_path().IsNull();
}

@@ -29,7 +29,7 @@ class Response;
gcc_const
bool
playlist_commands_available();
playlist_commands_available() noexcept;
CommandResult
handle_save(Client &client, Request request, Response &response);

@@ -45,68 +45,57 @@ public:
: default_value;
}
gcc_pure
int ParseInt(unsigned idx) const {
assert(idx < size);
return ParseCommandArgInt(data[idx]);
}
gcc_pure
int ParseInt(unsigned idx, int min_value, int max_value) const {
assert(idx < size);
return ParseCommandArgInt(data[idx], min_value, max_value);
}
gcc_pure
int ParseUnsigned(unsigned idx) const {
assert(idx < size);
return ParseCommandArgUnsigned(data[idx]);
}
gcc_pure
int ParseUnsigned(unsigned idx, unsigned max_value) const {
assert(idx < size);
return ParseCommandArgUnsigned(data[idx], max_value);
}
gcc_pure
bool ParseBool(unsigned idx) const {
assert(idx < size);
return ParseCommandArgBool(data[idx]);
}
gcc_pure
RangeArg ParseRange(unsigned idx) const {
assert(idx < size);
return ParseCommandArgRange(data[idx]);
}
gcc_pure
float ParseFloat(unsigned idx) const {
assert(idx < size);
return ParseCommandArgFloat(data[idx]);
}
gcc_pure
SongTime ParseSongTime(unsigned idx) const {
assert(idx < size);
return ParseCommandArgSongTime(data[idx]);
}
gcc_pure
SignedSongTime ParseSignedSongTime(unsigned idx) const {
assert(idx < size);
return ParseCommandArgSignedSongTime(data[idx]);
}
gcc_pure
int ParseOptional(unsigned idx, int default_value) const {
return idx < size
? ParseInt(idx)
: default_value;
}
gcc_pure
RangeArg ParseOptional(unsigned idx, RangeArg default_value) const {
return idx < size
? ParseRange(idx)

@@ -45,12 +45,12 @@
gcc_pure
static bool
skip_path(const char *name_utf8)
skip_path(const char *name_utf8) noexcept
{
return strchr(name_utf8, '\n') != nullptr;
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
/* PRIu64 causes bogus compiler warning */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat"
@@ -94,7 +94,7 @@ handle_listfiles_storage(Response &r, StorageDirectoryReader &reader)
}
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
#if defined(_WIN32) && GCC_CHECK_VERSION(4,6)
#pragma GCC diagnostic pop
#endif

@@ -68,7 +68,7 @@ ConfigBlock::~ConfigBlock()
}
const BlockParam *
ConfigBlock::GetBlockParam(const char *name) const
ConfigBlock::GetBlockParam(const char *name) const noexcept
{
for (const auto &i : block_params) {
if (i.name == name) {
@@ -81,7 +81,8 @@ ConfigBlock::GetBlockParam(const char *name) const
}
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);
if (bp == nullptr)
@@ -128,7 +129,6 @@ ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
return bp->GetUnsignedValue();
}
gcc_pure
bool
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)
:name(_name), value(_value), line(_line), used(false) {}
gcc_pure
int GetIntValue() const;
gcc_pure
unsigned GetUnsignedValue() const;
gcc_pure
bool GetBoolValue() const;
};
@@ -85,12 +82,12 @@ struct ConfigBlock {
* object that was synthesized and not loaded from a
* configuration file.
*/
bool IsNull() const {
bool IsNull() const noexcept {
return line < 0;
}
gcc_pure
bool IsEmpty() const {
bool IsEmpty() const noexcept {
return block_params.empty();
}
@@ -101,11 +98,11 @@ struct ConfigBlock {
}
gcc_nonnull_all gcc_pure
const BlockParam *GetBlockParam(const char *_name) const;
const BlockParam *GetBlockParam(const char *_name) const noexcept;
gcc_pure
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
@@ -116,13 +113,10 @@ struct ConfigBlock {
AllocatedPath GetPath(const char *name,
const char *default_value=nullptr) const;
gcc_pure
int GetBlockValue(const char *name, int default_value) const;
gcc_pure
unsigned GetBlockValue(const char *name, unsigned default_value) const;
gcc_pure
bool GetBlockValue(const char *name, bool default_value) const;
};

@@ -75,7 +75,7 @@ void config_global_check(void)
}
const ConfigParam *
config_get_param(ConfigOption option)
config_get_param(ConfigOption option) noexcept
{
auto *param = config_data.params[unsigned(option)];
if (param != nullptr)
@@ -84,7 +84,7 @@ config_get_param(ConfigOption option)
}
const ConfigBlock *
config_get_block(ConfigBlockOption option)
config_get_block(ConfigBlockOption option) noexcept
{
ConfigBlock *block = config_data.blocks[unsigned(option)];
if (block != nullptr)
@@ -110,7 +110,7 @@ config_find_block(ConfigBlockOption option, const char *key, const char *value)
}
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);

@@ -48,11 +48,11 @@ ReadConfigFile(Path path);
gcc_pure
const ConfigParam *
config_get_param(enum ConfigOption option);
config_get_param(enum ConfigOption option) noexcept;
gcc_pure
const ConfigBlock *
config_get_block(enum ConfigBlockOption option);
config_get_block(enum ConfigBlockOption option) noexcept;
/**
* Find a block with a matching attribute.
@@ -61,20 +61,12 @@ config_get_block(enum ConfigBlockOption option);
* @param key the attribute name
* @param value the expected attribute value
*/
gcc_pure
const ConfigBlock *
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 *
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
@@ -86,11 +78,9 @@ config_get_string(enum ConfigOption option, const char *default_value=nullptr);
AllocatedPath
config_get_path(enum ConfigOption option);
gcc_pure
unsigned
config_get_unsigned(enum ConfigOption option, unsigned default_value);
gcc_pure
static inline std::chrono::steady_clock::duration
config_get_unsigned(ConfigOption option,
std::chrono::steady_clock::duration default_value)
@@ -100,11 +90,9 @@ config_get_unsigned(ConfigOption option,
return std::chrono::steady_clock::duration(u);
}
gcc_pure
unsigned
config_get_positive(enum ConfigOption option, unsigned default_value);
gcc_pure
static inline std::chrono::steady_clock::duration
config_get_positive(ConfigOption option,
std::chrono::steady_clock::duration default_value)
@@ -114,7 +102,6 @@ config_get_positive(ConfigOption option,
return std::chrono::steady_clock::duration(u);
}
gcc_pure
bool config_get_bool(enum ConfigOption option, bool default_value);
#endif

@@ -22,7 +22,7 @@
#include "Compiler.h"
#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
#if defined(_WIN32) && CLANG_OR_GCC_VERSION(4,7)
/* "INPUT" is declared by winuser.h */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
@@ -93,7 +93,7 @@ enum class ConfigBlockOption {
MAX
};
#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
#if defined(_WIN32) && CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic pop
#endif
@@ -102,13 +102,13 @@ enum class ConfigBlockOption {
*/
gcc_pure
enum ConfigOption
ParseConfigOptionName(const char *name);
ParseConfigOptionName(const char *name) noexcept;
/**
* @return #ConfigOption::MAX if not found
*/
gcc_pure
enum ConfigBlockOption
ParseConfigBlockOptionName(const char *name);
ParseConfigBlockOptionName(const char *name) noexcept;
#endif

@@ -29,7 +29,7 @@
#include <assert.h>
#include <string.h>
#ifndef WIN32
#ifndef _WIN32
#include <pwd.h>
/**
@@ -79,7 +79,7 @@ ParsePath(const char *path)
{
assert(path != nullptr);
#ifndef WIN32
#ifndef _WIN32
if (path[0] == '~') {
++path;
@@ -119,7 +119,7 @@ ParsePath(const char *path)
} else {
#endif
return AllocatedPath::FromUTF8Throw(path);
#ifndef WIN32
#ifndef _WIN32
}
#endif
}

@@ -101,7 +101,7 @@ static_assert(n_config_block_templates == unsigned(ConfigBlockOption::MAX),
gcc_pure
static inline unsigned
ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
const char *name)
const char *name) noexcept
{
unsigned i = 0;
for (; i < count; ++i)
@@ -112,7 +112,7 @@ ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
}
ConfigOption
ParseConfigOptionName(const char *name)
ParseConfigOptionName(const char *name) noexcept
{
return ConfigOption(ParseConfigTemplateName(config_param_templates,
n_config_param_templates,
@@ -120,7 +120,7 @@ ParseConfigOptionName(const char *name)
}
ConfigBlockOption
ParseConfigBlockOptionName(const char *name)
ParseConfigBlockOptionName(const char *name) noexcept
{
return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
n_config_block_templates,

@@ -71,7 +71,6 @@ struct ConfigParam {
*
* Throws #std::runtime_error on error.
*/
gcc_pure
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.n_songs++;
@@ -70,8 +70,6 @@ stats_visitor_song(SearchStats &stats, const LightSong &song)
const auto duration = song.GetDuration();
if (!duration.IsNegative())
stats.total_duration += duration;
return true;
}
static bool
@@ -94,7 +92,7 @@ CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
return found;
}
static bool
static void
GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
{
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)
/* fall back to "Artist" if no "AlbumArtist" was found */
CollectGroupCounts(map, TAG_ARTIST, tag);
return true;
}
void

@@ -37,5 +37,10 @@ DatabaseGlobalInit(EventLoop &loop, DatabaseListener &listener,
throw FormatRuntimeError("No such database plugin: %s",
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
static inline bool
holding_db_lock(void)
holding_db_lock() noexcept
{
return db_mutex_holder.IsInside();
}

@@ -27,13 +27,12 @@
#include <functional>
static bool
static void
AddSong(const Storage &storage, const char *playlist_path_utf8,
const LightSong &song)
{
spl_append_song(playlist_path_utf8,
DatabaseDetachSong(storage, song));
return true;
}
void

@@ -49,16 +49,14 @@ PrintDirectoryURI(Response &r, bool base, const LightDirectory &directory)
ApplyBaseFlag(directory.GetPath(), base));
}
static bool
static void
PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
{
if (!directory.IsRoot())
PrintDirectoryURI(r, base, directory);
return true;
}
static bool
static void
PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
{
if (!directory.IsRoot()) {
@@ -67,8 +65,6 @@ PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
if (directory.mtime > 0)
time_print(r, "Last-Modified", directory.mtime);
}
return true;
}
static void
@@ -96,7 +92,7 @@ print_playlist_in_directory(Response &r, bool base,
directory->GetPath(), name_utf8);
}
static bool
static void
PrintSongBrief(Response &r, Partition &partition,
bool base, const LightSong &song)
{
@@ -106,11 +102,9 @@ PrintSongBrief(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base,
song.directory, song.uri);
return true;
}
static bool
static void
PrintSongFull(Response &r, Partition &partition,
bool base, const LightSong &song)
{
@@ -120,21 +114,18 @@ PrintSongFull(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base,
song.directory, song.uri);
return true;
}
static bool
static void
PrintPlaylistBrief(Response &r, bool base,
const PlaylistInfo &playlist,
const LightDirectory &directory)
{
print_playlist_in_directory(r, base,
&directory, playlist.name.c_str());
return true;
}
static bool
static void
PrintPlaylistFull(Response &r, bool base,
const PlaylistInfo &playlist,
const LightDirectory &directory)
@@ -144,8 +135,6 @@ PrintPlaylistFull(Response &r, bool base,
if (playlist.mtime > 0)
time_print(r, "Last-Modified", playlist.mtime);
return true;
}
void
@@ -191,15 +180,13 @@ db_selection_print(Response &r, Partition &partition,
0, std::numeric_limits<int>::max());
}
static bool
static void
PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
{
song_print_uri(r, partition, song);
return true;
}
static bool
static void
PrintUniqueTag(Response &r, TagType tag_type,
const Tag &tag)
{
@@ -211,8 +198,6 @@ PrintUniqueTag(Response &r, TagType tag_type,
if (item.type != tag_type)
r.Format("%s: %s\n",
tag_item_names[item.type], item.value);
return true;
}
void

@@ -27,14 +27,13 @@
#include <functional>
static bool
static void
AddToQueue(Partition &partition, const LightSong &song)
{
const Storage &storage = *partition.instance.storage;
partition.playlist.AppendSong(partition.pc,
DatabaseDetachSong(storage,
song));
return true;
}
void

@@ -31,7 +31,6 @@ class DetachedSong;
* "Detach" the #Song object, i.e. convert it to a #DetachedSong
* instance.
*/
gcc_pure
DetachedSong
DatabaseDetachSong(const Storage &storage, const LightSong &song);

@@ -29,7 +29,7 @@
struct StringLess {
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;
}
};
@@ -67,15 +67,13 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
}
}
static bool
static void
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
const LightSong &song)
{
++stats.song_count;
StatsVisitTag(stats, artists, albums, *song.tag);
return true;
}
DatabaseStats

@@ -106,7 +106,6 @@ public:
TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag) const = 0;
gcc_pure
virtual DatabaseStats GetStats(const DatabaseSelection &selection) const = 0;
/**
@@ -127,7 +126,7 @@ public:
* Returns 0 if that is not not known/available.
*/
gcc_pure
virtual time_t GetUpdateStamp() const = 0;
virtual time_t GetUpdateStamp() const noexcept = 0;
};
#endif

Some files were not shown because too many files have changed in this diff Show More