Compare commits
46 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3bbcda917c | ||
![]() |
7e43fb79af | ||
![]() |
eb2b567da6 | ||
![]() |
ab332d7b2e | ||
![]() |
53e22b81ef | ||
![]() |
3fc9d50adb | ||
![]() |
c2da6dd45b | ||
![]() |
7146f825b2 | ||
![]() |
f61a5f5200 | ||
![]() |
fef45d469c | ||
![]() |
e7353ec7e7 | ||
![]() |
e3237f057d | ||
![]() |
54d5d9d1cc | ||
![]() |
31d9aebf0b | ||
![]() |
301abac0c1 | ||
![]() |
7019f6bea4 | ||
![]() |
8bde47280a | ||
![]() |
521c6da830 | ||
![]() |
5c3e55b5b1 | ||
![]() |
1859ba5ec8 | ||
![]() |
ee026386e5 | ||
![]() |
49c04ccfc7 | ||
![]() |
11ba44870b | ||
![]() |
f9a64d24bf | ||
![]() |
e1a8dcfcc8 | ||
![]() |
1ee0e29974 | ||
![]() |
77a9940461 | ||
![]() |
9c1c180ae0 | ||
![]() |
06682bd2a9 | ||
![]() |
7c251fe190 | ||
![]() |
a85455fb3f | ||
![]() |
d4db873716 | ||
![]() |
de0752fd56 | ||
![]() |
4204d4928b | ||
![]() |
05de0ecec3 | ||
![]() |
b05beb000f | ||
![]() |
093abaad29 | ||
![]() |
e84e4169f9 | ||
![]() |
cd6c5cfd4c | ||
![]() |
b855f2fcc2 | ||
![]() |
ba69ade024 | ||
![]() |
a546bfe7d9 | ||
![]() |
25deae6cc7 | ||
![]() |
62000670e3 | ||
![]() |
ac49043fbb | ||
![]() |
37a7ca7f14 |
.gitignoreMakefile.amNEWSconfigure.ac
doc
src
Chrono.hxxCompiler.hLogInit.cxx
db
decoder
fs
input
plugins
neighbor
plugins
output
queue
storage
system
tag
util
systemd
test
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,7 +35,7 @@ tags
|
||||
/mkinstalldirs
|
||||
/build
|
||||
/src/mpd
|
||||
/systemd/mpd.service
|
||||
/systemd/system/mpd.service
|
||||
/stamp-h1
|
||||
|
||||
/src/dsd2pcm/dsd2pcm
|
||||
|
11
Makefile.am
11
Makefile.am
@@ -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
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)
|
||||
|
23
configure.ac
23
configure.ac
@@ -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>
|
||||
|
||||
|
29
doc/user.xml
29
doc/user.xml
@@ -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
|
26
systemd/system/mpd.service.in
Normal file
26
systemd/system/mpd.service.in
Normal file
@@ -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
|
29
systemd/user/mpd.service.in
Normal file
29
systemd/user/mpd.service.in
Normal file
@@ -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);
|
||||
|
Reference in New Issue
Block a user