diff --git a/.gitignore b/.gitignore
index 612924822..432b8d907 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,7 +35,8 @@ tags
/mkinstalldirs
/build
/src/mpd
-/systemd/mpd.service
+/systemd/system/mpd.service
+/systemd/user/mpd.service
/stamp-h1
/src/dsd2pcm/dsd2pcm
diff --git a/Makefile.am b/Makefile.am
index 0e26cafea..f82ff3e32 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1599,8 +1599,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
@@ -2356,7 +2361,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 \
diff --git a/NEWS b/NEWS
index 318574646..94001b9a3 100644
--- a/NEWS
+++ b/NEWS
@@ -62,6 +62,12 @@ ver 0.20 (not yet released)
* switch the code base to C++14
- GCC 4.9 or clang 3.4 (or newer) recommended
+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
diff --git a/configure.ac b/configure.ac
index d4ac95b20..d420e572c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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 ---------------------------------------------------------------------------
@@ -1498,7 +1514,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.'
diff --git a/doc/user.xml b/doc/user.xml
index c86458f32..082ba9188 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -151,7 +151,7 @@ apt-get install g++ \
systemd unit files: a "service"
unit and a "socket" unit. These will only be installed when
MPD was configured with
- --with-systemdsystemunitdir=/lib/systemd.
+ --with-systemdsystemunitdir=/lib/systemd/system.
@@ -167,6 +167,33 @@ systemctl start mpd.socket
port settings.
+
+
+ systemd user unit
+
+
+ You can launch MPD as a
+ systemd user unit. The service file will
+ only be installed when MPD was
+ configured with
+ --with-systemduserunitdir=/usr/lib/systemd/user
+ or
+ --with-systemduserunitdir=$HOME/.local/share/systemd/user.
+
+
+
+ Once the user unit is installed, you can start and stop
+ MPD like any other service:
+
+
+ systemctl --user start mpd
+
+
+ To auto-start MPD upon login, type:
+
+
+ systemctl --user enable mpd
+
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index d6f8f5e72..499066d78 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -68,10 +68,8 @@ FfmpegOpenInput(AVIOContext *pb,
context->pb = pb;
int err = avformat_open_input(&context, filename, fmt, nullptr);
- if (err < 0) {
- avformat_free_context(context);
+ if (err < 0)
throw MakeFfmpegError(err, "avformat_open_input() failed");
- }
return context;
}
diff --git a/systemd/mpd.service.in b/systemd/system/mpd.service.in
similarity index 100%
rename from systemd/mpd.service.in
rename to systemd/system/mpd.service.in
diff --git a/systemd/mpd.socket b/systemd/system/mpd.socket
similarity index 100%
rename from systemd/mpd.socket
rename to systemd/system/mpd.socket
diff --git a/systemd/user/mpd.service.in b/systemd/user/mpd.service.in
new file mode 100644
index 000000000..12b814c2d
--- /dev/null
+++ b/systemd/user/mpd.service.in
@@ -0,0 +1,31 @@
+[Unit]
+Description=Music Player Daemon
+Documentation=man:mpd(1) man:mpd.conf(5)
+After=network.target sound.target
+
+[Service]
+Type=notify
+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
diff --git a/test/test_queue_priority.cxx b/test/test_queue_priority.cxx
index 517cb028c..171585dec 100644
--- a/test/test_queue_priority.cxx
+++ b/test/test_queue_priority.cxx
@@ -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);