Compare commits

...

72 Commits

Author SHA1 Message Date
Max Kellermann
4a5528697d release v0.18.23 2015-02-06 17:04:14 +01:00
Max Kellermann
5489dec28d NEWS: fix v0.18.22 release date 2015-02-01 12:22:24 +01:00
PHO
a4f4fc50b9 Avoid integer overflow in MonotonicClock{S,MS,US}
This is Darwin specific: the previous implementation was causing an integer
overflow when base.numer is very large. On PPC Darwin, the timebase info is 1000000000/33330116 and this is too large for integer arithmetic.
2015-01-29 08:33:48 +01:00
Max Kellermann
ad1b6ef0ac {playlist,input}/despotify: remove defunct plugin 2015-01-26 09:55:31 +01:00
Max Kellermann
ed5c6be2f1 util/list: disable gcc5 warning
This file has been removed in newer MPD versions, so don't care about
it now.
2015-01-23 16:50:31 +01:00
Max Kellermann
30cb082932 ClientProcess: cast enum to int before passing to printf()
Fixes gcc5 warning.
2015-01-23 16:50:31 +01:00
Max Kellermann
645554d12f configure.ac: prepare for 0.18.23 2015-01-23 16:47:13 +01:00
Max Kellermann
8534f2d1e2 release v0.18.22 2015-01-14 23:04:49 +01:00
Max Kellermann
665031467a db/proxy, output/shout: fix implicit nullptr/bool conversion
Return false on error, not nullptr.
2014-12-26 13:50:54 +01:00
Max Kellermann
df33171107 db/{simple,proxy}, ...: add "override" keywords
Fixes -Winconsistent-missing-override (clang 3.6).
2014-12-26 13:47:04 +01:00
Max Kellermann
53f4044890 util/{ASCII,UriUtil}, ...: work around -Wtautological-pointer-compare
New in clang 3.6.
2014-12-26 13:43:32 +01:00
Max Kellermann
a5049136ff DatabaseGlue: convert nullptr check to assertion 2014-12-26 13:43:32 +01:00
Max Kellermann
705b3c6b63 util/ASCII: fix indent 2014-12-26 13:37:38 +01:00
Max Kellermann
6b4ac66962 Compiler.h: add macro CLANG_CHECK_VERSION() 2014-12-26 13:31:03 +01:00
Max Kellermann
0964b06240 Compiler.h: add macro GCC_OLDER_THAN() 2014-12-26 13:30:44 +01:00
Max Kellermann
92eeca3ba7 util/Manual: reimplement GCC_CHECK_VERSION() using GCC_MAKE_VERSION() 2014-12-26 13:30:22 +01:00
Max Kellermann
2a86554ac4 Compiler.h: add macro GCC_MAKE_VERSION() 2014-12-26 13:30:11 +01:00
Max Kellermann
805caa30ce configure.ac: prepare for 0.18.22 2014-12-26 13:23:04 +01:00
Max Kellermann
acb798e544 release v0.18.21 2014-12-17 19:13:47 +01:00
k44
773de38bd9 playlist/embcue: fix filename suffix detection
The definition of the playlist_plugin struct member of the embcue
plugin was incorrect.
2014-12-16 18:43:05 +01:00
Max Kellermann
fa4beeee75 decoder/ffmpeg: detect and fix negative time stamps
Works around assertion failure due to something that appears to be a
(minor) FFmpeg bug.
2014-12-15 00:40:46 +01:00
Max Kellermann
d8351772d3 configure.ac: prepare for 0.18.21 2014-12-15 00:39:52 +01:00
Max Kellermann
1b5f33a435 release v0.18.20 2014-12-08 14:57:17 +01:00
Max Kellermann
41b4a63f2b decoder/ffmpeg: support FFmpeg 2.5
Version 2.5 fixed an API oddity, however it broke API compatibility,
at least with C++.  Disable the workaround when a libavformat version
is detected that is recent enough.
2014-12-08 14:25:34 +01:00
Max Kellermann
d8fc2db910 thread/Id: drop "::" prefix before pthread function names
The "::" to explicitly refer to the global namespace appeared like a
good idea in C++, but it breaks with C libraries that implement
standard functions using macros (e.g. musl).
2014-12-08 14:17:17 +01:00
Max Kellermann
dc11dea7cc configure.ac: prepare for 0.18.20 2014-12-08 14:13:20 +01:00
Max Kellermann
04f627c2af release v0.18.19 2014-11-26 19:58:48 +01:00
Max Kellermann
a254f5a3a8 archive/zzip: fix inverted error handler
Set the Error when zzip_seek()==-1 and not on success.  Fixes a crash
after seeking.
2014-11-24 22:08:50 +01:00
Max Kellermann
143c735f96 configure.ac: prepare for 0.18.19 2014-11-24 22:08:50 +01:00
Max Kellermann
7aa2104596 release v0.18.18 2014-11-18 21:34:03 +01:00
Max Kellermann
c8b93d6573 Client: assume uid==0 is local socket
A negative uid value means it's not a "local socket" (PF_LOCAL).
uid==0 means user "root" connected.
2014-11-18 20:56:27 +01:00
Max Kellermann
3f5f96ac91 event/ServerSocket: fix get_remote_uid() error value
Must return -1 on error, not 0.  0 is root.
2014-11-18 20:53:59 +01:00
Florent Le Coz
7e7b403043 Construct a Null AllocatedPath if the filename conversion into UTF8 failed 2014-11-11 17:15:19 +01:00
Max Kellermann
c64ad78c7b decoder/ffmpeg: support opus 2014-11-10 18:00:30 +01:00
Max Kellermann
4a043a915f configure.ac: prepare for 0.18.1 2014-11-10 17:59:06 +01:00
Max Kellermann
38a0d15190 release v0.18.17 2014-11-02 13:06:20 +01:00
Max Kellermann
ec3191f502 input/curl: fix curl_easy_setopt() parameter types 2014-11-02 11:55:48 +01:00
Max Kellermann
32b5654a6e Decoder, Playlist: ignore URI query string for plugin detection
Use the new uri_get_suffix() overload that removes the query string.
2014-11-02 11:54:26 +01:00
Max Kellermann
674091424e util/UriUtil: add uri_get_suffix() overload that ignores query string 2014-11-02 11:53:31 +01:00
Max Kellermann
6ad336743d PlaylistFile: don't allow empty playlist name 2014-11-02 11:52:48 +01:00
Max Kellermann
c882568ccd playlist/m3u: recognize the file suffix ".m3u8" 2014-11-02 11:50:56 +01:00
Max Kellermann
f6b2899dd2 decoder/faad: remove workaround for ancient libfaad2 ABI bug
Many years ago, FAAD had a serious ABI bug: the NeAACDecInit()
prototype in its header declared the "samplerate" parameter to be
"unsigned long *", but internally, the function assumed it was
"uint32_t *" instead.  On 32 bit machines, that was no difference, but
on 64 bit, this left one portion of the return value uninitialized;
and worse, on big-endian, the wrong word was filled.  This bug had to
be worked around in MPD (commit 9c4e97a6).

A few months later, the bug was fixed in the FAAD CVS in commit 1.117
on file libfaad/decoder.c; the commit message was:

 "Use public headers internally to prevent duplicate declarations"

The commit message was too brief at best; the problem was not
duplicate declarations, but a prototype mismatch.  No mention of the
bug fix in the ChangeLog.

The MPD project never learned about this bug fix, and so MPD would
always pass a "uin32_t *" dressed up as a "unsigned long *".  Nearly 6
years later, it's about time to fix this second ABI problem.  Let's
kill the workaround!
2014-11-02 11:50:56 +01:00
Steven OBrien
bccd4ef2f7 decoder/ffmpeg: recognize MIME type audio/aacp 2014-11-02 11:50:56 +01:00
Max Kellermann
94c240a026 configure.ac: show DSD in result 2014-11-02 11:50:56 +01:00
Max Kellermann
c50a0cf7bf output/roar: remove unnecessary "volatile" keyword
A mutex acts as a memory barrier, and thus "volatile" is not
necessary.
2014-11-02 11:50:56 +01:00
Max Kellermann
c37f7abb79 TagString: use g_strndup() for unterminated string
Fixes buffer overflow bug.
2014-11-02 11:48:13 +01:00
Max Kellermann
432ce9b1de configure.ac: prepare for 0.18.17 2014-11-02 11:41:40 +01:00
Max Kellermann
fe45f28204 release v0.18.16 2014-09-26 10:57:04 +02:00
Max Kellermann
861067412f configure.ac: fix DSD breakage due to typo 2014-09-26 10:56:20 +02:00
Max Kellermann
7eca886608 configure.ac: prepare for 0.18.16 2014-09-26 10:55:43 +02:00
Max Kellermann
79b6f9e89e release v0.18.15 2014-09-26 09:41:40 +02:00
Max Kellermann
3d17c06777 configure.ac: allow building MPD without decoder plugin
There's always the "PCM" decoder plugin, which was never checked by
configure.ac.
2014-09-26 09:29:18 +02:00
Max Kellermann
d6c08fb79f configure.ac: allow building MPD without output plugin
MPD can easily be used as a database provider for the proxy database
plugin.  In that case, it needs only one "null" output, and no real
output plugin.
2014-09-26 09:29:18 +02:00
Max Kellermann
ef02b20811 CommandLine: update copyright year 2014-09-26 09:29:18 +02:00
Max Kellermann
8bf46a665e configure.ac: add option to disable the DSD decoders
Allow building a smaller MPD binary for people who don't need DSD.
2014-09-26 09:29:18 +02:00
Max Kellermann
c4fca2aa61 playlist/embcue: change name string to "embcue"
The name "cue" was listed twice in "mpd --version".
2014-09-26 09:29:18 +02:00
Max Kellermann
87268c2297 test/test_protocol: add missing stdlib.h include
EXIT_SUCCESS and EXIT_FAILURE are defined in stdlib.h, not unistd.h.
D'oh!
2014-09-24 23:03:28 +02:00
Max Kellermann
e93975cb46 test/test_protocol: add missing unistd.h include 2014-09-24 21:43:11 +02:00
Max Kellermann
b6fa22bd84 OutputThread: retain negative mix ratio
Fixes MixRamp breakage.
2014-09-18 13:50:23 +02:00
Andrzej Rybczak
a0ef27a0cd command/list: reset used size after the list has been processed 2014-09-18 09:15:39 +02:00
Max Kellermann
e304d0f8ee thread/Posix{Cond,Mutex}: don't ues PTHREAD_*_INITIALIZER on NetBSD
On NetBSD, PTHREAD_MUTEX_INITIALIZER and PTHREAD_COND_INITIALIZER are
not compatible with C++11 "constexpr" (see Mantis ticket 0004110).  As
a workaround, don't ues "constexpr", and use the functions
pthread_mutex_init(), pthread_mutex_destroy(), pthread_cond_init() and
pthread_cond_destroy() instead.  This adds some runtime overhead, but
is portable to POSIX implementations that have awkward initializer
macros.
2014-09-13 11:26:17 +02:00
Max Kellermann
ab7b38d4b9 configure.ac: prepare for 0.18.15 2014-09-13 11:14:41 +02:00
Max Kellermann
eaf675dc92 release v0.18.14 2014-09-11 19:09:49 +02:00
Max Kellermann
57068e526c test/run_decoder: dump MixRamp data 2014-09-09 19:17:22 +02:00
Max Kellermann
c14a00eec9 decoder/ffmpeg: use memset() to initialize AVProbeData 2014-09-09 19:07:46 +02:00
Max Kellermann
219c42522f decoder/ffmpeg: pass MIME type to ffmpeg/libav version 11
That attribute was uninitialized before, which could crash
libavformat.

See Debian bug 760669
2014-09-07 22:05:33 +02:00
Max Kellermann
e3a0f15837 Decoder*: add more assertions 2014-09-07 21:52:34 +02:00
Max Kellermann
a6bb27483b DecoderThread: clear the pipe when handling late SEEK
See code comment.  Fixes assertion failure in
decoder_command_finished().
2014-09-07 21:50:00 +02:00
Max Kellermann
7ada7def9e decoder/audiofile: fix crash after seeking
Log call was added to the wrong branch.

Fixes regression by commit ca1a1149
2014-09-06 19:32:10 +02:00
Max Kellermann
421c4ae907 protocol/ArgParser: fix integer overflow in parse_range()
Casting std::numeric_limits<unsigned>::max() to "long" leads to an
overflow if sizeof(unsigned)==sizeof(long), and the result will be -1.

This happens on some 32 bit architectures, for example ARM and WIN32.

Workaround: use std::numeric_limits<int>::max(), which is the largest
signed integer.  Since sizeof(long)>=sizeof(int), this will never
overflow.

Fixes Mantis ticket 0004080.
2014-09-04 17:37:31 +02:00
Max Kellermann
4907f610d6 test/test_protocol: unit test for protocol/ArgParser.cxx 2014-09-04 17:10:30 +02:00
Max Kellermann
f9d1bbbffb configure.ac: prepare for 0.18.14 2014-09-03 19:59:26 +02:00
71 changed files with 474 additions and 998 deletions

1
.gitignore vendored

@@ -63,6 +63,7 @@ test/run_normalize
test/tmp
test/run_inotify
test/test_queue_priority
test/test_protocol
test/run_ntp_server
test/run_resolver
test/run_tcp_connect

@@ -114,9 +114,6 @@ For WavPack playback.
libadplug - http://adplug.sourceforge.net/
For AdLib playback.
despotify - https://github.com/SimonKagstrom/despotify
For Spotify playback.
Optional Miscellaneous Dependencies
-----------------------------------

@@ -221,11 +221,6 @@ EXTRA_src_mpd_DEPENDENCIES = src/win32/mpd_win32_rc.$(OBJEXT)
src_mpd_LDFLAGS = -Wl,src/win32/mpd_win32_rc.$(OBJEXT)
endif
if ENABLE_DESPOTIFY
src_mpd_SOURCES += \
src/DespotifyUtils.cxx src/DespotifyUtils.hxx
endif
if ENABLE_INOTIFY
src_mpd_SOURCES += \
src/InotifyDomain.cxx src/InotifyDomain.hxx \
@@ -476,12 +471,6 @@ endif
libdecoder_plugins_a_SOURCES = \
src/decoder/PcmDecoderPlugin.cxx \
src/decoder/PcmDecoderPlugin.hxx \
src/decoder/DsdiffDecoderPlugin.cxx \
src/decoder/DsdiffDecoderPlugin.hxx \
src/decoder/DsfDecoderPlugin.cxx \
src/decoder/DsfDecoderPlugin.hxx \
src/decoder/DsdLib.cxx \
src/decoder/DsdLib.hxx \
src/DecoderBuffer.cxx src/DecoderBuffer.hxx \
src/DecoderPlugin.cxx \
src/DecoderList.cxx src/DecoderList.hxx
@@ -525,6 +514,16 @@ DECODER_LIBS = \
DECODER_SRC =
if ENABLE_DSD
libdecoder_plugins_a_SOURCES += \
src/decoder/DsdiffDecoderPlugin.cxx \
src/decoder/DsdiffDecoderPlugin.hxx \
src/decoder/DsfDecoderPlugin.cxx \
src/decoder/DsfDecoderPlugin.hxx \
src/decoder/DsdLib.cxx \
src/decoder/DsdLib.hxx
endif
if HAVE_MAD
libdecoder_plugins_a_SOURCES += \
src/decoder/MadDecoderPlugin.cxx \
@@ -766,7 +765,6 @@ libinput_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(CURL_CFLAGS) \
$(CDIO_PARANOIA_CFLAGS) \
$(FFMPEG_CFLAGS) \
$(DESPOTIFY_CFLAGS) \
$(MMS_CFLAGS)
INPUT_LIBS = \
@@ -774,7 +772,6 @@ INPUT_LIBS = \
$(CURL_LIBS) \
$(CDIO_PARANOIA_LIBS) \
$(FFMPEG_LIBS) \
$(DESPOTIFY_LIBS) \
$(MMS_LIBS)
if ENABLE_CURL
@@ -799,12 +796,6 @@ libinput_a_SOURCES += \
src/input/MmsInputPlugin.cxx src/input/MmsInputPlugin.hxx
endif
if ENABLE_DESPOTIFY
libinput_a_SOURCES += \
src/input/DespotifyInputPlugin.cxx \
src/input/DespotifyInputPlugin.hxx
endif
liboutput_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
$(AO_CFLAGS) \
@@ -985,12 +976,6 @@ PLAYLIST_LIBS = \
libplaylist_plugins.a \
$(FLAC_LIBS)
if ENABLE_DESPOTIFY
libplaylist_plugins_a_SOURCES += \
src/playlist/DespotifyPlaylistPlugin.cxx \
src/playlist/DespotifyPlaylistPlugin.hxx
endif
if ENABLE_SOUNDCLOUD
libplaylist_plugins_a_SOURCES += \
src/playlist/SoundCloudPlaylistPlugin.cxx \
@@ -1064,6 +1049,7 @@ C_TESTS = \
test/test_mixramp \
test/test_icy_parser \
test/test_pcm \
test/test_protocol \
test/test_queue_priority
if ENABLE_ARCHIVE
@@ -1180,10 +1166,6 @@ test_visit_archive_SOURCES = test/visit_archive.cxx \
src/IOThread.cxx \
src/InputStream.cxx
if ENABLE_DESPOTIFY
test_visit_archive_SOURCES += src/DespotifyUtils.cxx
endif
endif
test_dump_text_file_LDADD = \
@@ -1308,14 +1290,6 @@ test_run_filter_SOURCES = test/run_filter.cxx \
src/ReplayGainInfo.cxx \
src/AudioCompress/compress.c
if ENABLE_DESPOTIFY
test_read_tags_SOURCES += src/DespotifyUtils.cxx
test_run_input_SOURCES += src/DespotifyUtils.cxx
test_dump_text_file_SOURCES += src/DespotifyUtils.cxx
test_dump_playlist_SOURCES += src/DespotifyUtils.cxx
test_run_decoder_SOURCES += src/DespotifyUtils.cxx
endif
if ENABLE_ENCODER
noinst_PROGRAMS += test/run_encoder
test_run_encoder_SOURCES = test/run_encoder.cxx \
@@ -1538,6 +1512,16 @@ test_test_archive_LDADD = \
$(GLIB_LIBS) \
$(CPPUNIT_LIBS)
test_test_protocol_SOURCES = \
src/protocol/ArgParser.cxx \
test/test_protocol.cxx
test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0
test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations
test_test_protocol_LDADD = \
libsystem.a \
libutil.a \
$(CPPUNIT_LIBS)
test_test_queue_priority_SOURCES = \
src/Queue.cxx \
test/test_queue_priority.cxx
@@ -1548,6 +1532,8 @@ test_test_queue_priority_LDADD = \
libutil.a \
$(CPPUNIT_LIBS)
if ENABLE_DSD
noinst_PROGRAMS += src/pcm/dsd2pcm/dsd2pcm
src_pcm_dsd2pcm_dsd2pcm_SOURCES = \
@@ -1560,6 +1546,8 @@ src_pcm_dsd2pcm_dsd2pcm_LDADD = libutil.a
endif
endif
#
# Documentation

55
NEWS

@@ -1,3 +1,58 @@
ver 0.18.23 (2015/02/06)
* despotify: remove defunct plugin
* fix clock integer overflow on OS X
* fix gcc 5.0 warnings
ver 0.18.22 (2015/01/14)
* fix clang 3.6 warnings
ver 0.18.21 (2014/12/17)
* playlist
- embcue: fix filename suffix detection
* decoder
- ffmpeg: fix time stamp underflow
ver 0.18.20 (2014/12/08)
* decoder
- ffmpeg: support FFmpeg 2.5
* fix build failure with musl
ver 0.18.19 (2014/11/26)
* archive
- zzip: fix crash after seeking
ver 0.18.18 (2014/11/18)
* decoder
- ffmpeg: support opus
* fix crash on failed filename charset conversion
* fix local socket detection from uid=0 (root)
ver 0.18.17 (2014/11/02)
* playlist
- don't allow empty playlist name
- m3u: recognize the file suffix ".m3u8"
* decoder
- ignore URI query string for plugin detection
- faad: remove workaround for ancient libfaad2 ABI bug
- ffmpeg: recognize MIME type audio/aacp
ver 0.18.16 (2014/09/26)
* fix DSD breakage due to typo in configure.ac
ver 0.18.15 (2014/09/26)
* command
- list: reset used size after the list has been processed
* fix MixRamp
* work around build failure on NetBSD
ver 0.18.14 (2014/09/11)
* protocol
- fix range parser bug on certain 32 bit architectures
* decoder
- audiofile: fix crash after seeking
- ffmpeg: fix crash with ffmpeg/libav version 11
- fix assertion failure after seeking
ver 0.18.13 (2014/08/31)
* protocol
- don't change song on "seekcur" in random mode

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.13, mpd-devel@musicpd.org)
AC_INIT(mpd, 0.18.23, mpd-devel@musicpd.org)
VERSION_MAJOR=0
VERSION_MINOR=18
VERSION_REVISION=0
VERSION_REVISION=23
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -214,6 +214,11 @@ AC_ARG_ENABLE(documentation,
[build documentation (default: disable)]),,
[enable_documentation=no])
AC_ARG_ENABLE(dsd,
AS_HELP_STRING([--enable-dsd],
[enable DSD decoder (default: enable)]),,
[enable_dsd=yes])
AC_ARG_ENABLE(ffmpeg,
AS_HELP_STRING([--enable-ffmpeg],
[enable FFMPEG support]),,
@@ -271,11 +276,6 @@ AC_ARG_ENABLE(jack,
AC_SYS_LARGEFILE
AC_ARG_ENABLE(despotify,
AS_HELP_STRING([--enable-despotify],
[enable support for despotify (default: disable)]),,
[enable_despotify=no])
AC_ARG_ENABLE(soundcloud,
AS_HELP_STRING([--enable-soundcloud],
[enable support for soundcloud.com]),,
@@ -720,14 +720,6 @@ if test x$enable_curl = xyes; then
fi
AM_CONDITIONAL(ENABLE_CURL, test x$enable_curl = xyes)
dnl --------------------------------- Despotify ---------------------------------
MPD_AUTO_PKG(despotify, DESPOTIFY, [despotify],
[Despotify support], [despotify not found])
if test x$enable_despotify = xyes; then
AC_DEFINE(ENABLE_DESPOTIFY, 1, [Define when despotify is enabled])
fi
AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
dnl --------------------------------- Soundcloud ------------------------------
if test x$enable_soundcloud != xno; then
PKG_CHECK_MODULES([YAJL], [yajl >= 2.0],
@@ -846,6 +838,14 @@ if test x$enable_audiofile = xyes; then
AC_DEFINE(HAVE_AUDIOFILE, 1, [Define for audiofile support])
fi
dnl ----------------------------------- DSD -----------------------------------
if test x$enable_dsd = xyes; then
AC_DEFINE(ENABLE_DSD, 1, [Define for the DSD decoder])
fi
AM_CONDITIONAL(ENABLE_DSD, test x$enable_dsd = xyes)
dnl ----------------------------------- FAAD ----------------------------------
AM_PATH_FAAD()
@@ -1081,27 +1081,6 @@ AM_CONDITIONAL(ENABLE_WILDMIDI, test x$enable_wildmidi = xyes)
dnl ------------------------ Post Decoder Plugins Tests -----------------------
if
test x$enable_aac = xno &&
test x$enable_audiofile = xno &&
test x$enable_ffmpeg = xno &&
test x$enable_flac = xno &&
test x$enable_fluidsynth = xno &&
test x$enable_mad = xno &&
test x$enable_mikmod = xno; then
test x$enable_modplug = xno &&
test x$enable_mpc = xno &&
test x$enable_mpg123 = xno &&
test x$enable_opus = xno &&
test x$enable_sidplay = xno &&
test x$enable_tremor = xno &&
test x$enable_vorbis = xno &&
test x$enable_wavpack = xno &&
test x$enable_wildmidi = xno &&
AC_MSG_ERROR([No input plugins supported!])
fi
AM_CONDITIONAL(HAVE_XIPH,
test x$enable_vorbis = xyes || test x$enable_tremor = xyes || test x$enable_flac = xyes || test x$enable_opus = xyes)
@@ -1410,27 +1389,6 @@ esac
AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes)
dnl --------------------- Post Audio Output Plugins Tests ---------------------
if
test x$enable_alsa = xno &&
test x$enable_roar = xno &&
test x$enable_ao = xno &&
test x$enable_fifo = xno &&
test x$enable_httpd_output = xno &&
test x$enable_jack = xno &&
test x$enable_openal = xno &&
test x$enable_oss = xno &&
test x$enable_osx = xno &&
test x$enable_pipe_output = xno &&
test x$enable_pulse = xno &&
test x$enable_recorder_output = xno &&
test x$enable_shout = xno &&
test x$enable_solaris_output = xno &&
test x$enable_winmm_output = xno; then
AC_MSG_ERROR([No Audio Output types configured!])
fi
dnl ---------------------------------------------------------------------------
dnl Documentation
dnl ---------------------------------------------------------------------------
@@ -1552,6 +1510,7 @@ results(un,[UNIX Domain Sockets])
printf '\nFile format support:\n\t'
results(aac, [AAC])
results(adplug, [AdPlug])
results(dsd, [DSD])
results(sidplay, [C64 SID])
results(ffmpeg, [FFMPEG])
results(flac, [FLAC])
@@ -1616,7 +1575,6 @@ fi
printf '\nStreaming support:\n\t'
results(cdio_paranoia, [CDIO_PARANOIA])
results(curl,[CURL])
results(despotify,[Despotify])
results(soundcloud,[Soundcloud])
printf '\n\t'
results(mms,[MMS])

@@ -274,16 +274,6 @@ of database.
Limit the depth of the directories being watched, 0 means only watch
the music directory itself. There is no limit by default.
.TP
.B despotify_user <name>
This specifies the user to use when logging in to Spotify using the despotify plugins.
.TP
.B despotify_password <name>
This specifies the password to use when logging in to Spotify using the despotify plugins.
.TP
.B despotify_high_bitrate <yes or no>
This specifies if the requested bitrate for Spotify should be high or not. Higher sounds
better but requires more processing and higher bandwidth. Default is yes.
.TP
.SH REQUIRED AUDIO OUTPUT PARAMETERS
.TP
.B type <type>

@@ -220,9 +220,8 @@ systemctl start mpd.socket</programlisting>
</para>
<programlisting>input {
plugin "despotify"
user "foo"
password "bar"
plugin "curl"
proxy "proxy.local"
}
</programlisting>
@@ -842,66 +841,6 @@ systemctl start mpd.socket</programlisting>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>despotify</varname></title>
<para>
Plays <ulink url="http://www.spotify.com">Spotify</ulink> tracks using the despotify
library. The despotify plugin uses a <filename>spt://</filename> URI and a Spotify
URL. So for example, you can add a song with:
</para>
<para>
<filename>mpc add spt://spotify:track:5qENVY0YEdZ7fiuOax70x1</filename>
</para>
<para>
You need a Spotify premium account to use this plugin, and you need
to setup username and password in the configuration file. The
configuration settings are global since the despotify playlist plugin
use the same settings.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>despotify_user</varname>
</entry>
<entry>
Sets up the Spotify username (required)
</entry>
</row>
<row>
<entry>
<varname>despotify_password</varname>
</entry>
<entry>
Sets up the Spotify password (required)
</entry>
</row>
<row>
<entry>
<varname>despotify_high_bitrate</varname>
</entry>
<entry>
Set up if high bitrate should be used for Spotify tunes.
High bitrate sounds better but slow systems can have problems
with playback (default yes).
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
</section>
<section>
@@ -2193,27 +2132,6 @@ systemctl start mpd.socket</programlisting>
playlist files.
</para>
</section>
<section>
<title><varname>despotify</varname></title>
<para>
Adds <ulink url="http://www.spotify.com/">Spotify</ulink>
playlists. Spotify playlists use the <filename>spt://</filename> URI,
and a Spotify playlist URL. So for example, you can load a playlist
with
</para>
<para>
<filename>mpc load spt://spotify:user:simon.kagstrom:playlist:3SUwkOe5VbVHysZcidEZtH</filename>
</para>
<para>
See the despotify input plugin for configuration options (username
and password needs to be setup)
</para>
</section>
</section>
</chapter>
</book>

@@ -62,36 +62,7 @@ int main() {
CPPFLAGS=$oldcppflags
fi
if test x$enable_aac = xyes; then
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
LIBS="$LIBS $FAAD_LIBS"
CPPFLAGS=$CFLAGS
AC_MSG_CHECKING(for broken libfaad headers)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
#include <stddef.h>
#include <stdint.h>
int main() {
unsigned char channels;
uint32_t sample_rate;
NeAACDecInit2(NULL, NULL, 0, &sample_rate, &channels);
return 0;
}
])],
[AC_MSG_RESULT(correct)],
[AC_MSG_RESULT(broken);
AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])
CFLAGS=$oldcflags
LIBS=$oldlibs
CPPFLAGS=$oldcppflags
else
if test x$enable_aac = xno; then
FAAD_LIBS=""
FAAD_CFLAGS=""
fi

@@ -109,7 +109,7 @@ public:
* a local (UNIX domain) socket?
*/
bool IsLocal() const {
return uid > 0;
return uid >= 0;
}
unsigned GetPermission() const {

@@ -47,7 +47,7 @@ client_allow_file(const Client &client, Path path_fs, Error &error)
instance */
return true;
if (uid <= 0) {
if (uid < 0) {
/* unauthenticated client */
error.Set(ack_domain, ACK_ERROR_PERMISSION, "Access denied");
return false;

@@ -41,7 +41,7 @@ client_process_command_list(Client &client, bool list_ok,
FormatDebug(client_domain, "process command \"%s\"", cmd);
ret = command_process(client, num++, cmd);
FormatDebug(client_domain, "command returned %i", ret);
FormatDebug(client_domain, "command returned %i", int(ret));
if (ret != CommandResult::OK || client.IsExpired())
break;
else if (list_ok)
@@ -90,7 +90,7 @@ client_process_line(Client &client, char *line)
std::move(cmd_list));
FormatDebug(client_domain,
"[%u] process command "
"list returned %i", client.num, ret);
"list returned %i", client.num, int(ret));
if (ret == CommandResult::CLOSE ||
client.IsExpired())
@@ -126,7 +126,7 @@ client_process_line(Client &client, char *line)
ret = command_process(client, 0, line);
FormatDebug(client_domain,
"[%u] command returned %i",
client.num, ret);
client.num, int(ret));
if (ret == CommandResult::CLOSE ||
client.IsExpired())

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* Copyright (C) 2003-2014 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ static void version(void)
puts("Music Player Daemon " VERSION "\n"
"\n"
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
"Copyright (C) 2008-2013 Max Kellermann <max@duempel.org>\n"
"Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\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"
"\n"

@@ -20,33 +20,45 @@
#ifndef COMPILER_H
#define COMPILER_H
#define GCC_CHECK_VERSION(major, minor) \
(defined(__GNUC__) && \
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
#define GCC_MAKE_VERSION(major, minor, patchlevel) ((major) * 10000 + (minor) * 100 + patchlevel)
#ifdef __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#define GCC_VERSION GCC_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#else
#define GCC_VERSION 0
#endif
#define GCC_CHECK_VERSION(major, minor) \
(defined(__GNUC__) && GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
/**
* Are we building with gcc (not clang or any other compiler) and a
* version older than the specified one?
*/
#define GCC_OLDER_THAN(major, minor) \
(defined(__GNUC__) && !defined(__clang__) && \
GCC_VERSION < GCC_MAKE_VERSION(major, minor, 0))
#ifdef __clang__
# define CLANG_VERSION (__clang_major__ * 10000 \
+ __clang_minor__ * 100 \
+ __clang_patchlevel__)
# define CLANG_VERSION GCC_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
# if __clang_major__ < 3
# error Sorry, your clang version is too old. You need at least version 3.1.
# endif
#elif defined(__GNUC__)
# if !GCC_CHECK_VERSION(4,6)
# if GCC_OLDER_THAN(4,6)
# error Sorry, your gcc version is too old. You need at least version 4.6.
# endif
#else
# warning Untested compiler. Use at your own risk!
#endif
/**
* Are we building with the specified version of clang or newer?
*/
#define CLANG_CHECK_VERSION(major, minor) \
(defined(__clang__) && \
CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
#if GCC_CHECK_VERSION(4,0)
/* GCC 4.x */
@@ -141,7 +153,7 @@
#if defined(__cplusplus)
/* support for C++11 "override" was added in gcc 4.7 */
#if !defined(__clang__) && !GCC_CHECK_VERSION(4,7)
#if GCC_OLDER_THAN(4,7)
#define override
#define final
#endif

@@ -112,13 +112,15 @@ db_get_root(void)
Directory *
db_get_directory(const char *name)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(name != nullptr);
#endif
if (db == nullptr)
return nullptr;
Directory *music_root = db_get_root();
if (name == nullptr)
return music_root;
return music_root->LookupDirectory(name);
}

@@ -47,6 +47,7 @@ decoder_initialized(Decoder &decoder,
assert(dc.state == DecoderState::START);
assert(dc.pipe != nullptr);
assert(dc.pipe->IsEmpty());
assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr);
assert(!decoder.seeking);
@@ -405,6 +406,9 @@ decoder_data(Decoder &decoder,
length == 0)
return cmd;
assert(!decoder.initial_seek_pending);
assert(!decoder.initial_seek_running);
/* send stream tags */
if (update_stream_tag(decoder, is)) {

@@ -83,6 +83,9 @@ void
decoder_flush_chunk(Decoder &decoder)
{
DecoderControl &dc = decoder.dc;
assert(!decoder.seeking);
assert(!decoder.initial_seek_running);
assert(!decoder.initial_seek_pending);
assert(decoder.chunk != nullptr);

@@ -73,8 +73,10 @@ const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef HAVE_AUDIOFILE
&audiofile_decoder_plugin,
#endif
#ifdef ENABLE_DSD
&dsdiff_decoder_plugin,
&dsf_decoder_plugin,
#endif
#ifdef HAVE_FAAD
&faad_decoder_plugin,
#endif

@@ -26,7 +26,10 @@
bool
DecoderPlugin::SupportsSuffix(const char *suffix) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(suffix != nullptr);
#endif
return suffixes != nullptr && string_array_contains(suffixes, suffix);
@@ -35,7 +38,10 @@ DecoderPlugin::SupportsSuffix(const char *suffix) const
bool
DecoderPlugin::SupportsMimeType(const char *mime_type) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(mime_type != nullptr);
#endif
return mime_types != nullptr &&
string_array_contains(mime_types, mime_type);

@@ -26,6 +26,7 @@
#include "Song.hxx"
#include "system/FatalError.hxx"
#include "Mapper.hxx"
#include "MusicPipe.hxx"
#include "fs/Traits.hxx"
#include "fs/AllocatedPath.hxx"
#include "DecoderAPI.hxx"
@@ -211,7 +212,8 @@ static bool
decoder_run_stream_locked(Decoder &decoder, InputStream &is,
const char *uri, bool &tried_r)
{
const char *const suffix = uri_get_suffix(uri);
UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
using namespace std::placeholders;
const auto f = std::bind(decoder_run_stream_plugin,
@@ -418,9 +420,18 @@ decoder_task(void *arg)
dc.replay_gain_prev_db = dc.replay_gain_db;
dc.replay_gain_db = 0;
/* fall through */
decoder_run(dc);
break;
case DecoderCommand::SEEK:
/* this seek was too late, and the decoder had
already finished; start a new decoder */
/* we need to clear the pipe here; usually the
PlayerThread is responsible, but it is not
aware that the decoder has finished */
dc.pipe->Clear(*dc.buffer);
decoder_run(dc);
break;

@@ -1,154 +0,0 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "DespotifyUtils.hxx"
#include "tag/Tag.hxx"
#include "ConfigGlobal.hxx"
#include "ConfigOption.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
extern "C" {
#include <despotify.h>
}
#include <stdio.h>
const Domain despotify_domain("despotify");
static struct despotify_session *g_session;
static void (*registered_callbacks[8])(struct despotify_session *,
int, void *, void *);
static void *registered_callback_data[8];
static void
callback(struct despotify_session* ds, int sig,
void *data, gcc_unused void *callback_data)
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
void (*cb)(struct despotify_session *, int, void *, void *) = registered_callbacks[i];
void *cb_data = registered_callback_data[i];
if (cb)
cb(ds, sig, data, cb_data);
}
}
bool mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, void *, void *),
void *cb_data)
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
if (!registered_callbacks[i]) {
registered_callbacks[i] = cb;
registered_callback_data[i] = cb_data;
return true;
}
}
return false;
}
void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, void *, void *))
{
size_t i;
for (i = 0; i < sizeof(registered_callbacks) / sizeof(registered_callbacks[0]); i++) {
if (registered_callbacks[i] == cb) {
registered_callbacks[i] = nullptr;
}
}
}
Tag *
mpd_despotify_tag_from_track(struct ds_track *track)
{
char tracknum[20];
char comment[80];
char date[20];
Tag *tag = new Tag();
if (!track->has_meta_data)
return tag;
snprintf(tracknum, sizeof(tracknum), "%d", track->tracknumber);
snprintf(date, sizeof(date), "%d", track->year);
snprintf(comment, sizeof(comment), "Bitrate %d Kbps, %sgeo restricted",
track->file_bitrate / 1000,
track->geo_restricted ? "" : "not ");
tag->AddItem(TAG_TITLE, track->title);
tag->AddItem(TAG_ARTIST, track->artist->name);
tag->AddItem(TAG_TRACK, tracknum);
tag->AddItem(TAG_ALBUM, track->album);
tag->AddItem(TAG_DATE, date);
tag->AddItem(TAG_COMMENT, comment);
tag->time = track->length / 1000;
return tag;
}
struct despotify_session *mpd_despotify_get_session(void)
{
const char *user;
const char *passwd;
bool high_bitrate;
if (g_session)
return g_session;
user = config_get_string(CONF_DESPOTIFY_USER, nullptr);
passwd = config_get_string(CONF_DESPOTIFY_PASSWORD, nullptr);
high_bitrate = config_get_bool(CONF_DESPOTIFY_HIGH_BITRATE, true);
if (user == nullptr || passwd == nullptr) {
LogDebug(despotify_domain,
"disabling despotify because account is not configured");
return nullptr;
}
if (!despotify_init()) {
LogWarning(despotify_domain, "Can't initialize despotify");
return nullptr;
}
g_session = despotify_init_client(callback, nullptr,
high_bitrate, true);
if (!g_session) {
LogWarning(despotify_domain,
"Can't initialize despotify client");
return nullptr;
}
if (!despotify_authenticate(g_session, user, passwd)) {
LogWarning(despotify_domain,
"Can't authenticate despotify session");
despotify_exit(g_session);
return nullptr;
}
return g_session;
}

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2003-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_DESPOTIFY_H
#define MPD_DESPOTIFY_H
struct Tag;
struct despotify_session;
struct ds_track;
extern const class Domain despotify_domain;
/**
* Return the current despotify session.
*
* If the session isn't initialized, this function will initialize
* it and connect to Spotify.
*
* @return a pointer to the despotify session, or nullptr if it can't
* be initialized (e.g., if the configuration isn't supplied)
*/
struct despotify_session *mpd_despotify_get_session(void);
/**
* Create a MPD tags structure from a spotify track
*
* @param track the track to convert
*
* @return a pointer to the filled in tags structure
*/
Tag *
mpd_despotify_tag_from_track(struct ds_track *track);
/**
* Register a despotify callback.
*
* Despotify calls this e.g., when a track ends.
*
* @param cb the callback
* @param cb_data the data to pass to the callback
*
* @return true if the callback could be registered
*/
bool mpd_despotify_register_callback(void (*cb)(struct despotify_session *, int, void *, void *),
void *cb_data);
/**
* Unregister a despotify callback.
*
* @param cb the callback to unregister.
*/
void mpd_despotify_unregister_callback(void (*cb)(struct despotify_session *, int, void *, void *));
#endif

@@ -40,7 +40,10 @@ extern "C" {
inline Directory *
Directory::Allocate(const char *path)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path != nullptr);
#endif
const size_t path_size = strlen(path) + 1;
Directory *directory =

@@ -42,10 +42,6 @@
#include "input/CdioParanoiaInputPlugin.hxx"
#endif
#ifdef ENABLE_DESPOTIFY
#include "input/DespotifyInputPlugin.hxx"
#endif
const InputPlugin *const input_plugins[] = {
&input_plugin_file,
#ifdef ENABLE_ARCHIVE
@@ -62,9 +58,6 @@ const InputPlugin *const input_plugins[] = {
#endif
#ifdef ENABLE_CDIO_PARANOIA
&input_plugin_cdio_paranoia,
#endif
#ifdef ENABLE_DESPOTIFY
&input_plugin_despotify,
#endif
nullptr
};

@@ -155,7 +155,10 @@ InputStream::IsAvailable()
size_t
InputStream::Read(void *ptr, size_t _size, Error &error)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(ptr != nullptr);
#endif
assert(_size > 0);
return plugin.read(this, ptr, _size, error);
@@ -164,7 +167,10 @@ InputStream::Read(void *ptr, size_t _size, Error &error)
size_t
InputStream::LockRead(void *ptr, size_t _size, Error &error)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(ptr != nullptr);
#endif
assert(_size > 0);
const ScopeLock protect(mutex);

@@ -385,11 +385,20 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
if (length > other_length)
length = other_length;
float mix_ratio = chunk->mix_ratio;
if (mix_ratio >= 0)
/* reverse the mix ratio (because the
arguments to pcm_mix() are reversed), but
only if the mix ratio is non-negative; a
negative mix ratio is a MixRamp special
case */
mix_ratio = 1.0 - mix_ratio;
void *dest = ao->cross_fade_buffer.Get(other_length);
memcpy(dest, other_data, other_length);
if (!pcm_mix(dest, data, length,
ao->in_audio_format.format,
1.0 - chunk->mix_ratio)) {
mix_ratio)) {
FormatError(output_domain,
"Cannot cross-fade format %s",
sample_format_to_string(ao->in_audio_format.format));

@@ -69,6 +69,10 @@ spl_global_init(void)
bool
spl_valid_name(const char *name_utf8)
{
if (*name_utf8 == 0)
/* empty name not allowed */
return false;
/*
* Not supporting '/' was done out of laziness, and we should
* really strive to support it in the future.

@@ -23,7 +23,6 @@
#include "playlist/ExtM3uPlaylistPlugin.hxx"
#include "playlist/M3uPlaylistPlugin.hxx"
#include "playlist/XspfPlaylistPlugin.hxx"
#include "playlist/DespotifyPlaylistPlugin.hxx"
#include "playlist/SoundCloudPlaylistPlugin.hxx"
#include "playlist/PlsPlaylistPlugin.hxx"
#include "playlist/AsxPlaylistPlugin.hxx"
@@ -52,9 +51,6 @@ const struct playlist_plugin *const playlist_plugins[] = {
&pls_playlist_plugin,
&asx_playlist_plugin,
&rss_playlist_plugin,
#ifdef ENABLE_DESPOTIFY
&despotify_playlist_plugin,
#endif
#ifdef ENABLE_SOUNDCLOUD
&soundcloud_playlist_plugin,
#endif
@@ -164,12 +160,12 @@ static SongEnumerator *
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
const bool *tried)
{
const char *suffix;
SongEnumerator *playlist = nullptr;
assert(uri != nullptr);
suffix = uri_get_suffix(uri);
UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
if (suffix == nullptr)
return nullptr;
@@ -273,8 +269,6 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri)
{
const char *suffix;
is.LockWaitReady();
const char *const mime = is.GetMimeType();
@@ -284,7 +278,10 @@ playlist_list_open_stream(InputStream &is, const char *uri)
return playlist;
}
suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr;
UriSuffixBuffer suffix_buffer;
const char *suffix = uri != nullptr
? uri_get_suffix(uri, suffix_buffer)
: nullptr;
if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix);
if (playlist != nullptr)

@@ -78,7 +78,10 @@ SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
bool
SongFilter::Item::StringMatch(const char *s) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(s != nullptr);
#endif
if (fold_case) {
char *p = g_utf8_casefold(s, -1);

@@ -186,12 +186,13 @@ zzip_input_seek(InputStream *is, InputPlugin::offset_type offset,
{
ZzipInputStream *zis = (ZzipInputStream *)is;
zzip_off_t ofs = zzip_seek(zis->file, offset, whence);
if (ofs != -1) {
if (ofs < 0) {
error.Set(zzip_domain, "zzip_seek() has failed");
is->offset = ofs;
return true;
return false;
}
return false;
is->offset = ofs;
return true;
}
/* exported structures */

@@ -27,6 +27,7 @@ void
CommandListBuilder::Reset()
{
list.clear();
size = 0;
mode = Mode::DISABLED;
}

@@ -57,7 +57,7 @@ public:
virtual void Close() override;
virtual Song *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(Song *song) const;
void ReturnSong(Song *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -592,7 +592,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
{
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
if (!visit_directory && !visit_playlist && selection.recursive &&
(ServerSupportsSearchBase(connection)
@@ -617,7 +617,7 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
{
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
enum mpd_tag_type tag_type2 = Convert(tag_type);
if (tag_type2 == MPD_TAG_COUNT) {
@@ -657,7 +657,7 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
struct mpd_stats *stats2 =
mpd_run_stats(connection);

@@ -61,7 +61,7 @@ public:
virtual Song *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(Song *song) const;
void ReturnSong(Song *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,

@@ -110,9 +110,9 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
Error error;
if (is.LockSeek(offset, whence, error)) {
LogError(error, "Seek failed");
return is.GetOffset();
} else {
LogError(error, "Seek failed");
return -1;
}
}

@@ -277,20 +277,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
}
uint8_t channels;
uint32_t sample_rate;
#ifdef HAVE_FAAD_LONG
/* neaacdec.h declares all arguments as "unsigned long", but
internally expects uint32_t pointers. To avoid gcc
warnings, use this workaround. */
unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
#else
uint32_t *sample_rate_p = &sample_rate;
#endif
unsigned long sample_rate;
long nbytes = NeAACDecInit(decoder,
/* deconst hack, libfaad requires this */
const_cast<unsigned char *>(data),
length,
sample_rate_p, &channels);
&sample_rate, &channels);
if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream");
return false;

@@ -284,10 +284,13 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
AVFrame *frame,
uint8_t **buffer, int *buffer_size)
{
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start_time_fallback(*stream),
stream->time_base));
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE) {
auto start = start_time_fallback(*stream);
if (packet->pts >= start)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start,
stream->time_base));
}
AVPacket packet2 = *packet;
@@ -383,10 +386,28 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
nbytes -= PADDING;
AVProbeData avpd;
/* new versions of ffmpeg may add new attributes, and leaving
them uninitialized may crash; hopefully, zero-initializing
everything we don't know is ok */
memset(&avpd, 0, sizeof(avpd));
avpd.buf = buffer;
avpd.buf_size = nbytes;
avpd.filename = is.uri.c_str();
#ifdef AVPROBE_SCORE_MIME
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(56, 5, 1)
/* this attribute was added in libav/ffmpeg version 11, but
unfortunately it's "uint8_t" instead of "char", and it's
not "const" - wtf? */
avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType());
#else
/* API problem fixed in FFmpeg 2.5 */
avpd.mime_type = is.GetMimeType();
#endif
#endif
return av_probe_input_format(&avpd, true);
}
@@ -607,7 +628,7 @@ static const char *const ffmpeg_suffixes[] = {
"mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+",
"mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu",
"mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv",
"ogx", "oma", "ogg", "omg", "psp", "pva", "qcp", "qt", "r3d", "ra",
"ogx", "oma", "ogg", "omg", "opus", "psp", "pva", "qcp", "qt", "r3d", "ra",
"ram", "rl2", "rm", "rmvb", "roq", "rpl", "rvc", "shn", "smk", "snd",
"sol", "son", "spx", "str", "swf", "tgi", "tgq", "tgv", "thp", "ts",
"tsp", "tta", "xa", "xvid", "uv", "uv2", "vb", "vid", "vob", "voc",
@@ -630,6 +651,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/8svx",
"audio/16sv",
"audio/aac",
"audio/aacp",
"audio/ac3",
"audio/aiff"
"audio/amr",
@@ -640,6 +662,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/mpeg",
"audio/musepack",
"audio/ogg",
"audio/opus",
"audio/qcelp",
"audio/vorbis",
"audio/vorbis+ogg",

@@ -141,7 +141,7 @@ get_remote_uid(int fd)
socklen_t len = sizeof (cred);
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
return 0;
return -1;
return cred.uid;
#else

@@ -52,10 +52,11 @@ public:
children.emplace_back(name, filter);
}
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error) override;
private:
/**

@@ -34,10 +34,11 @@ class NormalizeFilter final : public Filter {
PcmBuffer buffer;
public:
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error) override;
};
static Filter *

@@ -116,10 +116,11 @@ public:
*/
void Update();
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error) override;
};
void

@@ -120,10 +120,11 @@ public:
*/
bool Configure(const config_param &param, Error &error);
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error) override;
};
bool

@@ -57,10 +57,10 @@ public:
volume = _volume;
}
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error);
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
const void *FilterPCM(const void *src, size_t src_size,
size_t *dest_size_r, Error &error) override;
};
static constexpr Domain volume_domain("pcm_volume");

@@ -46,7 +46,11 @@ AllocatedPath::Build(const_pointer a, const_pointer b)
AllocatedPath
AllocatedPath::FromUTF8(const char *path_utf8)
{
return AllocatedPath(Donate(), ::PathFromUTF8(path_utf8));
char *path = ::PathFromUTF8(path_utf8);
if (path == nullptr)
return AllocatedPath::Null();
return AllocatedPath(Donate(), path);
}
AllocatedPath

@@ -79,7 +79,10 @@ GetFSCharset()
std::string
PathToUTF8(const char *path_fs)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_fs != nullptr);
#endif
if (fs_charset.empty())
return std::string(path_fs);
@@ -109,7 +112,10 @@ PathToUTF8(const char *path_fs)
char *
PathFromUTF8(const char *path_utf8)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_utf8 != nullptr);
#endif
if (fs_charset.empty())
return g_strdup(path_utf8);

@@ -25,7 +25,10 @@
const char *
PathTraits::GetBaseUTF8(const char *p)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
const char *slash = strrchr(p, SEPARATOR_UTF8);
return slash != nullptr
@@ -36,7 +39,10 @@ PathTraits::GetBaseUTF8(const char *p)
std::string
PathTraits::GetParentUTF8(const char *p)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
const char *slash = strrchr(p, SEPARATOR_UTF8);
return slash != nullptr

@@ -983,10 +983,10 @@ input_curl_easy_init(struct input_curl *c, Error &error)
input_curl_writefunction);
curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c);
curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(c->easy, CURLOPT_NETRC, 1);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1l);
curl_easy_setopt(c->easy, CURLOPT_NETRC, 1l);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5l);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l);
curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l);

@@ -1,234 +0,0 @@
/*
* Copyright (C) 2011-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "DespotifyInputPlugin.hxx"
#include "DespotifyUtils.hxx"
#include "InputStream.hxx"
#include "InputPlugin.hxx"
#include "tag/Tag.hxx"
#include "Log.hxx"
extern "C" {
#include <despotify.h>
}
#include <glib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
struct DespotifyInputStream {
InputStream base;
struct despotify_session *session;
struct ds_track *track;
Tag *tag;
struct ds_pcm_data pcm;
size_t len_available;
bool eof;
DespotifyInputStream(const char *uri,
Mutex &mutex, Cond &cond,
despotify_session *_session,
ds_track *_track)
:base(input_plugin_despotify, uri, mutex, cond),
session(_session), track(_track),
tag(mpd_despotify_tag_from_track(track)),
len_available(0), eof(false) {
memset(&pcm, 0, sizeof(pcm));
/* Despotify outputs pcm data */
base.mime = "audio/x-mpd-cdda-pcm";
base.ready = true;
}
~DespotifyInputStream() {
delete tag;
despotify_free_track(track);
}
};
static void
refill_buffer(DespotifyInputStream *ctx)
{
/* Wait until there is data */
while (1) {
int rc = despotify_get_pcm(ctx->session, &ctx->pcm);
if (rc == 0 && ctx->pcm.len) {
ctx->len_available = ctx->pcm.len;
break;
}
if (ctx->eof == true)
break;
if (rc < 0) {
LogDebug(despotify_domain, "despotify_get_pcm error");
ctx->eof = true;
break;
}
/* Wait a while until next iteration */
usleep(50 * 1000);
}
}
static void callback(gcc_unused struct despotify_session* ds,
int sig, gcc_unused void* data, void* callback_data)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)callback_data;
switch (sig) {
case DESPOTIFY_NEW_TRACK:
break;
case DESPOTIFY_TIME_TELL:
break;
case DESPOTIFY_TRACK_PLAY_ERROR:
LogWarning(despotify_domain, "Track play error");
ctx->eof = true;
ctx->len_available = 0;
break;
case DESPOTIFY_END_OF_PLAYLIST:
ctx->eof = true;
FormatDebug(despotify_domain, "End of playlist: %d", ctx->eof);
break;
}
}
static InputStream *
input_despotify_open(const char *url,
Mutex &mutex, Cond &cond,
gcc_unused Error &error)
{
struct despotify_session *session;
struct ds_link *ds_link;
struct ds_track *track;
if (!g_str_has_prefix(url, "spt://"))
return nullptr;
session = mpd_despotify_get_session();
if (!session)
return nullptr;
ds_link = despotify_link_from_uri(url + 6);
if (!ds_link) {
FormatDebug(despotify_domain, "Can't find %s", url);
return nullptr;
}
if (ds_link->type != LINK_TYPE_TRACK) {
despotify_free_link(ds_link);
return nullptr;
}
track = despotify_link_get_track(session, ds_link);
despotify_free_link(ds_link);
if (!track)
return nullptr;
DespotifyInputStream *ctx =
new DespotifyInputStream(url, mutex, cond,
session, track);
if (!mpd_despotify_register_callback(callback, ctx)) {
delete ctx;
return nullptr;
}
if (despotify_play(ctx->session, ctx->track, false) == false) {
mpd_despotify_unregister_callback(callback);
delete ctx;
return nullptr;
}
return &ctx->base;
}
static size_t
input_despotify_read(InputStream *is, void *ptr, size_t size,
gcc_unused Error &error)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)is;
size_t to_cpy = size;
if (ctx->len_available == 0)
refill_buffer(ctx);
if (ctx->len_available < size)
to_cpy = ctx->len_available;
memcpy(ptr, ctx->pcm.buf, to_cpy);
ctx->len_available -= to_cpy;
is->offset += to_cpy;
return to_cpy;
}
static void
input_despotify_close(InputStream *is)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)is;
mpd_despotify_unregister_callback(callback);
delete ctx;
}
static bool
input_despotify_eof(InputStream *is)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)is;
return ctx->eof;
}
static Tag *
input_despotify_tag(InputStream *is)
{
DespotifyInputStream *ctx = (DespotifyInputStream *)is;
Tag *tag = ctx->tag;
ctx->tag = nullptr;
return tag;
}
const InputPlugin input_plugin_despotify = {
"spt",
nullptr,
nullptr,
input_despotify_open,
input_despotify_close,
nullptr,
nullptr,
input_despotify_tag,
nullptr,
input_despotify_read,
input_despotify_eof,
nullptr,
};

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2011-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef INPUT_DESPOTIFY_HXX
#define INPUT_DESPOTIFY_HXX
extern const struct InputPlugin input_plugin_despotify;
#endif

@@ -54,9 +54,6 @@ static const char *remoteUrlPrefixes[] = {
#endif
#ifdef ENABLE_CDIO_PARANOIA
"cdda://",
#endif
#ifdef ENABLE_DESPOTIFY
"spt://",
#endif
NULL
};

@@ -28,7 +28,7 @@ struct notify {
Cond cond;
bool pending;
#ifndef WIN32
#if !defined(WIN32) && !defined(__NetBSD__)
constexpr
#endif
notify():pending(false) {}

@@ -46,7 +46,7 @@ class RoarOutput {
struct roar_connection con;
struct roar_audio_info info;
mutable Mutex mutex;
volatile bool alive;
bool alive;
public:
RoarOutput()

@@ -114,7 +114,7 @@ ShoutOutput::Configure(const config_param &param, Error &error)
if (!audio_format.IsFullyDefined()) {
error.Set(config_domain,
"Need full audio format specification");
return nullptr;
return false;
}
const char *host = require_block_string(param, "host");

@@ -1,145 +0,0 @@
/*
* Copyright (C) 2011-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "DespotifyPlaylistPlugin.hxx"
#include "DespotifyUtils.hxx"
#include "PlaylistPlugin.hxx"
#include "MemorySongEnumerator.hxx"
#include "tag/Tag.hxx"
#include "Song.hxx"
#include "Log.hxx"
extern "C" {
#include <despotify.h>
}
#include <string.h>
#include <stdlib.h>
static void
add_song(std::forward_list<SongPointer> &songs, struct ds_track *track)
{
const char *dsp_scheme = despotify_playlist_plugin.schemes[0];
Song *song;
char uri[128];
char *ds_uri;
/* Create a spt://... URI for MPD */
snprintf(uri, sizeof(uri), "%s://", dsp_scheme);
ds_uri = uri + strlen(dsp_scheme) + 3;
if (despotify_track_to_uri(track, ds_uri) != ds_uri) {
/* Should never really fail, but let's be sure */
FormatDebug(despotify_domain,
"Can't add track %s", track->title);
return;
}
song = Song::NewRemote(uri);
song->tag = mpd_despotify_tag_from_track(track);
songs.emplace_front(song);
}
static bool
parse_track(struct despotify_session *session,
std::forward_list<SongPointer> &songs,
struct ds_link *link)
{
struct ds_track *track = despotify_link_get_track(session, link);
if (track == nullptr)
return false;
add_song(songs, track);
return true;
}
static bool
parse_playlist(struct despotify_session *session,
std::forward_list<SongPointer> &songs,
struct ds_link *link)
{
ds_playlist *playlist = despotify_link_get_playlist(session, link);
if (playlist == nullptr)
return false;
for (ds_track *track = playlist->tracks; track != nullptr;
track = track->next)
add_song(songs, track);
return true;
}
static SongEnumerator *
despotify_playlist_open_uri(const char *url,
gcc_unused Mutex &mutex, gcc_unused Cond &cond)
{
despotify_session *session = mpd_despotify_get_session();
if (session == nullptr)
return nullptr;
/* Get link without spt:// */
ds_link *link =
despotify_link_from_uri(url + strlen(despotify_playlist_plugin.schemes[0]) + 3);
if (link == nullptr) {
FormatDebug(despotify_domain, "Can't find %s\n", url);
return nullptr;
}
std::forward_list<SongPointer> songs;
bool parse_result;
switch (link->type) {
case LINK_TYPE_TRACK:
parse_result = parse_track(session, songs, link);
break;
case LINK_TYPE_PLAYLIST:
parse_result = parse_playlist(session, songs, link);
break;
default:
parse_result = false;
break;
}
despotify_free_link(link);
if (!parse_result)
return nullptr;
songs.reverse();
return new MemorySongEnumerator(std::move(songs));
}
static const char *const despotify_schemes[] = {
"spt",
nullptr
};
const struct playlist_plugin despotify_playlist_plugin = {
"despotify",
nullptr,
nullptr,
despotify_playlist_open_uri,
nullptr,
despotify_schemes,
nullptr,
nullptr,
};

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2011-2013 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_HXX
#define MPD_PLAYLIST_DESPOTIFY_PLAYLIST_PLUGIN_HXX
extern const struct playlist_plugin despotify_playlist_plugin;
#endif

@@ -171,14 +171,14 @@ static const char *const embcue_playlist_suffixes[] = {
};
const struct playlist_plugin embcue_playlist_plugin = {
"cue",
"embcue",
nullptr,
nullptr,
embcue_playlist_open_uri,
nullptr,
nullptr,
embcue_playlist_suffixes,
nullptr,
nullptr,
};

@@ -135,7 +135,8 @@ ExtM3uPlaylist::NextSong()
static const char *const extm3u_suffixes[] = {
"m3u",
NULL
"m3u8",
nullptr
};
static const char *const extm3u_mime_types[] = {

@@ -61,6 +61,7 @@ M3uPlaylist::NextSong()
static const char *const m3u_suffixes[] = {
"m3u",
"m3u8",
nullptr
};

@@ -81,7 +81,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
/* compatibility with older MPD versions: specifying
"-1" makes MPD display the whole list */
*value_r1 = 0;
*value_r2 = std::numeric_limits<unsigned>::max();
*value_r2 = std::numeric_limits<int>::max();
return true;
}
@@ -108,7 +108,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
}
if (test == test2)
value = std::numeric_limits<unsigned>::max();
value = std::numeric_limits<int>::max();
if (value < 0) {
command_error(client, ACK_ERROR_ARG,

@@ -40,8 +40,8 @@ MonotonicClockMS(void)
if (base.denom == 0)
(void)mach_timebase_info(&base);
return (unsigned)((mach_absolute_time() * base.numer)
/ (1000000 * base.denom));
return (unsigned)(((double)mach_absolute_time() * base.numer)
/ base.denom / 1000000);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -82,8 +82,8 @@ MonotonicClockUS(void)
if (base.denom == 0)
(void)mach_timebase_info(&base);
return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer)
/ (1000 * (uint64_t)base.denom);
return (uint64_t)(((double)mach_absolute_time() * base.numer)
/ base.denom / 1000);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);

@@ -77,7 +77,10 @@ TagBuilder::Commit()
inline void
TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
assert(length > 0);
char *p = FixTagString(value, length);
@@ -98,7 +101,10 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
void
TagBuilder::AddItem(TagType type, const char *value, size_t length)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
if (length == 0 || ignore_tag_items[type])
return;
@@ -109,7 +115,10 @@ TagBuilder::AddItem(TagType type, const char *value, size_t length)
void
TagBuilder::AddItem(TagType type, const char *value)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
AddItem(type, value, strlen(value));
}

@@ -33,7 +33,7 @@ patch_utf8(const char *src, size_t length, const gchar *end)
{
/* duplicate the string, and replace invalid bytes in that
buffer */
char *dest = g_strdup(src);
char *dest = g_strndup(src, length);
do {
dest[end - src] = '?';

@@ -75,7 +75,7 @@ public:
#ifdef WIN32
return ::GetCurrentThreadId();
#else
return ::pthread_self();
return pthread_self();
#endif
}
@@ -84,7 +84,7 @@ public:
#ifdef WIN32
return id == other.id;
#else
return ::pthread_equal(id, other.id);
return pthread_equal(id, other.id);
#endif
}

@@ -41,7 +41,21 @@ class PosixCond {
pthread_cond_t cond;
public:
#ifdef __NetBSD__
/* NetBSD's PTHREAD_COND_INITIALIZER is not compatible with
"constexpr" */
PosixCond() {
pthread_cond_init(&cond, nullptr);
}
~PosixCond() {
pthread_cond_destroy(&cond);
}
#else
/* optimized constexpr constructor for sane POSIX
implementations */
constexpr PosixCond():cond(PTHREAD_COND_INITIALIZER) {}
#endif
PosixCond(const PosixCond &other) = delete;
PosixCond &operator=(const PosixCond &other) = delete;

@@ -41,7 +41,21 @@ class PosixMutex {
pthread_mutex_t mutex;
public:
#ifdef __NetBSD__
/* NetBSD's PTHREAD_MUTEX_INITIALIZER is not compatible with
"constexpr" */
PosixMutex() {
pthread_mutex_init(&mutex, nullptr);
}
~PosixMutex() {
pthread_mutex_destroy(&mutex);
}
#else
/* optimized constexpr constructor for sane POSIX
implementations */
constexpr PosixMutex():mutex(PTHREAD_MUTEX_INITIALIZER) {}
#endif
PosixMutex(const PosixMutex &other) = delete;
PosixMutex &operator=(const PosixMutex &other) = delete;

@@ -43,24 +43,30 @@ gcc_pure gcc_nonnull_all
static inline bool
StringEqualsCaseASCII(const char *a, const char *b)
{
assert(a != nullptr);
assert(b != nullptr);
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(a != nullptr);
assert(b != nullptr);
#endif
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strcasecmp(a, b) == 0;
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strcasecmp(a, b) == 0;
}
gcc_pure gcc_nonnull_all
static inline bool
StringEqualsCaseASCII(const char *a, const char *b, size_t n)
{
assert(a != nullptr);
assert(b != nullptr);
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(a != nullptr);
assert(b != nullptr);
#endif
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strncasecmp(a, b, n) == 0;
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strncasecmp(a, b, n) == 0;
}
#endif

@@ -35,7 +35,7 @@
#include <new>
#include <utility>
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
#if GCC_OLDER_THAN(4,8)
#include <type_traits>
#endif
@@ -54,7 +54,7 @@
*/
template<class T>
class Manual {
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
#if GCC_OLDER_THAN(4,8)
/* no alignas() on gcc < 4.8: apply worst-case fallback */
__attribute__((aligned(8)))
#else

@@ -44,6 +44,23 @@ uri_get_suffix(const char *uri)
return suffix;
}
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
{
const char *suffix = uri_get_suffix(uri);
if (suffix == nullptr)
return nullptr;
const char *q = strchr(suffix, '?');
if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
memcpy(buffer.data, suffix, q - suffix);
buffer.data[q - suffix] = 0;
suffix = buffer.data;
}
return suffix;
}
static const char *
verify_uri_segment(const char *p)
{
@@ -111,8 +128,11 @@ uri_remove_auth(const char *uri)
bool
uri_is_child(const char *parent, const char *child)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(parent != nullptr);
assert(child != nullptr);
#endif
const size_t parent_length = strlen(parent);
return memcmp(parent, child, parent_length) == 0 &&

@@ -35,6 +35,17 @@ gcc_pure
const char *
uri_get_suffix(const char *uri);
struct UriSuffixBuffer {
char data[8];
};
/**
* Returns the file name suffix, ignoring the query string.
*/
gcc_pure
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer);
/**
* Returns true if this is a safe "local" URI:
*

@@ -30,6 +30,10 @@
#pragma GCC diagnostic ignored "-Wlanguage-extension-token"
#endif
#if defined(__GNUC__) && __GNUC__ >= 5
#pragma GCC diagnostic ignored "-Winvalid-offsetof"
#endif
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.

@@ -175,8 +175,10 @@ decoder_replay_gain(gcc_unused Decoder &decoder,
}
void
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp)
{
fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
mix_ramp.GetStart(), mix_ramp.GetEnd());
}
int main(int argc, char **argv)

62
test/test_protocol.cxx Normal file

@@ -0,0 +1,62 @@
#include "config.h"
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
#include "Compiler.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <stdlib.h>
static enum ack last_error = ack(-1);
void
command_error(gcc_unused Client &client, enum ack error,
gcc_unused const char *fmt, ...)
{
last_error = error;
}
class ArgParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ArgParserTest);
CPPUNIT_TEST(TestRange);
CPPUNIT_TEST_SUITE_END();
public:
void TestRange();
};
void
ArgParserTest::TestRange()
{
Client &client = *(Client *)nullptr;
unsigned a, b;
CPPUNIT_ASSERT(check_range(client, &a, &b, "1"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(2u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(5u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT(b >= 999999u);
CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2"));
CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error);
}
CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest);
int
main(gcc_unused int argc, gcc_unused char **argv)
{
CppUnit::TextUi::TestRunner runner;
auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
}

@@ -33,6 +33,25 @@ public:
uri_get_suffix(".jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/.jpg"));
/* the first overload does not eliminate the query
string */
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
"jpg?query_string"));
/* ... but the second one does */
UriSuffixBuffer buffer;
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
buffer),
"jpg"));
/* repeat some of the above tests with the second overload */
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/bar", buffer));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo.jpg/bar", buffer));
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
"jpg"));
}
void TestRemoveAuth() {