Compare commits
250 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
323231d1dd | ||
![]() |
714011c81e | ||
![]() |
952ff4207b | ||
![]() |
150b16ec2c | ||
![]() |
c98bc4a243 | ||
![]() |
014f8cd693 | ||
![]() |
aea37e46e3 | ||
![]() |
31ab78ae8e | ||
![]() |
f82e1453e4 | ||
![]() |
a2b77c8813 | ||
![]() |
18add29472 | ||
![]() |
b111a8fe8d | ||
![]() |
3b23cf0258 | ||
![]() |
28e864e096 | ||
![]() |
1de19b921a | ||
![]() |
ff162b5a03 | ||
![]() |
d8e4705dd4 | ||
![]() |
338e1f5926 | ||
![]() |
a7fdfa08e1 | ||
![]() |
9703a401c5 | ||
![]() |
753a2aa462 | ||
![]() |
10990a0684 | ||
![]() |
91254e9211 | ||
![]() |
0f79287b04 | ||
![]() |
f2fac77d8c | ||
![]() |
81b7373637 | ||
![]() |
fa67c2548a | ||
![]() |
ea80587ddb | ||
![]() |
828f5f8384 | ||
![]() |
1295a1272a | ||
![]() |
66646d9276 | ||
![]() |
d0497dba92 | ||
![]() |
42914e8227 | ||
![]() |
59b49b7881 | ||
![]() |
5620f16330 | ||
![]() |
be024d4ad7 | ||
![]() |
75c740fe2b | ||
![]() |
6c8d86bb90 | ||
![]() |
b253a6b71e | ||
![]() |
ca7b4df812 | ||
![]() |
bc8dd57236 | ||
![]() |
f4f461b8bb | ||
![]() |
cbb9b6957f | ||
![]() |
f6b56c9317 | ||
![]() |
3717fb6c8d | ||
![]() |
f6abbc01bd | ||
![]() |
57a71c157d | ||
![]() |
cc76aeb7bb | ||
![]() |
811cabf8a9 | ||
![]() |
bf8d2f93d2 | ||
![]() |
07d8259ad6 | ||
![]() |
a00d412008 | ||
![]() |
5fb39658f1 | ||
![]() |
b0703b92c3 | ||
![]() |
dd9fd3d8a7 | ||
![]() |
cf0c59864f | ||
![]() |
4c0404c70d | ||
![]() |
573a413ee1 | ||
![]() |
f633e6ca49 | ||
![]() |
07b06d76be | ||
![]() |
856fe2da15 | ||
![]() |
f82aae65cd | ||
![]() |
3fbd11a104 | ||
![]() |
58a99f1907 | ||
![]() |
cf86dfd317 | ||
![]() |
a057b4f6d8 | ||
![]() |
62b03cfddf | ||
![]() |
18b827b979 | ||
![]() |
0a379fc514 | ||
![]() |
445c11b8d9 | ||
![]() |
8d290ad509 | ||
![]() |
b90c48b50f | ||
![]() |
d19e7db09e | ||
![]() |
9939904b02 | ||
![]() |
ca23b15f5c | ||
![]() |
ffa676f577 | ||
![]() |
6d023c4df3 | ||
![]() |
b31bd37a30 | ||
![]() |
78faee8c7c | ||
![]() |
40e2a703d0 | ||
![]() |
b01edcb9bc | ||
![]() |
f7fffc9be8 | ||
![]() |
50e8634097 | ||
![]() |
e3994e517e | ||
![]() |
2bb7785189 | ||
![]() |
90c8408111 | ||
![]() |
64786ec12a | ||
![]() |
b3c82f8886 | ||
![]() |
063259dc52 | ||
![]() |
b4c9d9c2a7 | ||
![]() |
fa2b59df4b | ||
![]() |
f41a169460 | ||
![]() |
f567083006 | ||
![]() |
a2a677e539 | ||
![]() |
9123c0b733 | ||
![]() |
788e3b31e1 | ||
![]() |
71f0ed8b74 | ||
![]() |
ac2e4e593d | ||
![]() |
edaa7d7748 | ||
![]() |
3cdf965fba | ||
![]() |
6b60d1e71f | ||
![]() |
7b7fb5acd5 | ||
![]() |
0a7d612f41 | ||
![]() |
38da76bbe0 | ||
![]() |
a13e045742 | ||
![]() |
811620c0a0 | ||
![]() |
504f5f7bdd | ||
![]() |
32bcad51b8 | ||
![]() |
a40510c241 | ||
![]() |
ac8dce6599 | ||
![]() |
190d525099 | ||
![]() |
1b6666fa39 | ||
![]() |
1dd01c99e8 | ||
![]() |
d50b30a498 | ||
![]() |
42a3a87f13 | ||
![]() |
9dfedbe619 | ||
![]() |
88957b4c9d | ||
![]() |
b2f2c9322b | ||
![]() |
3be2051808 | ||
![]() |
ff32b0dc9b | ||
![]() |
c1869a11af | ||
![]() |
e22a4fdba4 | ||
![]() |
29a7b2c5b5 | ||
![]() |
3b6c285c2a | ||
![]() |
575d1786af | ||
![]() |
bc1c927952 | ||
![]() |
f95bc85f91 | ||
![]() |
4015195314 | ||
![]() |
c3d883c6cb | ||
![]() |
097e30321b | ||
![]() |
b6ddeaacf2 | ||
![]() |
b0c60ec124 | ||
![]() |
f3b788703e | ||
![]() |
4bb83781e8 | ||
![]() |
a73195b7cc | ||
![]() |
1bd00b8a9a | ||
![]() |
d84eaeafc5 | ||
![]() |
20ae84bff9 | ||
![]() |
7372c931b3 | ||
![]() |
29e1b6e465 | ||
![]() |
eda06993f8 | ||
![]() |
4b30ef1cf2 | ||
![]() |
e92e5e8eb8 | ||
![]() |
4e5271fcdf | ||
![]() |
3c55487a16 | ||
![]() |
76a1cae5d8 | ||
![]() |
81a97315e3 | ||
![]() |
53c14d97a6 | ||
![]() |
69a82eec17 | ||
![]() |
45cadef22f | ||
![]() |
0a033fb10a | ||
![]() |
591afa0647 | ||
![]() |
05eac20ffe | ||
![]() |
38d263ac19 | ||
![]() |
f71c204eef | ||
![]() |
51147203be | ||
![]() |
a931686317 | ||
![]() |
5bd322bdcf | ||
![]() |
bb097109f0 | ||
![]() |
2ab6c40ff1 | ||
![]() |
68bb738af2 | ||
![]() |
6b968beede | ||
![]() |
f68dd1bffb | ||
![]() |
f92b71ca99 | ||
![]() |
2b79fe2d6a | ||
![]() |
44dd9af276 | ||
![]() |
d3013d4f8c | ||
![]() |
678524ad21 | ||
![]() |
32a64481f2 | ||
![]() |
1776015c6c | ||
![]() |
f1c71a26e3 | ||
![]() |
e78ab767d3 | ||
![]() |
f01eb2f95d | ||
![]() |
1450e45d97 | ||
![]() |
ec8cba369c | ||
![]() |
f4c248f406 | ||
![]() |
f3b2a58646 | ||
![]() |
c6f89c42b2 | ||
![]() |
5e93cfdd9e | ||
![]() |
d91d5a3ab5 | ||
![]() |
907c045f33 | ||
![]() |
90f189eb54 | ||
![]() |
4abd5b2112 | ||
![]() |
df9a665994 | ||
![]() |
7a098ca0ed | ||
![]() |
33716732a1 | ||
![]() |
97ae594375 | ||
![]() |
3f321ae9a0 | ||
![]() |
161d32a7e7 | ||
![]() |
d7137586a9 | ||
![]() |
cd0c06ba6e | ||
![]() |
899ab63d91 | ||
![]() |
1097820a5a | ||
![]() |
39114f91a7 | ||
![]() |
4f01387edf | ||
![]() |
de3e0585f1 | ||
![]() |
f85f25ba82 | ||
![]() |
10a2c179f9 | ||
![]() |
6eea56861b | ||
![]() |
21fd2064ae | ||
![]() |
dcbab8e37a | ||
![]() |
5677278251 | ||
![]() |
a83bee993d | ||
![]() |
96a31f554a | ||
![]() |
d14ec6aea5 | ||
![]() |
917cedf893 | ||
![]() |
193dd71600 | ||
![]() |
6c293a3d7f | ||
![]() |
e847ddf011 | ||
![]() |
7e8b448985 | ||
![]() |
d1f3a87c08 | ||
![]() |
9f8145e590 | ||
![]() |
791efc171a | ||
![]() |
144312a525 | ||
![]() |
92684112ed | ||
![]() |
ef114ee6cb | ||
![]() |
667f209742 | ||
![]() |
4ad0747c78 | ||
![]() |
c5cf66402c | ||
![]() |
05417049eb | ||
![]() |
c7b0c46d9f | ||
![]() |
df578c91ad | ||
![]() |
70008c47c9 | ||
![]() |
938affef32 | ||
![]() |
a3c33000ee | ||
![]() |
1e54b7b294 | ||
![]() |
cc0dbcf3f4 | ||
![]() |
c5a2cadccc | ||
![]() |
9aa43416b6 | ||
![]() |
8364029db8 | ||
![]() |
d842d21be0 | ||
![]() |
3514fd2433 | ||
![]() |
6778ff27ea | ||
![]() |
f32315d699 | ||
![]() |
8b754b24b6 | ||
![]() |
b1bee9ff38 | ||
![]() |
569be2d402 | ||
![]() |
78a73eac53 | ||
![]() |
533cb99c33 | ||
![]() |
79726940dc | ||
![]() |
27c7891169 | ||
![]() |
7a3a793a12 | ||
![]() |
8088469eca | ||
![]() |
3dcb082015 | ||
![]() |
bece023028 | ||
![]() |
9c4df66925 | ||
![]() |
2b43ceb6c6 | ||
![]() |
c143adba91 | ||
![]() |
142fdc8d86 | ||
![]() |
67778dcd3d |
.travis.ymlAUTHORSINSTALLMakefile.amNEWSREADME.md
android
configure.acdoc
m4
python/build
src
AudioFormat.cxxAudioFormat.hxxAudioParser.cxxAudioParser.hxxCommandLine.cxxDetachedSong.cxxDetachedSong.hxxIOThread.cxxIOThread.hxxIdleFlags.cxxIdleFlags.hxxInstance.hxxMain.cxxMapper.cxxMapper.hxxMixRampInfo.hxxMusicBuffer.cxxMusicBuffer.hxxMusicChunk.cxxMusicChunk.hxxMusicPipe.cxxMusicPipe.hxxPartition.cxxPartition.hxxPermission.cxxPlaylistFile.cxxPlaylistSave.cxxReplayGainInfo.cxxReplayGainInfo.hxxReplayGainMode.cxxReplayGainMode.hxxSongFilter.cxxSongFilter.hxxStateFile.cxxStateFile.hxxTagStream.cxxls.cxxls.hxx
archive
client
command
CommandError.cxxFileCommands.cxxNeighborCommands.cxxNeighborCommands.hxxPlayerCommands.cxxPlaylistCommands.cxxPlaylistCommands.hxxRequest.hxxStorageCommands.cxx
config
db
Count.cxxDatabaseGlue.cxxDatabaseLock.hxxDatabasePlaylist.cxxDatabasePrint.cxxDatabaseQueue.cxxDatabaseSong.hxxHelpers.cxxInterface.hxxLightDirectory.hxxLightSong.cxxLightSong.hxxPlaylistInfo.hxxPlaylistVector.cxxPlaylistVector.hxxRegistry.cxxRegistry.hxxSelection.cxxSelection.hxx
plugins
ProxyDatabasePlugin.cxx
simple
Directory.cxxDirectory.hxxDirectorySave.cxxMount.cxxSimpleDatabasePlugin.hxxSong.cxxSong.hxxSongSort.cxxSongSort.hxx
upnp
update
decoder
Bridge.cxxBridge.hxxClient.hxxDecoderBuffer.hxxDecoderControl.cxxDecoderControl.hxxDecoderList.cxxDecoderList.hxxDecoderPlugin.cxxDecoderPlugin.hxxDecoderThread.cxx
plugins
AudiofileDecoderPlugin.cxxDsdLib.cxxDsdLib.hxxFfmpegDecoderPlugin.cxxFfmpegMetaData.cxxFlacMetadata.cxxFlacMetadata.hxxGmeDecoderPlugin.cxxMadDecoderPlugin.cxxMpcdecDecoderPlugin.cxxOpusDecoderPlugin.cxxOpusTags.cxxPcmDecoderPlugin.cxxSidplayDecoderPlugin.cxxSndfileDecoderPlugin.cxxVorbisDecoderPlugin.cxxWavpackDecoderPlugin.cxx
encoder
plugins
event
filter
fs
AllocatedPath.cxxAllocatedPath.hxxCharset.cxxCharset.hxxGlob.hxxPath.cxxPath.hxxPath2.cxxStandardDirectory.cxxStandardDirectory.hxxTraits.cxxTraits.hxx
io
input
AsyncInputStream.cxxAsyncInputStream.hxxInputStream.cxxInputStream.hxxProxyInputStream.cxxProxyInputStream.hxxThreadInputStream.cxxThreadInputStream.hxx
plugins
java
lib
curl
Easy.hxxGlobal.cxxGlobal.hxxHandler.hxxMulti.hxxRequest.cxxRequest.hxxSlist.hxxVersion.cxxVersion.hxx
expat
ffmpeg
icu
nfs
Base.cxxBase.hxxCallback.hxxCancellable.hxxConnection.cxxConnection.hxxFileReader.hxxGlue.cxxGlue.hxxManager.cxxManager.hxx
upnp
mixer
neighbor
net
AllocatedSocketAddress.cxxAllocatedSocketAddress.hxxSocketAddress.cxxSocketAddress.hxxSocketError.cxxSocketError.hxxStaticSocketAddress.cxxStaticSocketAddress.hxxToString.cxxToString.hxx
output
Init.cxxInternal.cxxInternal.hxxMultipleOutputs.cxxMultipleOutputs.hxxOutputPlugin.cxxOutputPlugin.hxxOutputThread.cxxSharedPipeConsumer.cxxSharedPipeConsumer.hxxSource.cxxSource.hxxWrapper.hxx
plugins
pcm
ChannelsConverter.cxxChannelsConverter.hxxDsd16.cxxDsd16.hxxDsd32.cxxDsd32.hxxFloatConvert.hxxFormatConverter.cxxFormatConverter.hxxGlueResampler.cxxGlueResampler.hxxLibsamplerateResampler.cxxLibsamplerateResampler.hxxOrder.hxxPcmBuffer.hxxPcmChannels.cxxPcmConvert.cxxPcmConvert.hxxPcmDop.cxxPcmDsd.cxxPcmDsd.hxxPcmExport.cxxPcmExport.hxxPcmFormat.cxxPcmFormat.hxxPcmMix.cxxPcmMix.hxxPcmUtils.hxxResampler.hxxSampleFormat.cxxSampleFormat.hxxSilence.cxxSoxrResampler.cxxTraits.hxxVolume.cxxVolume.hxx
player
playlist
protocol
queue
sticker
storage
CompositeStorage.cxxCompositeStorage.hxxConfigured.cxxConfigured.hxxFileInfo.hxxRegistry.cxxRegistry.hxxStorageInterface.cxxStorageInterface.hxx
plugins
system
tag
Aiff.cxxFormat.cxxFormat.hxxId3Load.cxxId3MusicBrainz.cxxId3MusicBrainz.hxxMixRamp.cxxReplayGain.cxxSet.cxxSet.hxxSettings.hxxTag.cxxTag.hxxTagBuilder.cxxTagBuilder.hxxTagHandler.cxxTagId3.cxxTagString.cxxTagTable.cxxTagTable.hxxVorbisComment.cxxVorbisComment.hxx
thread
Cond.hxxCriticalSection.hxxId.hxxMutex.hxxPosixCond.hxxPosixMutex.hxxThread.hxxUtil.cxxUtil.hxxWindowsCond.hxx
unix
util
ASCII.hxxAllocatedArray.hxxAllocatedString.cxxAllocatedString.hxxBindMethod.hxxCast.hxxCharUtil.hxxCircularBuffer.hxxClamp.hxxConstBuffer.hxxDeleteDisposer.hxxDomain.hxxDynamicFifoBuffer.hxxException.cxxException.hxxForeignFifoBuffer.hxxFormatString.cxxHugeAllocator.cxxHugeAllocator.hxxIterableSplitString.hxxMacros.hxxManual.hxxNumberParser.hxxPeakBuffer.cxxPeakBuffer.hxxReusableArray.hxxRuntimeError.hxxScopeExit.hxxSplitString.cxxSplitString.hxxStaticFifoBuffer.hxxStringAPI.hxxStringBuffer.hxxStringCompare.cxxStringCompare.hxxStringPointer.hxxStringUtil.cxxStringUtil.hxxStringView.cxxStringView.hxxTextFile.hxxTimeParser.cxxTimeParser.hxxTokenizer.cxxTokenizer.hxxUTF8.cxxUTF8.hxxUriUtil.cxxUriUtil.hxxVarSize.hxxWStringAPI.hxxWStringCompare.cxxWStringCompare.hxxWritableBuffer.hxx
test
FakeDecoderAPI.cxxFakeDecoderAPI.hxxTestAudioFormat.cxxTestAudioFormat.hxxdump_rva2.cxxread_mixer.cxxread_tags.cxxrun_filter.cxxrun_output.cxxtest_byte_reverse.cxxtest_pcm_all.hxxtest_pcm_channels.cxxtest_pcm_dither.cxxtest_pcm_export.cxxtest_pcm_format.cxxtest_pcm_main.cxxtest_pcm_pack.cxxtest_protocol.cxxtest_rewind.cxxtest_translate_song.cxx
win32
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
dist: trusty
|
||||
language: cpp
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libcppunit-dev
|
||||
- libboost-dev
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
global:
|
||||
- MAKEFLAGS="-j2"
|
||||
|
||||
before_install:
|
||||
# C++14
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get update -qq
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || brew update
|
||||
|
||||
install:
|
||||
# C++14
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || sudo apt-get install -qq g++-5
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || brew install cppunit
|
||||
|
||||
script:
|
||||
- OPTIONS="--enable-test"
|
||||
- test "$TRAVIS_OS_NAME" != "linux" || export CC=gcc-5 CXX=g++-5
|
||||
- test "$TRAVIS_OS_NAME" != "osx" || OPTIONS="$OPTIONS --enable-osx"
|
||||
- ./autogen.sh
|
||||
- ./configure --disable-silent-rules --disable-dependency-tracking $OPTIONS
|
||||
- make
|
||||
- make check
|
3
AUTHORS
3
AUTHORS
@@ -5,7 +5,7 @@ The following people have contributed code to MPD:
|
||||
|
||||
Warren Dukes <warren.dukes@gmail.com>
|
||||
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
206
INSTALL
@@ -1,206 +0,0 @@
|
||||
Music Player Daemon (MPD) - INSTALL
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This document is a very small amount of documentation about what is needed to
|
||||
install MPD. If more information is desired, read the user manual:
|
||||
|
||||
http://www.musicpd.org/doc/user/
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
gcc 4.7 or later - http://gcc.gnu.org/
|
||||
clang 3.2 or later - http://clang.llvm.org/
|
||||
Any other C++11 compliant compiler should also work.
|
||||
|
||||
Boost 1.46 - http://www.boost.org/
|
||||
|
||||
|
||||
Optional Output Dependencies
|
||||
----------------------------
|
||||
|
||||
You will need at least one of these to compile MPD.
|
||||
|
||||
Most of these are available as packages on major distributions. Be sure to
|
||||
install both the library package as well as the development package.
|
||||
|
||||
AO - http://www.xiph.org/ao/
|
||||
A portable library that abstracts many audio output types as one API. Should
|
||||
be used only if there is no native plugin available or if the native plugin
|
||||
doesn't work. You will need libao.
|
||||
|
||||
ALSA - http://www.alsa-project.org/
|
||||
The Advanced Linux Sound Architecture. Recommended audio output if you use
|
||||
Linux. You will need libasound.
|
||||
|
||||
FIFO
|
||||
This is a mostly undocumented, developer plugin to transmit raw data.
|
||||
|
||||
OSS - http://www.opensound.com
|
||||
Open Sound System.
|
||||
|
||||
PulseAudio - http://www.pulseaudio.org/
|
||||
An advanced sound daemon. You will need libpulse.
|
||||
|
||||
JACK - http://www.jackaudio.org/
|
||||
A low-latency sound daemon.
|
||||
|
||||
libshout - http://www.icecast.org/
|
||||
For streaming to an Icecast or Shoutcast server.
|
||||
You also need an encoder: either libvorbisenc (ogg), or liblame (mp3).
|
||||
|
||||
OpenAL - http://kcat.strangesoft.net/openal.html
|
||||
Open Audio Library
|
||||
|
||||
|
||||
Optional Input Dependencies
|
||||
---------------------------
|
||||
|
||||
You will need at least one of these to compile MPD.
|
||||
|
||||
Most of these are available as packages on major distributions. Be sure to
|
||||
install both the library package as well as the development package.
|
||||
|
||||
MAD - http://www.underbit.com/products/mad/
|
||||
For MP3 support. You will need libmad, and optionally libid3tag if you want
|
||||
ID3 tag support.
|
||||
|
||||
libmpg123 - http://www.mpg123.de/
|
||||
Alternative for MP3 support.
|
||||
|
||||
Ogg Vorbis - http://www.xiph.org/ogg/vorbis/
|
||||
For Ogg Vorbis support. You will need libogg and libvorbis.
|
||||
|
||||
libopus - http://www.opus-codec.org/
|
||||
Opus codec support
|
||||
|
||||
FLAC - http://flac.sourceforge.net/
|
||||
For FLAC support. You will need version 1.2 or higher of libFLAC.
|
||||
|
||||
Audio File - http://www.68k.org/~michael/audiofile/
|
||||
For WAVE, AIFF, and AU support. You will need libaudiofile.
|
||||
|
||||
FAAD2 - http://www.audiocoding.com/
|
||||
For MP4/AAC support.
|
||||
|
||||
libmpcdec - http://www.musepack.net/
|
||||
For Musepack support.
|
||||
|
||||
MikMod - http://mikmod.raphnet.net/
|
||||
For MOD support. You will need libmikmod.
|
||||
|
||||
libavcodec, libavformat (ffmpeg or libav) - http://ffmpeg.mplayerhq.hu/ http://libav.org/
|
||||
Multi-codec library.
|
||||
|
||||
libsidplay2 - http://sidplay2.sourceforge.net/
|
||||
For C64 SID support.
|
||||
|
||||
libfluidsynth - http://fluidsynth.resonance.org/
|
||||
For MIDI support.
|
||||
|
||||
libwildmidi 0.2.3 - http://wildmidi.sourceforge.net/
|
||||
For MIDI support.
|
||||
|
||||
libsndfile - http://www.mega-nerd.com/libsndfile/
|
||||
WAVE, AIFF, and many others.
|
||||
|
||||
libwavpack - http://www.wavpack.com/
|
||||
For WavPack playback.
|
||||
|
||||
libadplug - http://adplug.sourceforge.net/
|
||||
For AdLib playback.
|
||||
|
||||
|
||||
Optional Miscellaneous Dependencies
|
||||
-----------------------------------
|
||||
|
||||
Avahi - http://www.avahi.org/
|
||||
For Zeroconf support.
|
||||
|
||||
libsamplerate - http://www.mega-nerd.com/SRC/
|
||||
For advanced samplerate conversions.
|
||||
|
||||
libcurl - http://curl.haxx.se/
|
||||
For playing HTTP streams.
|
||||
|
||||
libmms - https://launchpad.net/libmms
|
||||
For playing MMS streams.
|
||||
|
||||
SQLite - http://www.sqlite.org/
|
||||
For the sticker database.
|
||||
|
||||
libcdio - http://www.gnu.org/software/libcdio/
|
||||
For playing audio CDs.
|
||||
|
||||
libsystemd-daemon - http://freedesktop.org/wiki/Software/systemd/
|
||||
For systemd activation.
|
||||
|
||||
|
||||
pkg-config
|
||||
----------
|
||||
|
||||
MPD uses pkg-config to locate most external libraries. If you do not
|
||||
have pkg-config, or if your version of the library does not ship the
|
||||
".pc" file, you have to provide the library's build options in
|
||||
environment variables. These variables are documented in "./configure
|
||||
--help". Example:
|
||||
|
||||
FLAC_CFLAGS=-I/usr/include/FLAC FLAC_LIBS=-lFLAC ./configure
|
||||
|
||||
|
||||
Download
|
||||
--------
|
||||
|
||||
Get the latest release from of MPD from <http://www.musicpd.org/>.
|
||||
|
||||
Compile
|
||||
-------
|
||||
|
||||
1) unpack the archive
|
||||
|
||||
$ tar xf mpd-x.x.x.tar.xz
|
||||
|
||||
2) change to directory created
|
||||
|
||||
$ cd mpd-x.x.x
|
||||
|
||||
3) Run configure script (this will determine what dependencies you have)
|
||||
|
||||
$ ./configure
|
||||
|
||||
4) Compile
|
||||
|
||||
$ make
|
||||
|
||||
Install (Optional)
|
||||
-------
|
||||
|
||||
(as root)
|
||||
$ make install
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
1) run mpd:
|
||||
|
||||
$ mpd <config file>
|
||||
|
||||
First default is $XDG_CONFIG_HOME/mpd/mpd.conf then ~/.mpdconf then
|
||||
~/.mpd/mpd.conf then /etc/mpd.conf. If neither of these exist a mpd
|
||||
configuration file must be specified at runtime.
|
||||
|
||||
A sample config file is included with the source of MPD, mpdconf.example.
|
||||
|
||||
The first time MPD is run it will attempt to discover all music in your
|
||||
music root, recursively. This can be affected by the symbolic link
|
||||
options specified in the example mpd.conf.
|
||||
|
||||
Using MPD
|
||||
---------
|
||||
|
||||
You can download many different interfaces for MPD at
|
||||
|
||||
http://www.musicpd.org/clients/
|
20
Makefile.am
20
Makefile.am
@@ -243,6 +243,7 @@ CURL_SOURCES = \
|
||||
src/lib/curl/Slist.hxx
|
||||
|
||||
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 \
|
||||
@@ -415,6 +416,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 \
|
||||
@@ -517,6 +519,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
|
||||
|
||||
@@ -539,6 +543,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 \
|
||||
@@ -575,6 +583,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
|
||||
@@ -613,7 +623,8 @@ libxiph_a_SOURCES += \
|
||||
src/lib/xiph/OggStreamState.hxx
|
||||
endif
|
||||
|
||||
XIPH_LIBS = libxiph.a
|
||||
XIPH_LIBS = libxiph.a \
|
||||
$(OGG_LIBS)
|
||||
|
||||
endif
|
||||
|
||||
@@ -869,9 +880,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
|
||||
@@ -918,6 +926,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
|
||||
@@ -1484,6 +1493,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 += \
|
||||
@@ -2225,6 +2236,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 \
|
||||
|
116
NEWS
116
NEWS
@@ -1,3 +1,119 @@
|
||||
ver 0.20.12 (2017/11/25)
|
||||
* database
|
||||
- upnp: adapt to libupnp 1.8 API changes
|
||||
* input
|
||||
- cdio_paranoia, ffmpeg, file, smbclient: reduce lock contention,
|
||||
fixing lots of xrun problems
|
||||
- curl: fix seeking
|
||||
* decoder
|
||||
- ffmpeg: fix GCC 8 warning
|
||||
- vorbis: fix Tremor support
|
||||
* player
|
||||
- log message when decoder is too slow
|
||||
* encoder
|
||||
- vorbis: default to quality 3
|
||||
* output
|
||||
- fix hanging playback with soxr resampler
|
||||
- httpd: flush encoder after tag; fixes corrupt Vorbis stream
|
||||
|
||||
ver 0.20.11 (2017/10/18)
|
||||
* storage
|
||||
- curl: support Content-Type application/xml
|
||||
* decoder
|
||||
- ffmpeg: more reliable song duration
|
||||
- gme: fix track numbering
|
||||
* improve random song order when switching songs manually
|
||||
* fix case insensitive search without libicu
|
||||
* fix Unicode file names in playlists on Windows
|
||||
* fix endless loop when accessing malformed file names in ZIP files
|
||||
|
||||
ver 0.20.10 (2017/08/24)
|
||||
* decoder
|
||||
- ffmpeg: support MusicBrainz ID3v2 tags
|
||||
* tags
|
||||
- aiff: fix FORM chunk size endianess (is big-endian)
|
||||
* mixer
|
||||
- osx: add a mixer for OSX.
|
||||
* fix crash when resuming playback before decoder is ready
|
||||
* fix crash on Windows
|
||||
|
||||
ver 0.20.9 (2017/06/04)
|
||||
* decoder
|
||||
- ffmpeg: support *.adx
|
||||
* fix byte order detection on FreeBSD/aarch64
|
||||
* fix more random crashes when compiled with clang
|
||||
|
||||
ver 0.20.8 (2017/05/19)
|
||||
* output
|
||||
- osx: fix build failure due to missing "noexcept"
|
||||
* playlist
|
||||
- m3u: support MIME type `audio/mpegurl`
|
||||
* fix build failure with GCC 4.x
|
||||
|
||||
ver 0.20.7 (2017/05/15)
|
||||
* database
|
||||
- simple: fix false positive directory loop detection with NFS
|
||||
* enforce a reasonable minimum audio_buffer_size setting
|
||||
* cap buffer_before_play at 80% to prevent deadlock
|
||||
* fix random crashes when compiled with clang
|
||||
|
||||
ver 0.20.6 (2017/03/10)
|
||||
* input
|
||||
- curl: fix headers after HTTP redirect to Shoutcast server
|
||||
* decoder
|
||||
- ffmpeg: re-enable as fallback
|
||||
- mpcdec: fix crash (division by zero) after seeking
|
||||
- sidplay: make compatible with libsidplayfp < 1.8
|
||||
* fix stream tags after automatic song change
|
||||
* workaround for GCC 4.9.4 / libstdc++ bug (build failure)
|
||||
|
||||
ver 0.20.5 (2017/02/20)
|
||||
* tags
|
||||
- id3: fix memory leak on corrupt ID3 tags
|
||||
* decoder
|
||||
- sidplay: don't require libsidutils when building with libsidplayfp
|
||||
* output
|
||||
- httpd: fix two buffer overflows in IcyMetaData length calculation
|
||||
* mixer
|
||||
- alsa: fix crash bug
|
||||
|
||||
ver 0.20.4 (2017/02/01)
|
||||
* input
|
||||
- nfs: fix freeze after reconnect
|
||||
* output
|
||||
- sndio: work around a libroar C++ incompatibility
|
||||
* workaround for GCC 4.9 "constexpr" bug
|
||||
* fix FreeBSD build failure
|
||||
|
||||
ver 0.20.3 (2017/01/25)
|
||||
* protocol
|
||||
- "playlistadd" creates new playlist if it does not exist, as documented
|
||||
* database
|
||||
- proxy: fix error "terminate called after throwing ..."
|
||||
- proxy: make connect errors during startup non-fatal
|
||||
* neighbor
|
||||
- upnp: fix premature expiry
|
||||
* replay gain: don't reset ReplayGain levels when unpausing playback
|
||||
* silence surround channels when converting from stereo
|
||||
* use shortcuts such as "dsd64" in log messages
|
||||
|
||||
ver 0.20.2 (2017/01/15)
|
||||
* input
|
||||
- alsa: fix crash bug
|
||||
- alsa: fix buffer overruns
|
||||
* decoder
|
||||
- flac: add options "probesize" and "analyzeduration"
|
||||
* resampler
|
||||
- libsamplerate: reset state after seeking
|
||||
* output
|
||||
- fix static noise after changing to a different audio format
|
||||
- alsa: fix the DSD_U32 sample rate
|
||||
- alsa: fix the DSD_U32 byte order
|
||||
- alsa: support DSD_U16
|
||||
- recorder: fix error "Failed to create : No such file or directory"
|
||||
* playlist
|
||||
- cue: fix skipping songs
|
||||
|
||||
ver 0.20.1 (2017/01/09)
|
||||
* input
|
||||
- curl: fix crash bug
|
||||
|
@@ -7,14 +7,15 @@ server's audio device. The daemon stores info about all available music,
|
||||
and this info can be easily searched and retrieved. Player control, info
|
||||
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
|
||||
|
||||
|
@@ -87,9 +87,14 @@ class AndroidNdkToolchain:
|
||||
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_cppflags = '-nostdinc++ -isystem ' + os.path.join(libcxx_path, 'include') + ' -isystem ' + os.path.join(ndk_path, 'sources/android/support/include')
|
||||
libstdcxx_ldadd = os.path.join(libcxx_libs_path, 'libc++_static.a') + ' ' + os.path.join(libcxx_libs_path, 'libc++abi.a')
|
||||
|
||||
if self.is_armv7:
|
||||
libstdcxx_ldadd += ' ' + os.path.join(libcxx_libs_path, 'libunwind.a')
|
||||
|
||||
if use_cxx:
|
||||
self.libs += ' ' + libstdcxx_ldadd
|
||||
@@ -149,5 +154,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)
|
||||
|
12
configure.ac
12
configure.ac
@@ -1,10 +1,10 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.20.1, musicpd-dev-team@lists.sourceforge.net)
|
||||
AC_INIT(mpd, 0.20.12, musicpd-dev-team@lists.sourceforge.net)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=20
|
||||
VERSION_REVISION=1
|
||||
VERSION_REVISION=12
|
||||
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)
|
||||
@@ -992,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
|
||||
@@ -1384,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
|
||||
|
||||
|
@@ -97,20 +97,20 @@ Foo(const char *abc, int xyz)
|
||||
|
||||
<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
|
||||
@@ -188,17 +188,7 @@ 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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There is <ulink url="https://github.com/MaxKellermann/MPD">a
|
||||
mirror of the <application>MPD</application> git repository on
|
||||
GitHub</ulink>, and you can use that as well to submit pull
|
||||
requests.
|
||||
<command>git pull</command> requests are preferred.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
|
@@ -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>
|
||||
|
||||
|
@@ -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>
|
||||
|
481
doc/user.xml
481
doc/user.xml
@@ -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>
|
||||
@@ -1970,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.
|
||||
@@ -2006,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>
|
||||
@@ -2099,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>
|
||||
|
||||
@@ -2155,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>
|
||||
@@ -2186,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>
|
||||
|
||||
@@ -2195,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>
|
||||
|
||||
@@ -2203,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">
|
||||
@@ -2213,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>
|
||||
|
||||
@@ -2333,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>
|
||||
|
||||
@@ -2413,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>
|
||||
|
||||
@@ -2422,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>
|
||||
|
||||
@@ -2442,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>
|
||||
@@ -2499,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>
|
||||
|
||||
@@ -2508,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>
|
||||
|
||||
@@ -2518,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>
|
||||
|
||||
@@ -2713,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>
|
||||
|
||||
@@ -2736,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>
|
||||
@@ -3342,7 +3674,7 @@ run</programlisting>
|
||||
</informaltable>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section id="jack_output">
|
||||
<title><varname>jack</varname></title>
|
||||
|
||||
<para>
|
||||
@@ -3622,7 +3954,7 @@ run</programlisting>
|
||||
</informaltable>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section id="openal_output">
|
||||
<title><varname>openal</varname></title>
|
||||
|
||||
<para>
|
||||
@@ -3773,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>
|
||||
@@ -3930,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>
|
||||
@@ -3961,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>
|
||||
@@ -4151,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>
|
||||
|
||||
@@ -4175,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>
|
||||
|
||||
@@ -4183,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])
|
||||
|
29
python/build/cmdline.py
Normal file
29
python/build/cmdline.py
Normal file
@@ -0,0 +1,29 @@
|
||||
def concatenate_cmdline_variables(src, names):
|
||||
"""Find duplicate variable declarations on the given source list, and
|
||||
concatenate the values of those in the 'names' list."""
|
||||
|
||||
# the result list being constructed
|
||||
dest = []
|
||||
|
||||
# a map of variable name to destination list index
|
||||
positions = {}
|
||||
|
||||
for item in src:
|
||||
i = item.find('=')
|
||||
if i > 0:
|
||||
# it's a variable
|
||||
name = item[:i]
|
||||
if name in names:
|
||||
# it's a known variable
|
||||
if name in positions:
|
||||
# already specified: concatenate instead of
|
||||
# appending it
|
||||
dest[positions[name]] += ' ' + item[i + 1:]
|
||||
continue
|
||||
else:
|
||||
# not yet seen: append it and remember the list
|
||||
# index
|
||||
positions[name] = len(dest)
|
||||
dest.append(item)
|
||||
|
||||
return dest
|
@@ -19,8 +19,8 @@ libvorbis = AutotoolsProject(
|
||||
)
|
||||
|
||||
opus = AutotoolsProject(
|
||||
'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'],
|
||||
)
|
||||
@@ -36,8 +36,8 @@ flac = AutotoolsProject(
|
||||
)
|
||||
|
||||
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',
|
||||
)
|
||||
|
||||
@@ -57,9 +57,20 @@ libmad = AutotoolsProject(
|
||||
autogen=True,
|
||||
)
|
||||
|
||||
liblame = AutotoolsProject(
|
||||
'http://downloads.sourceforge.net/project/lame/lame/3.99/lame-3.99.5.tar.gz',
|
||||
'24346b4158e4af3bd9f2e194bb23eb473c75fb7377011523353196b19b9a23ff',
|
||||
'lib/libmp3lame.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-gtktest', '--disable-analyzer-hooks',
|
||||
'--disable-decoder', '--disable-frontend',
|
||||
],
|
||||
)
|
||||
|
||||
ffmpeg = FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz',
|
||||
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc',
|
||||
'http://ffmpeg.org/releases/ffmpeg-3.3.3.tar.xz',
|
||||
'd2a9002cdc6b533b59728827186c044ad02ba64841f1b7cd6c21779875453a1e',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -82,8 +93,8 @@ ffmpeg = FfmpegProject(
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.52.1.tar.lzma',
|
||||
'44286d4b825936e2430fc44ad730ce899afb736a5d328cbb8b5d42462f3f2365',
|
||||
'http://curl.haxx.se/download/curl-7.55.1.tar.xz',
|
||||
'3eafca6e84ecb4af5f35795dee84e643d5428287e88c041122bb8dac18676bb7',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -103,7 +114,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.65.0/boost_1_65_0.tar.bz2',
|
||||
'ea26712742e2fb079c2a566a31f3266973b76e38222b9f88b387e3c8b2f9902c',
|
||||
'include/boost/version.hpp',
|
||||
)
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -96,7 +96,7 @@ io_thread_deinit(void)
|
||||
}
|
||||
|
||||
EventLoop &
|
||||
io_thread_get()
|
||||
io_thread_get() noexcept
|
||||
{
|
||||
assert(io.loop != nullptr);
|
||||
|
||||
@@ -104,7 +104,7 @@ io_thread_get()
|
||||
}
|
||||
|
||||
bool
|
||||
io_thread_inside(void)
|
||||
io_thread_inside() noexcept
|
||||
{
|
||||
return io.thread.IsInside();
|
||||
}
|
||||
|
@@ -51,13 +51,13 @@ io_thread_deinit();
|
||||
|
||||
gcc_const
|
||||
EventLoop &
|
||||
io_thread_get();
|
||||
io_thread_get() noexcept;
|
||||
|
||||
/**
|
||||
* Is the current thread the I/O thread?
|
||||
*/
|
||||
gcc_pure
|
||||
bool
|
||||
io_thread_inside();
|
||||
io_thread_inside() noexcept;
|
||||
|
||||
#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
|
||||
|
||||
|
47
src/Main.cxx
47
src/Main.cxx
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -111,7 +111,7 @@ struct MusicChunk {
|
||||
* specified audio_format.
|
||||
*/
|
||||
gcc_pure
|
||||
bool CheckFormat(AudioFormat audio_format) const;
|
||||
bool CheckFormat(AudioFormat audio_format) const noexcept;
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -127,7 +127,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 +138,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,37 @@ public:
|
||||
* nullptr if the pipe is empty.
|
||||
*/
|
||||
gcc_pure
|
||||
const MusicChunk *Peek() const {
|
||||
const MusicChunk *Peek() const noexcept {
|
||||
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 {
|
||||
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);
|
||||
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/TimeParser.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "lib/icu/Collate.hxx"
|
||||
#include "lib/icu/CaseFold.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -39,7 +39,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))
|
||||
@@ -57,18 +57,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(AllocatedString<>::Duplicate(_value)),
|
||||
fold_case(_fold_case ? IcuCompare(value.c_str()) : IcuCompare())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -78,7 +70,7 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
|
||||
}
|
||||
|
||||
bool
|
||||
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 */
|
||||
@@ -88,23 +80,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);
|
||||
@@ -140,7 +130,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());
|
||||
@@ -155,7 +145,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();
|
||||
@@ -185,7 +175,7 @@ SongFilter::~SongFilter()
|
||||
|
||||
gcc_pure
|
||||
static time_t
|
||||
ParseTimeStamp(const char *s)
|
||||
ParseTimeStamp(const char *s) noexcept
|
||||
{
|
||||
assert(s != nullptr);
|
||||
|
||||
@@ -246,7 +236,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))
|
||||
@@ -256,7 +246,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))
|
||||
@@ -266,7 +256,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)
|
||||
@@ -276,7 +266,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)
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#ifndef MPD_SONG_FILTER_HXX
|
||||
#define MPD_SONG_FILTER_HXX
|
||||
|
||||
#include "lib/icu/Compare.hxx"
|
||||
#include "util/AllocatedString.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
@@ -48,10 +49,13 @@ public:
|
||||
class Item {
|
||||
uint8_t tag;
|
||||
|
||||
bool fold_case;
|
||||
|
||||
AllocatedString<> value;
|
||||
|
||||
/**
|
||||
* This value is only set if case folding is enabled.
|
||||
*/
|
||||
IcuCompare fold_case;
|
||||
|
||||
/**
|
||||
* For #LOCATE_TAG_MODIFIED_SINCE
|
||||
*/
|
||||
@@ -80,19 +84,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 +116,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 +137,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 +149,14 @@ 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;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -160,6 +164,6 @@ public:
|
||||
*/
|
||||
gcc_pure
|
||||
unsigned
|
||||
locate_parse_type(const char *str);
|
||||
locate_parse_type(const char *str) noexcept;
|
||||
|
||||
#endif
|
||||
|
@@ -50,7 +50,7 @@ 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();
|
||||
@@ -59,7 +59,7 @@ StateFile::RememberVersions()
|
||||
}
|
||||
|
||||
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() ||
|
||||
|
@@ -67,14 +67,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;
|
||||
|
@@ -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));
|
||||
|
@@ -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:
|
||||
@@ -205,7 +205,7 @@ Bzip2InputStream::Read(void *ptr, size_t length)
|
||||
}
|
||||
|
||||
bool
|
||||
Bzip2InputStream::IsEOF()
|
||||
Bzip2InputStream::IsEOF() noexcept
|
||||
{
|
||||
return eof;
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ public:
|
||||
}
|
||||
|
||||
/* virtual methods from InputStream */
|
||||
bool IsEOF() override;
|
||||
bool IsEOF() noexcept override;
|
||||
size_t Read(void *ptr, size_t size) override;
|
||||
};
|
||||
|
||||
@@ -213,7 +213,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;
|
||||
};
|
||||
@@ -147,7 +147,7 @@ ZzipInputStream::Read(void *ptr, size_t read_size)
|
||||
}
|
||||
|
||||
bool
|
||||
ZzipInputStream::IsEOF()
|
||||
ZzipInputStream::IsEOF() noexcept
|
||||
{
|
||||
return offset_type(zzip_tell(file)) == size;
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
@@ -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))
|
||||
|
@@ -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,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,13 @@ ToAck(std::exception_ptr ep)
|
||||
return ACK_ERROR_SYSTEM;
|
||||
} catch (const std::invalid_argument &e) {
|
||||
return ACK_ERROR_ARG;
|
||||
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20151204
|
||||
#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);
|
||||
|
@@ -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,7 +53,7 @@ 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();
|
||||
}
|
||||
@@ -107,7 +107,7 @@ handle_listfiles_local(Response &r, Path path_fs)
|
||||
|
||||
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,7 +45,7 @@
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
skip_path(const char *name_utf8)
|
||||
skip_path(const char *name_utf8) noexcept
|
||||
{
|
||||
return strchr(name_utf8, '\n') != nullptr;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -44,16 +44,16 @@ struct LightDirectory {
|
||||
constexpr LightDirectory(const char *_uri, time_t _mtime)
|
||||
:uri(_uri), mtime(_mtime) {}
|
||||
|
||||
static constexpr LightDirectory Root() {
|
||||
static constexpr LightDirectory Root() noexcept {
|
||||
return LightDirectory("", 0);
|
||||
}
|
||||
|
||||
bool IsRoot() const {
|
||||
bool IsRoot() const noexcept {
|
||||
return *uri == 0;
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
const char *GetPath() const {
|
||||
const char *GetPath() const noexcept {
|
||||
return uri;
|
||||
}
|
||||
};
|
||||
|
@@ -21,7 +21,7 @@
|
||||
#include "tag/Tag.hxx"
|
||||
|
||||
SignedSongTime
|
||||
LightSong::GetDuration() const
|
||||
LightSong::GetDuration() const noexcept
|
||||
{
|
||||
SongTime a = start_time, b = end_time;
|
||||
if (!b.IsPositive()) {
|
||||
|
@@ -76,7 +76,7 @@ struct LightSong {
|
||||
SongTime end_time;
|
||||
|
||||
gcc_pure
|
||||
std::string GetURI() const {
|
||||
std::string GetURI() const noexcept {
|
||||
if (directory == nullptr)
|
||||
return std::string(uri);
|
||||
|
||||
@@ -87,7 +87,7 @@ struct LightSong {
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
SignedSongTime GetDuration() const;
|
||||
SignedSongTime GetDuration() const noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -45,7 +45,7 @@ struct PlaylistInfo {
|
||||
constexpr CompareName(const char *_name):name(_name) {}
|
||||
|
||||
gcc_pure
|
||||
bool operator()(const PlaylistInfo &pi) const {
|
||||
bool operator()(const PlaylistInfo &pi) const noexcept {
|
||||
return pi.name.compare(name) == 0;
|
||||
}
|
||||
};
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#include <assert.h>
|
||||
|
||||
PlaylistVector::iterator
|
||||
PlaylistVector::find(const char *name)
|
||||
PlaylistVector::find(const char *name) noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
assert(name != nullptr);
|
||||
|
@@ -31,7 +31,7 @@ protected:
|
||||
* Caller must lock the #db_mutex.
|
||||
*/
|
||||
gcc_pure
|
||||
iterator find(const char *name);
|
||||
iterator find(const char *name) noexcept;
|
||||
|
||||
public:
|
||||
using std::list<PlaylistInfo>::empty;
|
||||
|
@@ -38,7 +38,7 @@ const DatabasePlugin *const database_plugins[] = {
|
||||
};
|
||||
|
||||
const DatabasePlugin *
|
||||
GetDatabasePluginByName(const char *name)
|
||||
GetDatabasePluginByName(const char *name) noexcept
|
||||
{
|
||||
for (auto i = database_plugins; *i != nullptr; ++i)
|
||||
if (strcmp((*i)->name, name) == 0)
|
||||
|
@@ -32,6 +32,6 @@ extern const DatabasePlugin *const database_plugins[];
|
||||
|
||||
gcc_pure
|
||||
const DatabasePlugin *
|
||||
GetDatabasePluginByName(const char *name);
|
||||
GetDatabasePluginByName(const char *name) noexcept;
|
||||
|
||||
#endif
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "Selection.hxx"
|
||||
#include "SongFilter.hxx"
|
||||
|
||||
@@ -34,19 +35,19 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
|
||||
}
|
||||
|
||||
bool
|
||||
DatabaseSelection::IsEmpty() const
|
||||
DatabaseSelection::IsEmpty() const noexcept
|
||||
{
|
||||
return uri.empty() && (filter == nullptr || filter->IsEmpty());
|
||||
}
|
||||
|
||||
bool
|
||||
DatabaseSelection::HasOtherThanBase() const
|
||||
DatabaseSelection::HasOtherThanBase() const noexcept
|
||||
{
|
||||
return filter != nullptr && filter->HasOtherThanBase();
|
||||
}
|
||||
|
||||
bool
|
||||
DatabaseSelection::Match(const LightSong &song) const
|
||||
DatabaseSelection::Match(const LightSong &song) const noexcept
|
||||
{
|
||||
return filter == nullptr || filter->Match(song);
|
||||
}
|
||||
|
@@ -45,16 +45,16 @@ struct DatabaseSelection {
|
||||
const SongFilter *_filter=nullptr);
|
||||
|
||||
gcc_pure
|
||||
bool IsEmpty() const;
|
||||
bool IsEmpty() const noexcept;
|
||||
|
||||
/**
|
||||
* Does this selection contain constraints other than "base"?
|
||||
*/
|
||||
gcc_pure
|
||||
bool HasOtherThanBase() const;
|
||||
bool HasOtherThanBase() const noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool Match(const LightSong &song) const;
|
||||
bool Match(const LightSong &song) const noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -34,6 +34,7 @@
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "protocol/Ack.hxx"
|
||||
#include "event/SocketMonitor.hxx"
|
||||
#include "event/IdleMonitor.hxx"
|
||||
@@ -46,7 +47,7 @@
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
class LibmpdclientError final : std::runtime_error {
|
||||
class LibmpdclientError final : public std::runtime_error {
|
||||
enum mpd_error code;
|
||||
|
||||
public:
|
||||
@@ -108,8 +109,8 @@ public:
|
||||
static Database *Create(EventLoop &loop, DatabaseListener &listener,
|
||||
const ConfigBlock &block);
|
||||
|
||||
virtual void Open() override;
|
||||
virtual void Close() override;
|
||||
void Open() override;
|
||||
void Close() override;
|
||||
const LightSong *GetSong(const char *uri_utf8) const override;
|
||||
void ReturnSong(const LightSong *song) const override;
|
||||
|
||||
@@ -126,7 +127,7 @@ public:
|
||||
|
||||
unsigned Update(const char *uri_utf8, bool discard) override;
|
||||
|
||||
virtual time_t GetUpdateStamp() const override {
|
||||
time_t GetUpdateStamp() const noexcept override {
|
||||
return update_stamp;
|
||||
}
|
||||
|
||||
@@ -138,10 +139,10 @@ private:
|
||||
void Disconnect();
|
||||
|
||||
/* virtual methods from SocketMonitor */
|
||||
virtual bool OnSocketReady(unsigned flags) override;
|
||||
bool OnSocketReady(unsigned flags) override;
|
||||
|
||||
/* virtual methods from IdleMonitor */
|
||||
virtual void OnIdle() override;
|
||||
void OnIdle() override;
|
||||
};
|
||||
|
||||
static constexpr struct {
|
||||
@@ -215,7 +216,7 @@ ProxySong::ProxySong(const mpd_song *song)
|
||||
|
||||
gcc_const
|
||||
static enum mpd_tag_type
|
||||
Convert(TagType tag_type)
|
||||
Convert(TagType tag_type) noexcept
|
||||
{
|
||||
for (auto i = &tag_table[0]; i->d != TAG_NUM_OF_ITEM_TYPES; ++i)
|
||||
if (i->d == tag_type)
|
||||
@@ -345,9 +346,15 @@ ProxyDatabase::Create(EventLoop &loop, DatabaseListener &listener,
|
||||
void
|
||||
ProxyDatabase::Open()
|
||||
{
|
||||
Connect();
|
||||
|
||||
update_stamp = 0;
|
||||
|
||||
try {
|
||||
Connect();
|
||||
} catch (const std::runtime_error &error) {
|
||||
/* this error is non-fatal, because this plugin will
|
||||
attempt to reconnect again automatically */
|
||||
LogError(error);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -371,7 +378,10 @@ ProxyDatabase::Connect()
|
||||
mpd_connection_free(connection);
|
||||
connection = nullptr;
|
||||
|
||||
throw;
|
||||
std::throw_with_nested(host.empty()
|
||||
? std::runtime_error("Failed to connect to remote MPD")
|
||||
: FormatRuntimeError("Failed to connect to remote MPD '%s'",
|
||||
host.c_str()));
|
||||
}
|
||||
|
||||
#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
|
||||
@@ -564,7 +574,7 @@ Visit(struct mpd_connection *connection,
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
Match(const SongFilter *filter, const LightSong &song)
|
||||
Match(const SongFilter *filter, const LightSong &song) noexcept
|
||||
{
|
||||
return filter == nullptr || filter->Match(song);
|
||||
}
|
||||
@@ -707,7 +717,7 @@ SearchSongs(struct mpd_connection *connection,
|
||||
*/
|
||||
gcc_pure
|
||||
static bool
|
||||
ServerSupportsSearchBase(const struct mpd_connection *connection)
|
||||
ServerSupportsSearchBase(const struct mpd_connection *connection) noexcept
|
||||
{
|
||||
#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
|
||||
return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0;
|
||||
|
@@ -65,7 +65,7 @@ Directory::Delete()
|
||||
}
|
||||
|
||||
const char *
|
||||
Directory::GetName() const
|
||||
Directory::GetName() const noexcept
|
||||
{
|
||||
assert(!IsRoot());
|
||||
|
||||
@@ -89,7 +89,7 @@ Directory::CreateChild(const char *name_utf8)
|
||||
}
|
||||
|
||||
const Directory *
|
||||
Directory::FindChild(const char *name) const
|
||||
Directory::FindChild(const char *name) const noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
|
||||
@@ -101,7 +101,7 @@ Directory::FindChild(const char *name) const
|
||||
}
|
||||
|
||||
void
|
||||
Directory::PruneEmpty()
|
||||
Directory::PruneEmpty() noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
|
||||
@@ -118,7 +118,7 @@ Directory::PruneEmpty()
|
||||
}
|
||||
|
||||
Directory::LookupResult
|
||||
Directory::LookupDirectory(const char *uri)
|
||||
Directory::LookupDirectory(const char *uri) noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
assert(uri != nullptr);
|
||||
@@ -173,7 +173,7 @@ Directory::AddSong(Song *song)
|
||||
}
|
||||
|
||||
void
|
||||
Directory::RemoveSong(Song *song)
|
||||
Directory::RemoveSong(Song *song) noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
assert(song != nullptr);
|
||||
@@ -183,7 +183,7 @@ Directory::RemoveSong(Song *song)
|
||||
}
|
||||
|
||||
const Song *
|
||||
Directory::FindSong(const char *name_utf8) const
|
||||
Directory::FindSong(const char *name_utf8) const noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
assert(name_utf8 != nullptr);
|
||||
@@ -200,13 +200,13 @@ Directory::FindSong(const char *name_utf8) const
|
||||
|
||||
gcc_pure
|
||||
static bool
|
||||
directory_cmp(const Directory &a, const Directory &b)
|
||||
directory_cmp(const Directory &a, const Directory &b) noexcept
|
||||
{
|
||||
return IcuCollate(a.path.c_str(), b.path.c_str()) < 0;
|
||||
}
|
||||
|
||||
void
|
||||
Directory::Sort()
|
||||
Directory::Sort() noexcept
|
||||
{
|
||||
assert(holding_db_lock());
|
||||
|
||||
@@ -261,7 +261,7 @@ Directory::Walk(bool recursive, const SongFilter *filter,
|
||||
}
|
||||
|
||||
LightDirectory
|
||||
Directory::Export() const
|
||||
Directory::Export() const noexcept
|
||||
{
|
||||
return LightDirectory(GetPath(), mtime);
|
||||
}
|
||||
|
@@ -86,7 +86,7 @@ struct Directory {
|
||||
|
||||
Directory *parent;
|
||||
time_t mtime;
|
||||
unsigned inode, device;
|
||||
uint64_t inode, device;
|
||||
|
||||
std::string path;
|
||||
|
||||
@@ -134,10 +134,10 @@ public:
|
||||
* Caller must lock the #db_mutex.
|
||||
*/
|
||||
gcc_pure
|
||||
const Directory *FindChild(const char *name) const;
|
||||
const Directory *FindChild(const char *name) const noexcept;
|
||||
|
||||
gcc_pure
|
||||
Directory *FindChild(const char *name) {
|
||||
Directory *FindChild(const char *name) noexcept {
|
||||
const Directory *cthis = this;
|
||||
return const_cast<Directory *>(cthis->FindChild(name));
|
||||
}
|
||||
@@ -177,17 +177,17 @@ public:
|
||||
* @return the Directory, or nullptr if none was found
|
||||
*/
|
||||
gcc_pure
|
||||
LookupResult LookupDirectory(const char *uri);
|
||||
LookupResult LookupDirectory(const char *uri) noexcept;
|
||||
|
||||
gcc_pure
|
||||
bool IsEmpty() const {
|
||||
bool IsEmpty() const noexcept {
|
||||
return children.empty() &&
|
||||
songs.empty() &&
|
||||
playlists.empty();
|
||||
}
|
||||
|
||||
gcc_pure
|
||||
const char *GetPath() const {
|
||||
const char *GetPath() const noexcept {
|
||||
return path.c_str();
|
||||
}
|
||||
|
||||
@@ -195,13 +195,13 @@ public:
|
||||
* Returns the base name of the directory.
|
||||
*/
|
||||
gcc_pure
|
||||
const char *GetName() const;
|
||||
const char *GetName() const noexcept;
|
||||
|
||||
/**
|
||||
* Is this the root directory of the music database?
|
||||
*/
|
||||
gcc_pure
|
||||
bool IsRoot() const {
|
||||
bool IsRoot() const noexcept {
|
||||
return parent == nullptr;
|
||||
}
|
||||
|
||||
@@ -229,10 +229,10 @@ public:
|
||||
* Caller must lock the #db_mutex.
|
||||
*/
|
||||
gcc_pure
|
||||
const Song *FindSong(const char *name_utf8) const;
|
||||
const Song *FindSong(const char *name_utf8) const noexcept;
|
||||
|
||||
gcc_pure
|
||||
Song *FindSong(const char *name_utf8) {
|
||||
Song *FindSong(const char *name_utf8) noexcept {
|
||||
const Directory *cthis = this;
|
||||
return const_cast<Song *>(cthis->FindSong(name_utf8));
|
||||
}
|
||||
@@ -248,19 +248,19 @@ public:
|
||||
* invalidates the song object, because the "parent" attribute becomes
|
||||
* stale), but does not free it.
|
||||
*/
|
||||
void RemoveSong(Song *song);
|
||||
void RemoveSong(Song *song) noexcept;
|
||||
|
||||
/**
|
||||
* Caller must lock the #db_mutex.
|
||||
*/
|
||||
void PruneEmpty();
|
||||
void PruneEmpty() noexcept;
|
||||
|
||||
/**
|
||||
* Sort all directory entries recursively.
|
||||
*
|
||||
* Caller must lock the #db_mutex.
|
||||
*/
|
||||
void Sort();
|
||||
void Sort() noexcept;
|
||||
|
||||
/**
|
||||
* Caller must lock #db_mutex.
|
||||
@@ -270,7 +270,7 @@ public:
|
||||
VisitPlaylist visit_playlist) const;
|
||||
|
||||
gcc_pure
|
||||
LightDirectory Export() const;
|
||||
LightDirectory Export() const noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -40,7 +40,7 @@
|
||||
|
||||
gcc_const
|
||||
static const char *
|
||||
DeviceToTypeString(unsigned device)
|
||||
DeviceToTypeString(unsigned device) noexcept
|
||||
{
|
||||
switch (device) {
|
||||
case DEVICE_INARCHIVE:
|
||||
@@ -56,7 +56,7 @@ DeviceToTypeString(unsigned device)
|
||||
|
||||
gcc_pure
|
||||
static unsigned
|
||||
ParseTypeString(const char *type)
|
||||
ParseTypeString(const char *type) noexcept
|
||||
{
|
||||
if (strcmp(type, "archive") == 0)
|
||||
return DEVICE_INARCHIVE;
|
||||
|
@@ -25,6 +25,13 @@
|
||||
#include "db/Interface.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
/* workaround for "error: incomplete type 'PlaylistInfo' used in type
|
||||
trait expression" with libc++ version 3900 (from Android NDK
|
||||
r13b) */
|
||||
#include "db/PlaylistInfo.hxx"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
struct PrefixedLightDirectory : LightDirectory {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user