Compare commits

...

46 Commits

Author SHA1 Message Date
Max Kellermann
3bbcda917c release v0.19.21 2016-12-13 10:54:04 +01:00
Max Kellermann
7e43fb79af Makefile.am: fix mpd.socket path in EXTRA_DIST 2016-12-13 10:53:41 +01:00
Max Kellermann
eb2b567da6 NEWS: fix version number 2016-12-13 10:45:53 +01:00
Max Kellermann
ab332d7b2e systemd: add user unit
The user unit omits the "ProtectKernelModules" setting which fails
with modular kernels:

 Failed at step CAPABILITIES spawning /usr/bin/mpd: Operation not permitted

It is unfortunate that systemd (version 232) is unable to reduce its
own capabilities, because this requires us to split system and user
units.

 https://bugs.musicpd.org/view.php?id=4608
2016-12-13 10:24:10 +01:00
Max Kellermann
53e22b81ef systemd: add "system" sub directory 2016-12-13 10:24:10 +01:00
Max Kellermann
3fc9d50adb doc/user: fix --with-systemdsystemunitdir example 2016-12-13 10:24:10 +01:00
Max Kellermann
c2da6dd45b test/test_queue_priority: fix unit test failure after recent "setprio" change 2016-12-13 08:36:42 +01:00
Max Kellermann
7146f825b2 decoder/ffmpeg: fix double free bug
From the avformat_open_input() API documentation:

 "Note that a user-supplied AVFormatContext will be freed on failure."

https://bugs.musicpd.org/view.php?id=4607
2016-12-13 08:34:05 +01:00
Max Kellermann
f61a5f5200 configure.ac: prepare for 0.19.21 2016-12-13 08:31:21 +01:00
Max Kellermann
fef45d469c release v0.19.20 2016-12-09 20:02:07 +01:00
Max Kellermann
e7353ec7e7 Queue: "setprio" re-enqueues old song if priority has been raised
This commit changes a minor queue priority design to something which
makes a little bit more sense.

Previously, a song that had already been played would only be
re-enqueued if its priority had just been raised above the current
song's.  This means that if it was already above, it was not
re-enqueued.  That is a surprising behavior, because users expect a
song to be played when its priority is raised.

Now the song is always re-enqueued if its priority is raised (and
above the current song's - no matter if it has already been above
before).

 https://bugs.musicpd.org/view.php?id=4592
2016-12-09 13:02:26 +01:00
Max Kellermann
e3237f057d systemd: more paranoid security settings 2016-12-09 10:41:44 +01:00
Florian Schlichting
54d5d9d1cc systemd: protect /usr when running under systemd 2016-12-09 10:41:44 +01:00
Clément B
31d9aebf0b systemd: also disable mpd.socket when disabling mpd.service
e.g. when running 'update-rc.d mpd disable'
2016-12-09 10:41:43 +01:00
Max Kellermann
301abac0c1 LogInit: initialize out_fd properly to avoid closing stdin 2016-12-04 20:13:37 +01:00
Max Kellermann
7019f6bea4 decoder/pcm: round buffer size down to nearest frame size
https://bugs.musicpd.org/view.php?id=4599
2016-11-17 21:58:27 +01:00
Wieland Hoffmann
8bde47280a doc/protocol: Turn the link to the UTF-8 FAQ into a ulink element 2016-11-16 21:25:45 +01:00
Wieland Hoffmann
521c6da830 doc/protocol: UTF=8 → UTF-8 2016-11-16 21:25:40 +01:00
Max Kellermann
5c3e55b5b1 {input,output}/alsa: fix gcc 7.0 -Wimplicit-fallthrough 2016-11-16 19:50:38 +01:00
Max Kellermann
1859ba5ec8 output/winmm: 8 bit playback is not supported
Everything must be S16.
2016-11-07 08:53:57 +01:00
Max Kellermann
ee026386e5 storage/Composite: avoid setting the error twice
If an error has already been set by f.directory->storage->GetInfo(),
don't set it again.
2016-10-27 21:26:55 +02:00
Max Kellermann
49c04ccfc7 decoder/sidplay: fix playback speed with libsidplayfp
https://bugs.musicpd.org/view.php?id=4577
2016-10-27 20:25:19 +02:00
Max Kellermann
11ba44870b decoder/sidplay: simplify seek loop 2016-10-27 20:25:12 +02:00
Max Kellermann
f9a64d24bf storage/Composite: eliminate the second FindStorage() overload
It was used in a wrong way, which did not deal with errors
consistently.  And if that's wrong, there is no need for FindStorage()
at all - let's remove it and the confusion around it.
2016-10-27 19:55:20 +02:00
Max Kellermann
e1a8dcfcc8 storage/Composite: add FindStorage() API documentation 2016-10-27 19:55:08 +02:00
Max Kellermann
1ee0e29974 storage/Composite: fix documentation typo 2016-10-27 17:12:24 +02:00
Max Kellermann
77a9940461 decoder/ffmpeg: ignore empty packets
An empty packet would be a command for avcodec_send_packet() to
finalize the codec.

Fixes https://bugs.musicpd.org/view.php?id=4588
2016-10-26 18:29:07 +02:00
Max Kellermann
9c1c180ae0 tag/Item: declare value[] to have only one element
By declaring the variable-length array to have a nominal size of 1,
struct TagPoolSlot shrinks from 24 bytes to 16 bytes, because "ref"
and "item" now both fit in one machine word.
2016-10-26 18:26:01 +02:00
Max Kellermann
06682bd2a9 tag/Item: remove "packed" attribute, add static_assert on alignment instead
The "packed" attribute triggers a clang 4.0 warning, and it's not
necessary.  All we want is correct allocation of this
dynamically-sized struct.
2016-10-26 18:24:16 +02:00
dennisschagt
7c251fe190 Fix comment in mpdconf.example ("can setting can" -> "setting can") 2016-10-20 15:02:36 +02:00
Max Kellermann
a85455fb3f configure.ac: prepare for 0.19.20 2016-09-27 22:04:46 +02:00
Max Kellermann
d4db873716 release v0.19.19 2016-08-23 10:19:10 +02:00
Thomas Klausner
de0752fd56 system/ByteOrder: gssupport non-x86 NetBSD 2016-08-23 10:15:54 +02:00
Max Kellermann
4204d4928b decoder/ffmpeg: no avcodec_parameters_to_context() with FFmpeg 3.0
This function exists since FFmpeg 3.1.  Fix a build failure with
FFmpeg 3.0.
2016-08-23 10:15:54 +02:00
Max Kellermann
05de0ecec3 decoder/ffmpeg: call avcodec_parameters_to_context()
These bug reports describe problems with some FFmpeg codecs:

 https://bugs.musicpd.org/view.php?id=4564
 https://bugs.musicpd.org/view.php?id=4568
 https://bugs.musicpd.org/view.php?id=4572

According to the FFmpeg bug tracker, a call to
avcodec_parameters_to_context() is required after
avcodec_alloc_context3():

 https://trac.ffmpeg.org/ticket/5781

This requirement was previously undocumented.
2016-08-23 09:59:25 +02:00
Max Kellermann
b05beb000f Compiler.h: work around clang 3.9 warning -Wexpansion-to-defined
Check {GCC,CLANG}_VERSION==0 or >0 instead of using defined(), which
may render undefined behavior.
2016-08-23 09:59:25 +02:00
Max Kellermann
093abaad29 Compiler.h: always define CLANG_VERSION 2016-08-23 09:54:09 +02:00
Max Kellermann
e84e4169f9 Compiler.h: remove redundant __GNUC__ check
GCC_VERSION>0 implies defined(__GNUC__).
2016-08-23 09:53:17 +02:00
Max Kellermann
cd6c5cfd4c Compiler.h: exclude clang from GCC_CHECK_VERSION() 2016-08-23 09:52:14 +02:00
Max Kellermann
b855f2fcc2 Chrono: use macro GCC_OLDER_THAN() 2016-08-23 09:51:41 +02:00
Max Kellermann
ba69ade024 Compiler.h: add macro CLANG_OR_GCC_VERSION() 2016-08-23 09:48:58 +02:00
Max Kellermann
a546bfe7d9 decoder/wildmidi: support libWildMidi 0.4 2016-08-15 10:08:35 +02:00
Max Kellermann
25deae6cc7 decoder/wildmidi: move code to wildmidi_output() 2016-08-15 10:07:08 +02:00
Nils Schneider
62000670e3 Support S24_P32/S32/FLOAT sample formats on Pulse
This is based on a patch from Ian Scott in 2014. It was never committed,
so I figured I'd fix the outstanding issue and resubmit it.

https://www.mail-archive.com/mpd-devel%40musicpd.org/msg00139.html
2016-08-15 10:02:29 +02:00
Max Kellermann
ac49043fbb output/pulse: move variable declaration down 2016-08-15 10:02:22 +02:00
Max Kellermann
37a7ca7f14 configure.ac: prepare for 0.19.19 2016-08-15 10:00:03 +02:00
37 changed files with 310 additions and 122 deletions

2
.gitignore vendored

@@ -35,7 +35,7 @@ tags
/mkinstalldirs
/build
/src/mpd
/systemd/mpd.service
/systemd/system/mpd.service
/stamp-h1
/src/dsd2pcm/dsd2pcm

@@ -1449,8 +1449,13 @@ FILTER_LIBS = \
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
systemd/mpd.socket \
systemd/mpd.service
systemd/system/mpd.socket \
systemd/system/mpd.service
endif
if HAVE_SYSTEMD_USER
systemduserunit_DATA = \
systemd/user/mpd.service
endif
@@ -2166,7 +2171,7 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
$(wildcard $(srcdir)/scripts/*.rb) \
$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
$(wildcard $(srcdir)/doc/include/*.xml) \
systemd/mpd.socket \
systemd/system/mpd.socket \
android/AndroidManifest.xml \
android/build.py \
android/custom_rules.xml \

27
NEWS

@@ -1,3 +1,30 @@
ver 0.19.21 (2016/12/13)
* decoder
- ffmpeg: fix crash bug
* fix unit test failure after recent "setprio" change
* systemd: add user unit
ver 0.19.20 (2016/12/09)
* protocol
- "setprio" re-enqueues old song if priority has been raised
* decoder
- ffmpeg: ignore empty packets
- pcm: fix corruption bug with partial frames (after short read)
- sidplay: fix playback speed with libsidplayfp
* output
- winmm: fix 8 bit playback
* fix gcc 7.0 -Wimplicit-fallthrough
* systemd: paranoid security settings
ver 0.19.19 (2016/08/23)
* decoder
- ffmpeg: bug fix for FFmpeg 3.1 support
- wildmidi: support libWildMidi 0.4
* output
- pulse: support 32 bit, 24 bit and floating point playback
* support non-x86 NetBSD
* fix clang 3.9 warnings
ver 0.19.18 (2016/08/05)
* decoder
- ffmpeg: fix crash with older FFmpeg versions (< 3.0)

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.19.18, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.19.21, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=19
VERSION_REVISION=18
VERSION_REVISION=21
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -52,6 +52,22 @@ if test "x$with_systemdsystemunitdir" != xno; then
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
AC_ARG_WITH([systemduserunitdir],
AS_HELP_STRING([--with-systemduserunitdir=DIR], [Directory for systemd service files]),
[], [with_systemduserunitdir=no])
if test "x$with_systemduserunitdir" = xyes; then
AC_MSG_CHECKING(for systemd)
with_systemduserunitdir=$($PKG_CONFIG --variable=systemduserunitdir systemd)
if test -z "$with_systemduserunitdir"; then
AC_MSG_ERROR([Failed to detect systemd])
fi
AC_MSG_RESULT([$with_systemduserunitdir])
fi
if test "x$with_systemduserunitdir" != xno; then
AC_SUBST([systemduserunitdir], [$with_systemduserunitdir])
fi
AM_CONDITIONAL(HAVE_SYSTEMD_USER, [test -n "$with_systemduserunitdir" -a "x$with_systemduserunitdir" != xno ])
dnl ---------------------------------------------------------------------------
dnl Declare Variables
dnl ---------------------------------------------------------------------------
@@ -1905,7 +1921,8 @@ dnl Generate files
dnl ---------------------------------------------------------------------------
AC_CONFIG_FILES(Makefile)
AC_CONFIG_FILES(doc/doxygen.conf)
AC_CONFIG_FILES(systemd/mpd.service)
AC_CONFIG_FILES(systemd/system/mpd.service)
AC_CONFIG_FILES(systemd/user/mpd.service)
AC_OUTPUT
echo 'MPD is ready for compilation, type "make" to begin.'

@@ -164,7 +164,7 @@
# Permissions #################################################################
#
# If this setting is set, MPD will require password authorization. The password
# can setting can be specified multiple times for different password profiles.
# setting can be specified multiple times for different password profiles.
#
#password "password@read,add,control,admin"
#

@@ -66,8 +66,8 @@
<function>strcpy</function> just fine with UTF-8 encoded
strings. For example: <returnvalue>OK</returnvalue> encoded in
UTF-8 is simply <returnvalue>OK</returnvalue>. For more
information on UTF=8:
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
information on UTF-8:
<ulink url="http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8"/>)
</para>
</section>

@@ -151,7 +151,7 @@ apt-get install g++ \
<application>systemd</application> unit files: a "service"
unit and a "socket" unit. These will only be installed when
<application>MPD</application> was configured with
<parameter>--with-systemdsystemunitdir=/lib/systemd</parameter>.
<parameter>--with-systemdsystemunitdir=/lib/systemd/system</parameter>.
</para>
<para>
@@ -167,6 +167,33 @@ systemctl start mpd.socket</programlisting>
<varname>port</varname> settings.
</para>
</section>
<section id="systemd_user">
<title><filename>systemd</filename> user unit</title>
<para>
You can launch <application>MPD</application> as a
<filename>systemd</filename> user unit. The service file will
only be installed when <application>MPD</application> was
configured with
<parameter>--with-systemduserunitdir=/usr/lib/systemd/user</parameter>
or
<parameter>--with-systemduserunitdir=$HOME/.local/share/systemd/user</parameter>.
</para>
<para>
Once the user unit is installed, you can start and stop
<application>MPD</application> like any other service:
</para>
<programlisting>systemctl --user start mpd</programlisting>
<para>
To auto-start <application>MPD</application> upon login, type:
</para>
<programlisting>systemctl --user enable mpd</programlisting>
</section>
</chapter>
<chapter id="config">

@@ -26,7 +26,7 @@
#include <utility>
#include <cstdint>
#if defined(__GNUC__) && !GCC_CHECK_VERSION(4,7) && !defined(__clang__)
#if GCC_OLDER_THAN(4,7)
/* std::chrono::duration operators are "constexpr" since gcc 4.7 */
#define chrono_constexpr gcc_pure
#else

@@ -28,19 +28,36 @@
#define GCC_VERSION 0
#endif
#ifdef __clang__
# define CLANG_VERSION GCC_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
#elif defined(__GNUC__)
# define CLANG_VERSION 0
#endif
/**
* Are we building with the specified version of gcc (not clang or any
* other compiler) or newer?
*/
#define GCC_CHECK_VERSION(major, minor) \
(defined(__GNUC__) && GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
(CLANG_VERSION == 0 && \
GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
/**
* Are we building with clang (any version) or at least the specified
* gcc version?
*/
#define CLANG_OR_GCC_VERSION(major, minor) \
(CLANG_VERSION > 0 || GCC_CHECK_VERSION(major, minor))
/**
* 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 > 0 && CLANG_VERSION == 0 && \
GCC_VERSION < GCC_MAKE_VERSION(major, minor, 0))
#ifdef __clang__
# 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
@@ -56,10 +73,9 @@
* 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))
(CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
#if GCC_CHECK_VERSION(4,0)
#if CLANG_OR_GCC_VERSION(4,0)
/* GCC 4.x */
@@ -119,7 +135,7 @@
#endif
#if GCC_CHECK_VERSION(4,3)
#if CLANG_OR_GCC_VERSION(4,3)
#define gcc_hot __attribute__((hot))
#define gcc_cold __attribute__((cold))
@@ -131,7 +147,7 @@
#endif /* ! GCC_UNUSED >= 40300 */
#if GCC_CHECK_VERSION(4,6) && !defined(__clang__)
#if GCC_CHECK_VERSION(4,6)
#define gcc_flatten __attribute__((flatten))
#else
#define gcc_flatten
@@ -140,7 +156,7 @@
#ifndef __cplusplus
/* plain C99 has "restrict" */
#define gcc_restrict restrict
#elif GCC_CHECK_VERSION(4,0)
#elif CLANG_OR_GCC_VERSION(4,0)
/* "__restrict__" is a GCC extension for C++ */
#define gcc_restrict __restrict__
#else
@@ -158,7 +174,7 @@
#define final
#endif
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
#define gcc_alignas(T, fallback) alignas(T)
#else
#define gcc_alignas(T, fallback) gcc_aligned(fallback)

@@ -51,7 +51,7 @@ static constexpr Domain log_domain("log");
#ifndef ANDROID
static int out_fd;
static int out_fd = -1;
static AllocatedPath out_path = AllocatedPath::Null();
static void redirect_logs(int fd)

@@ -46,7 +46,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
for (const auto &item : tag) {
switch (item.type) {
case TAG_ARTIST:
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
artists.emplace(item.value);
#else
artists.insert(item.value);
@@ -54,7 +54,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
break;
case TAG_ALBUM:
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
albums.emplace(item.value);
#else
albums.insert(item.value);

@@ -749,7 +749,7 @@ UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection,
const char *value = dirent.tag.GetValue(tag);
if (value != nullptr) {
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
values.emplace(value);
#else
values.insert(value);

@@ -71,7 +71,6 @@ FfmpegOpenInput(AVIOContext *pb,
int err = avformat_open_input(&context, filename, fmt, nullptr);
if (err < 0) {
avformat_free_context(context);
SetFfmpegError(error, err, "avformat_open_input() failed");
return nullptr;
}
@@ -547,6 +546,10 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
AtScopeExit(&codec_context) {
avcodec_free_context(&codec_context);
};
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 25, 0) /* FFmpeg 3.1 */
avcodec_parameters_to_context(codec_context, av_stream.codecpar);
#endif
#endif
const SampleFormat sample_format =
@@ -639,7 +642,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
/* end of file */
break;
if (packet.stream_index == audio_stream) {
if (packet.size > 0 && packet.stream_index == audio_stream) {
cmd = ffmpeg_send_packet(decoder, input,
packet,
*codec_context,

@@ -23,10 +23,28 @@
#include "input/InputStream.hxx"
#include "util/Error.hxx"
#include "util/ByteReverse.hxx"
#include "util/StaticFifoBuffer.hxx"
#include "Log.hxx"
#include <assert.h>
#include <string.h>
template<typename B>
static bool
FillBuffer(Decoder &decoder, InputStream &is, B &buffer)
{
buffer.Shift();
auto w = buffer.Write();
assert(!w.IsEmpty());
size_t nbytes = decoder_read(decoder, is, w.data, w.size);
if (nbytes == 0 && is.LockIsEOF())
return false;
buffer.Append(nbytes);
return true;
}
static void
pcm_stream_decode(Decoder &decoder, InputStream &is)
{
@@ -50,25 +68,27 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
decoder_initialized(decoder, audio_format,
is.IsSeekable(), total_time);
StaticFifoBuffer<uint8_t, 4096> buffer;
DecoderCommand cmd;
do {
char buffer[4096];
size_t nbytes = decoder_read(decoder, is,
buffer, sizeof(buffer));
if (nbytes == 0 && is.LockIsEOF())
if (!FillBuffer(decoder, is, buffer))
break;
auto r = buffer.Read();
/* round down to the nearest frame size, because we
must not pass partial frames to decoder_data() */
r.size -= r.size % frame_size;
buffer.Consume(r.size);
if (reverse_endian)
/* make sure we deliver samples in host byte order */
reverse_bytes_16((uint16_t *)buffer,
(uint16_t *)buffer,
(uint16_t *)(buffer + nbytes));
reverse_bytes_16((uint16_t *)r.data,
(uint16_t *)r.data,
(uint16_t *)(r.data + r.size));
cmd = nbytes > 0
? decoder_data(decoder, is,
buffer, nbytes, 0)
cmd = !r.IsEmpty()
? decoder_data(decoder, is, r.data, r.size, 0)
: decoder_get_command(decoder);
if (cmd == DecoderCommand::SEEK) {
uint64_t frame = decoder_seek_where_frame(decoder);
@@ -76,6 +96,7 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
Error error;
if (is.LockSeek(offset, error)) {
buffer.Clear();
decoder_command_finished(decoder);
} else {
LogError(error);

@@ -354,12 +354,19 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
DecoderCommand cmd;
do {
short buffer[4096];
size_t nbytes;
nbytes = player.play(buffer, ARRAY_SIZE(buffer));
if (nbytes == 0)
const auto result = player.play(buffer, ARRAY_SIZE(buffer));
if (result <= 0)
break;
#ifdef HAVE_SIDPLAYFP
/* libsidplayfp returns the number of samples */
const size_t nbytes = result * sizeof(buffer[0]);
#else
/* libsidplay2 returns the number of bytes */
const size_t nbytes = result;
#endif
decoder_timestamp(decoder, (double)player.time() / timebase);
cmd = decoder_data(decoder, nullptr, buffer, nbytes, 0);
@@ -376,12 +383,9 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
}
/* ignore data until target time is reached */
while(data_time<target_time) {
nbytes=player.play(buffer, ARRAY_SIZE(buffer));
if(nbytes==0)
break;
while (data_time < target_time &&
player.play(buffer, ARRAY_SIZE(buffer)) > 0)
data_time = player.time();
}
decoder_command_finished(decoder);
}

@@ -65,6 +65,24 @@ wildmidi_finish(void)
WildMidi_Shutdown();
}
static DecoderCommand
wildmidi_output(Decoder &decoder, midi *wm)
{
#ifdef LIBWILDMIDI_VER_MAJOR
/* WildMidi 0.4 has switched from "char*" to "int8_t*" */
int8_t buffer[4096];
#else
/* pre 0.4 */
char buffer[4096];
#endif
int length = WildMidi_GetOutput(wm, buffer, sizeof(buffer));
if (length <= 0)
return DecoderCommand::STOP;
return decoder_data(decoder, nullptr, buffer, length, 0);
}
static void
wildmidi_file_decode(Decoder &decoder, Path path_fs)
{
@@ -94,18 +112,11 @@ wildmidi_file_decode(Decoder &decoder, Path path_fs)
DecoderCommand cmd;
do {
char buffer[4096];
int len;
info = WildMidi_GetInfo(wm);
if (info == nullptr)
break;
len = WildMidi_GetOutput(wm, buffer, sizeof(buffer));
if (len <= 0)
break;
cmd = decoder_data(decoder, nullptr, buffer, len, 0);
cmd = wildmidi_output(decoder, wm);
if (cmd == DecoderCommand::SEEK) {
unsigned long seek_where =

@@ -111,7 +111,7 @@ AllocatedPath::ChopSeparators()
while (l >= 2 && PathTraitsFS::IsSeparator(p[l - 1])) {
--l;
#if GCC_CHECK_VERSION(4,7) && !defined(__clang__)
#if GCC_CHECK_VERSION(4,7)
value.pop_back();
#else
value.erase(value.end() - 1, value.end());

@@ -247,6 +247,10 @@ AlsaInputStream::Recover(int err)
case -EPIPE:
LogDebug(alsa_input_domain, "Buffer Overrun");
// drop through
#if GCC_CHECK_VERSION(7,0)
[[fallthrough]];
#endif
case -ESTRPIPE:
case -EINTR:
err = snd_pcm_recover(capture_handle, err, 1);

@@ -216,7 +216,7 @@ SmbclientNeighborExplorer::Run()
prev = i;
} else {
/* can't see it anymore: move to "lost" */
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
lost.splice_after(lost.before_begin(), list, prev);
#else
/* the forward_list::splice_after() lvalue

@@ -760,6 +760,9 @@ alsa_recover(AlsaOutput *ad, int err)
if (err == -EAGAIN)
return 0;
/* fall-through to snd_pcm_prepare: */
#if GCC_CHECK_VERSION(7,0)
[[fallthrough]];
#endif
case SND_PCM_STATE_SETUP:
case SND_PCM_STATE_XRUN:
ad->period_position = 0;

@@ -545,7 +545,6 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
Error &error)
{
PulseOutput *po = (PulseOutput *)ao;
pa_sample_spec ss;
assert(po->mainloop != nullptr);
@@ -575,11 +574,30 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
return false;
}
/* MPD doesn't support the other pulseaudio sample formats, so
we just force MPD to send us everything as 16 bit */
audio_format.format = SampleFormat::S16;
/* Use the sample formats that our version of PulseAudio and MPD
have in common, otherwise force MPD to send 16 bit */
pa_sample_spec ss;
switch (audio_format.format) {
case SampleFormat::FLOAT:
ss.format = PA_SAMPLE_FLOAT32NE;
break;
case SampleFormat::S32:
ss.format = PA_SAMPLE_S32NE;
break;
case SampleFormat::S24_P32:
ss.format = PA_SAMPLE_S24_32NE;
break;
case SampleFormat::S16:
ss.format = PA_SAMPLE_S16NE;
break;
default:
audio_format.format = SampleFormat::S16;
ss.format = PA_SAMPLE_S16NE;
break;
}
ss.format = PA_SAMPLE_S16NE;
ss.rate = audio_format.sample_rate;
ss.channels = audio_format.channels;

@@ -148,10 +148,10 @@ winmm_output_open(AudioOutput *ao, AudioFormat &audio_format,
}
switch (audio_format.format) {
case SampleFormat::S8:
case SampleFormat::S16:
break;
case SampleFormat::S8:
case SampleFormat::S24_P32:
case SampleFormat::S32:
case SampleFormat::FLOAT:

@@ -153,7 +153,7 @@ public:
HttpdOutput(EventLoop &_loop);
~HttpdOutput();
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static HttpdOutput *Cast(AudioOutput *ao) {

@@ -426,14 +426,15 @@ Queue::SetPriority(unsigned position, uint8_t priority, int after_order)
if (_order < (unsigned)after_order) {
/* the specified song has been played already
- enqueue it only if its priority has just
become bigger than the current one's */
- enqueue it only if its priority has been
increased and is now bigger than the
current one's */
const unsigned after_position =
OrderToPosition(after_order);
const Item *after_item =
&items[after_position];
if (old_priority > after_item->priority ||
if (priority <= old_priority ||
priority <= after_item->priority)
/* priority hasn't become bigger */
return true;

@@ -137,7 +137,7 @@ CompositeStorage::Directory::Make(const char *uri)
Directory *directory = this;
while (*uri != 0) {
const std::string name = NextSegment(uri);
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
auto i = directory->children.emplace(std::move(name),
Directory());
#else
@@ -265,22 +265,13 @@ CompositeStorage::FindStorage(const char *uri) const
return result;
}
CompositeStorage::FindResult
CompositeStorage::FindStorage(const char *uri, Error &error) const
{
auto result = FindStorage(uri);
if (result.directory == nullptr)
error.Set(composite_domain, "No such directory");
return result;
}
bool
CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
Error &error)
{
const ScopeLock protect(mutex);
auto f = FindStorage(uri, error);
auto f = FindStorage(uri);
if (f.directory->storage != nullptr &&
f.directory->storage->GetInfo(f.uri, follow, info, error))
return true;
@@ -295,6 +286,8 @@ CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
return true;
}
if (!error.IsDefined())
error.Set(composite_domain, "No such directory");
return false;
}
@@ -304,13 +297,15 @@ CompositeStorage::OpenDirectory(const char *uri,
{
const ScopeLock protect(mutex);
auto f = FindStorage(uri, error);
auto f = FindStorage(uri);
const Directory *directory = f.directory->Find(f.uri);
if (directory == nullptr || directory->children.empty()) {
/* no virtual directories here */
if (f.directory->storage == nullptr)
if (f.directory->storage == nullptr) {
error.Set(composite_domain, "No such directory");
return nullptr;
}
return f.directory->storage->OpenDirectory(f.uri, error);
}

@@ -45,7 +45,7 @@ class CompositeStorage final : public Storage {
*/
struct Directory {
/**
* The #Storage mounted n this virtual directory. All
* The #Storage mounted in this virtual directory. All
* "leaf" Directory instances must have a #Storage.
* Other Directory instances may have one, and child
* mounts will be "mixed" in.
@@ -155,9 +155,16 @@ private:
}
}
/**
* Follow the given URI path, and find the outermost directory
* which is a #Storage mount point. If there are no mounts,
* it returns the root directory (with a nullptr "storage"
* attribute, of course). FindResult::uri contains the
* remaining unused part of the URI (may be empty if all of
* the URI was used).
*/
gcc_pure
FindResult FindStorage(const char *uri) const;
FindResult FindStorage(const char *uri, Error &error) const;
const char *MapToRelativeUTF8(const Directory &directory,
const char *uri) const;

@@ -40,7 +40,7 @@
/* well-known big-endian */
# define IS_LITTLE_ENDIAN false
# define IS_BIG_ENDIAN true
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__NetBSD__)
/* compile-time check for MacOS */
# include <machine/endian.h>
# if BYTE_ORDER == LITTLE_ENDIAN

@@ -75,7 +75,7 @@ TagSet::InsertUnique(const Tag &src, TagType type, const char *value,
else
builder.AddItem(type, value);
CopyTagMask(builder, src, group_mask);
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
#if CLANG_OR_GCC_VERSION(4,8)
emplace(builder.Commit());
#else
insert(builder.Commit());

@@ -21,7 +21,6 @@
#define MPD_TAG_ITEM_HXX
#include "TagType.h"
#include "Compiler.h"
/**
* One tag value. It is a mapping of #TagType to am arbitrary string
@@ -35,11 +34,14 @@ struct TagItem {
/**
* the value of this tag; this is a variable length string
*/
char value[sizeof(long) - sizeof(type)];
char value[1];
TagItem() = default;
TagItem(const TagItem &other) = delete;
TagItem &operator=(const TagItem &other) = delete;
} gcc_packed;
};
static_assert(sizeof(TagItem) == 2, "Unexpected size");
static_assert(alignof(TagItem) == 1, "Unexpected alignment");
#endif

@@ -50,7 +50,7 @@ struct TagPoolSlot {
static TagPoolSlot *Create(TagPoolSlot *_next, TagType type,
const char *value, size_t length);
} gcc_packed;
};
TagPoolSlot *
TagPoolSlot::Create(TagPoolSlot *_next, TagType type,
@@ -91,7 +91,7 @@ calc_hash(TagType type, const char *p)
return hash ^ type;
}
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline TagPoolSlot *

@@ -84,7 +84,7 @@ ContainerAttributeOffset(const A C::*p)
* Cast the given pointer to a struct member to its parent structure.
*/
template<class C, class A>
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline C &
@@ -97,7 +97,7 @@ ContainerCast(A &a, A C::*member)
* Cast the given pointer to a struct member to its parent structure.
*/
template<class C, class A>
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline const C &

@@ -41,7 +41,7 @@
#include <assert.h>
#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
#if CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
@@ -114,7 +114,7 @@ public:
}
};
#if defined(__clang__) || GCC_VERSION >= 40700
#if CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic pop
#endif

@@ -1,13 +0,0 @@
[Unit]
Description=Music Player Daemon
After=network.target sound.target
[Service]
ExecStart=@prefix@/bin/mpd --no-daemon
# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=infinity
[Install]
WantedBy=multi-user.target

@@ -0,0 +1,26 @@
[Unit]
Description=Music Player Daemon
After=network.target sound.target
[Service]
ExecStart=@prefix@/bin/mpd --no-daemon
# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=infinity
# disallow writing to /usr, /bin, /sbin, ...
ProtectSystem=yes
# more paranoid security settings
NoNewPrivileges=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
# AF_NETLINK is required by libsmbclient, or it will exit() .. *sigh*
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
RestrictNamespaces=yes
[Install]
WantedBy=multi-user.target
Also=mpd.socket

@@ -0,0 +1,29 @@
[Unit]
Description=Music Player Daemon
After=network.target sound.target
[Service]
ExecStart=@prefix@/bin/mpd --no-daemon
# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=infinity
# disallow writing to /usr, /bin, /sbin, ...
ProtectSystem=yes
# more paranoid security settings
NoNewPrivileges=yes
ProtectKernelTunables=yes
ProtectControlGroups=yes
# AF_NETLINK is required by libsmbclient, or it will exit() .. *sigh*
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
RestrictNamespaces=yes
# Note that "ProtectKernelModules=yes" is missing in the user unit
# because systemd 232 is unable to reduce its own capabilities
# ("Failed at step CAPABILITIES spawning /usr/bin/mpd: Operation not
# permitted")
[Install]
WantedBy=default.target

@@ -164,21 +164,6 @@ QueuePriorityTest::TestPriority()
check_descending_priority(&queue, current_order + 1);
/* priority=60 for the old prio50 item; must not be moved,
because it's before the current song, and it's status
hasn't changed (it was already higher before) */
unsigned c_order = 0;
unsigned c_position = queue.OrderToPosition(c_order);
CPPUNIT_ASSERT_EQUAL(50u, unsigned(queue.items[c_position].priority));
queue.SetPriority(c_position, 60, current_order);
current_order = queue.PositionToOrder(current_position);
CPPUNIT_ASSERT_EQUAL(3u, current_order);
c_order = queue.PositionToOrder(c_position);
CPPUNIT_ASSERT_EQUAL(0u, c_order);
/* move the prio=20 item back */
a_order = queue.PositionToOrder(a_position);