[Pkg-mpd-commits] [SCM] Git repository for pkg-mpd branch, master, updated. debian/0.16.2-1-20-ga4e0297

Alexander Wirt formorer at debian.org
Thu Oct 13 10:28:20 UTC 2011


The following commit has been merged in the master branch:
commit d91cb09c124f300d10756a87fc3d76da41c96066
Author: Alexander Wirt <formorer at debian.org>
Date:   Sat Sep 3 09:20:25 2011 +0200

    Imported Upstream version 0.16.4

diff --git a/Makefile.am b/Makefile.am
index 88eebe6..b3620bd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -11,6 +11,7 @@ noinst_LIBRARIES =
 
 src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS)
 src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
+	$(AVAHI_CFLAGS) \
 	$(LIBWRAP_CFLAGS) \
 	$(SQLITE_CFLAGS) \
 	$(ARCHIVE_CFLAGS) \
@@ -21,6 +22,7 @@ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
 	$(FILTER_CFLAGS) \
 	$(OUTPUT_CFLAGS)
 src_mpd_LDADD = $(MPD_LIBS) \
+	$(AVAHI_LIBS) \
 	$(LIBWRAP_LDFLAGS) \
 	$(SQLITE_LIBS) \
 	$(ARCHIVE_LIBS) \
diff --git a/Makefile.in b/Makefile.in
index 51c39b9..06bd134 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -652,11 +652,11 @@ am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 src_mpd_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
-	$(am__DEPENDENCIES_3) $(am__DEPENDENCIES_4) \
-	$(am__DEPENDENCIES_6) $(am__DEPENDENCIES_7) \
-	$(am__DEPENDENCIES_8) $(am__DEPENDENCIES_4) \
-	$(am__DEPENDENCIES_1)
+	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+	$(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_6) \
+	$(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) \
+	$(am__DEPENDENCIES_4) $(am__DEPENDENCIES_1)
 am__test_dump_playlist_SOURCES_DIST = test/dump_playlist.c src/conf.c \
 	src/tokenizer.c src/utils.c src/uri.c src/song.c src/tag.c \
 	src/tag_pool.c src/tag_save.c src/text_input_stream.c \
@@ -1580,6 +1580,7 @@ AM_CPPFLAGS = -I$(srcdir)/src $(GLIB_CFLAGS) \
 noinst_LIBRARIES = $(am__append_22)
 src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS)
 src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
+	$(AVAHI_CFLAGS) \
 	$(LIBWRAP_CFLAGS) \
 	$(SQLITE_CFLAGS) \
 	$(ARCHIVE_CFLAGS) \
@@ -1591,6 +1592,7 @@ src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
 	$(OUTPUT_CFLAGS)
 
 src_mpd_LDADD = $(MPD_LIBS) \
+	$(AVAHI_LIBS) \
 	$(LIBWRAP_LDFLAGS) \
 	$(SQLITE_LIBS) \
 	$(ARCHIVE_LIBS) \
diff --git a/NEWS b/NEWS
index 31169a8..d72e0e0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,27 @@
+ver 0.16.4 (2011/09/01)
+* don't abort configure when avahi is not found
+* auto-detect libmad without pkg-config
+* fix memory leaks
+* don't resume playback when seeking to another song while paused
+* apply follow_inside_symlinks to absolute symlinks
+* fix playback discontinuation after seeking
+* input:
+  - curl: limit the receive buffer size
+  - curl: implement a hard-coded timeout of 10 seconds
+* decoder:
+  - ffmpeg: workaround for semantic API change in recent ffmpeg versions
+  - flac: validate the sample rate when scanning the tag
+  - wavpack: obey all decoder commands, stop at CUE track border
+* encoder:
+  - vorbis: don't send end-of-stream on flush
+* output:
+  - alsa: fix SIGFPE when alsa announces a period size of 0
+  - httpd: don't warn on client disconnect
+  - osx: don't drain the buffer when closing
+  - pulse: fix deadlock when resuming the stream
+  - pulse: fix deadlock when the stream was suspended
+
+
 ver 0.16.3 (2011/06/04)
 * fix assertion failure in audio format mask parser
 * fix NULL pointer dereference in playlist parser
diff --git a/configure b/configure
index 313bcd3..abbe4c2 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.67 for mpd 0.16.3.
+# Generated by GNU Autoconf 2.67 for mpd 0.16.4.
 #
 # Report bugs to <musicpd-dev-team at lists.sourceforge.net>.
 #
@@ -552,8 +552,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='mpd'
 PACKAGE_TARNAME='mpd'
-PACKAGE_VERSION='0.16.3'
-PACKAGE_STRING='mpd 0.16.3'
+PACKAGE_VERSION='0.16.4'
+PACKAGE_STRING='mpd 0.16.4'
 PACKAGE_BUGREPORT='musicpd-dev-team at lists.sourceforge.net'
 PACKAGE_URL=''
 
@@ -726,6 +726,8 @@ FLUIDSYNTH_LIBS
 FLUIDSYNTH_CFLAGS
 HAVE_FLAC_FALSE
 HAVE_FLAC_TRUE
+OGG_LIBS
+OGG_CFLAGS
 FLAC_LIBS
 FLAC_CFLAGS
 HAVE_FFMPEG_FALSE
@@ -766,8 +768,6 @@ ENABLE_MMS_FALSE
 ENABLE_MMS_TRUE
 MMS_LIBS
 MMS_CFLAGS
-OGG_LIBS
-OGG_CFLAGS
 ENABLE_LASTFM_FALSE
 ENABLE_LASTFM_TRUE
 ENABLE_CURL_FALSE
@@ -786,10 +786,10 @@ SQLITE_LIBS
 SQLITE_CFLAGS
 HAVE_BONJOUR_FALSE
 HAVE_BONJOUR_TRUE
-HAVE_AVAHI_FALSE
-HAVE_AVAHI_TRUE
 HAVE_ZEROCONF_FALSE
 HAVE_ZEROCONF_TRUE
+HAVE_AVAHI_FALSE
+HAVE_AVAHI_TRUE
 AVAHI_LIBS
 AVAHI_CFLAGS
 HAVE_ID3TAG_FALSE
@@ -1001,8 +1001,6 @@ SAMPLERATE_013_CFLAGS
 SAMPLERATE_013_LIBS
 CURL_CFLAGS
 CURL_LIBS
-OGG_CFLAGS
-OGG_LIBS
 MMS_CFLAGS
 MMS_LIBS
 ISO9660_CFLAGS
@@ -1015,6 +1013,8 @@ FFMPEG_CFLAGS
 FFMPEG_LIBS
 FLAC_CFLAGS
 FLAC_LIBS
+OGG_CFLAGS
+OGG_LIBS
 FLUIDSYNTH_CFLAGS
 FLUIDSYNTH_LIBS
 GME_CFLAGS
@@ -1591,7 +1591,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures mpd 0.16.3 to adapt to many kinds of systems.
+\`configure' configures mpd 0.16.4 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1661,7 +1661,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of mpd 0.16.3:";;
+     short | recursive ) echo "Configuration of mpd 0.16.4:";;
    esac
   cat <<\_ACEOF
 
@@ -1684,13 +1684,13 @@ Optional Features:
   --enable-ffmpeg         enable FFMPEG support
   --disable-fifo          disable support for writing audio to a FIFO
                           (default: enable)
-  --disable-flac          disable flac support (default: enable)
+  --enable-flac           enable FLAC decoder
   --enable-fluidsynth     enable MIDI support via fluidsynth (default:
                           disable)
   --enable-gme            enable Blargg's game music emulator plugin
   --enable-gprof          enable profiling via gprof (default: disabled)
   --enable-httpd-output   enables the HTTP server output
-  --disable-id3           disable id3 support (default: enable)
+  --enable-id3            disable id3 support
   --disable-inotify       disable support Inotify automatic database update
                           (default: enabled)
   --disable-ipv6          disable IPv6 support (default: enable)
@@ -1729,7 +1729,7 @@ Optional Features:
                           enable the TwoLAME mp2 encoder
   --disable-un            disable support for clients connecting via unix
                           domain sockets (default: enable)
-  --disable-vorbis        disable Ogg Vorbis support (default: enable)
+  --enable-vorbis         enable Ogg Vorbis decoder
   --enable-vorbis-encoder enable the Ogg Vorbis encoder
   --enable-wave-encoder   enable the PCM wave encoder
   --enable-wavpack        enable WavPack support
@@ -1794,8 +1794,6 @@ Some influential environment variables:
               linker flags for SAMPLERATE_013, overriding pkg-config
   CURL_CFLAGS C compiler flags for CURL, overriding pkg-config
   CURL_LIBS   linker flags for CURL, overriding pkg-config
-  OGG_CFLAGS  C compiler flags for OGG, overriding pkg-config
-  OGG_LIBS    linker flags for OGG, overriding pkg-config
   MMS_CFLAGS  C compiler flags for MMS, overriding pkg-config
   MMS_LIBS    linker flags for MMS, overriding pkg-config
   ISO9660_CFLAGS
@@ -1813,6 +1811,8 @@ Some influential environment variables:
   FFMPEG_LIBS linker flags for FFMPEG, overriding pkg-config
   FLAC_CFLAGS C compiler flags for FLAC, overriding pkg-config
   FLAC_LIBS   linker flags for FLAC, overriding pkg-config
+  OGG_CFLAGS  C compiler flags for OGG, overriding pkg-config
+  OGG_LIBS    linker flags for OGG, overriding pkg-config
   FLUIDSYNTH_CFLAGS
               C compiler flags for FLUIDSYNTH, overriding pkg-config
   FLUIDSYNTH_LIBS
@@ -1932,7 +1932,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-mpd configure 0.16.3
+mpd configure 0.16.4
 generated by GNU Autoconf 2.67
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2442,7 +2442,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by mpd $as_me 0.16.3, which was
+It was created by mpd $as_me 0.16.4, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
   $ $0 $@
@@ -3258,7 +3258,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='mpd'
- VERSION='0.16.3'
+ VERSION='0.16.4'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -5979,7 +5979,7 @@ fi
 if test "${enable_flac+set}" = set; then :
   enableval=$enable_flac;
 else
-  enable_flac=yes
+  enable_flac=auto
 fi
 
 
@@ -6019,7 +6019,7 @@ fi
 if test "${enable_id3+set}" = set; then :
   enableval=$enable_id3;
 else
-  enable_id3=yes
+  enable_id3=auto
 fi
 
 
@@ -6468,7 +6468,7 @@ fi
 if test "${enable_vorbis+set}" = set; then :
   enableval=$enable_vorbis;
 else
-  enable_vorbis=yes
+  enable_vorbis=auto
 fi
 
 
@@ -7030,7 +7030,8 @@ else
 fi
 
 
-if test x$enable_id3 = xyes; then
+
+	if eval "test x`echo '$'enable_id3` != xno"; then
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ID3TAG" >&5
@@ -7129,9 +7130,9 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_id3tag_id3_file_open" >&5
 $as_echo "$ac_cv_lib_id3tag_id3_file_open" >&6; }
 if test "x$ac_cv_lib_id3tag_id3_file_open" = x""yes; then :
-  ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""
+  eval "found_id3=yes ID3TAG_LIBS='-lid3tag -lz' ID3TAG_CFLAGS=''"
 else
-  enable_id3=no
+  eval "found_id3=no"
 fi
 
 elif test $pkg_failed = untried; then
@@ -7172,9 +7173,9 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_id3tag_id3_file_open" >&5
 $as_echo "$ac_cv_lib_id3tag_id3_file_open" >&6; }
 if test "x$ac_cv_lib_id3tag_id3_file_open" = x""yes; then :
-  ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""
+  eval "found_id3=yes ID3TAG_LIBS='-lid3tag -lz' ID3TAG_CFLAGS=''"
 else
-  enable_id3=no
+  eval "found_id3=no"
 fi
 
 else
@@ -7182,9 +7183,48 @@ else
 	ID3TAG_LIBS=$pkg_cv_ID3TAG_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-	:
-fi
+	eval "found_id3=yes"
 fi
+	fi
+
+
+	name="id3"
+	var="enable_id3"
+	found="found_$name"
+	feature="id3tag"
+	msg="libid3tag not found"
+
+	if eval "test x`echo '$'$var` = xno"; then
+		eval "$found=no"
+	fi
+
+	if eval "test x`echo '$'$found` = xyes"; then
+
+	var="enable_$name"
+	feature="$feature"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: auto-detected $feature" >&5
+$as_echo "$as_me: auto-detected $feature" >&6;}
+		eval "$var=yes"
+	fi
+
+	else
+
+	var="enable_$name"
+	feature="$feature"
+	msg="$msg"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $msg -- disabling $feature" >&5
+$as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
+		eval "$var=no"
+	elif eval "test x`echo '$'$var` = xyes"; then
+		as_fn_error $? "$feature: $msg" "$LINENO" 5
+	fi
+
+	fi
+
 
 if test x$enable_id3 = xyes; then
 
@@ -7204,15 +7244,22 @@ fi
 
 
 case $with_zeroconf in
-no|avahi|bonjour)
+no|bonjour)
+	enable_avahi=no
 	;;
+
+avahi)
+	enable_avahi=yes
+	;;
+
 *)
 	with_zeroconf=auto
+	enable_avahi=auto
 	;;
 esac
 
-if test x$with_zeroconf != xno; then
-	if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then
+
+	if eval "test x`echo '$'enable_avahi` != xno"; then
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AVAHI" >&5
@@ -7274,35 +7321,81 @@ fi
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                found_avahi=0
+                eval "found_avahi=no"
 elif test $pkg_failed = untried; then
-	found_avahi=0
+	eval "found_avahi=no"
 else
 	AVAHI_CFLAGS=$pkg_cv_AVAHI_CFLAGS
 	AVAHI_LIBS=$pkg_cv_AVAHI_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-	found_avahi=1;
-$as_echo "#define HAVE_AVAHI 1" >>confdefs.h
-
-			 MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS"
+	eval "found_avahi=yes"
 fi
 	fi
 
-	if test x$found_avahi = x1; then
-		with_zeroconf=avahi
-	elif test x$with_zeroconf = xavahi; then
-		as_fn_error $? "Avahi support requested but not found" "$LINENO" 5
+
+	name="avahi"
+	var="enable_avahi"
+	found="found_$name"
+	feature="avahi client library"
+	msg="avahi client+glib not found"
+
+	if eval "test x`echo '$'$var` = xno"; then
+		eval "$found=no"
+	fi
+
+	if eval "test x`echo '$'$found` = xyes"; then
+
+	var="enable_$name"
+	feature="$feature"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: auto-detected $feature" >&5
+$as_echo "$as_me: auto-detected $feature" >&6;}
+		eval "$var=yes"
+	fi
+
+	else
+
+	var="enable_$name"
+	feature="$feature"
+	msg="$msg"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $msg -- disabling $feature" >&5
+$as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
+		eval "$var=no"
+	elif eval "test x`echo '$'$var` = xyes"; then
+		as_fn_error $? "$feature: $msg" "$LINENO" 5
+	fi
+
 	fi
 
+
+if test x$enable_avahi = xyes; then
+
+$as_echo "#define HAVE_AVAHI 1" >>confdefs.h
+
+	with_zeroconf=avahi
+fi
+
+ if test x$enable_avahi = xyes; then
+  HAVE_AVAHI_TRUE=
+  HAVE_AVAHI_FALSE='#'
+else
+  HAVE_AVAHI_TRUE='#'
+  HAVE_AVAHI_FALSE=
+fi
+
+
+enable_bounjour=no
+if test x$with_zeroconf != xno; then
 	if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then
 		ac_fn_c_check_header_mongrel "$LINENO" "dns_sd.h" "ac_cv_header_dns_sd_h" "$ac_includes_default"
 if test "x$ac_cv_header_dns_sd_h" = x""yes; then :
-  found_bonjour=1;
+  enable_bonjour=yes;
 $as_echo "#define HAVE_BONJOUR 1" >>confdefs.h
 
-else
-  found_bonjour=0
 fi
 
 
@@ -7348,7 +7441,7 @@ fi
 
 	fi
 
-	if test x$found_bonjour = x1; then
+	if test x$enable_bonjour = xyes; then
 		with_zeroconf=bonjour
 	elif test x$with_zeroconf = xbonjour; then
 		as_fn_error $? "Bonjour support requested but not found" "$LINENO" 5
@@ -7373,14 +7466,6 @@ else
   HAVE_ZEROCONF_FALSE=
 fi
 
- if test x$with_zeroconf = xavahi; then
-  HAVE_AVAHI_TRUE=
-  HAVE_AVAHI_FALSE='#'
-else
-  HAVE_AVAHI_TRUE='#'
-  HAVE_AVAHI_FALSE=
-fi
-
  if test x$with_zeroconf = xbonjour; then
   HAVE_BONJOUR_TRUE=
   HAVE_BONJOUR_FALSE='#'
@@ -7876,80 +7961,6 @@ else
 fi
 
 
-if test x$with_tremor = xno || test -z $with_tremor; then
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OGG" >&5
-$as_echo_n "checking for OGG... " >&6; }
-
-if test -n "$PKG_CONFIG"; then
-    if test -n "$OGG_CFLAGS"; then
-        pkg_cv_OGG_CFLAGS="$OGG_CFLAGS"
-    else
-        if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "ogg") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_OGG_CFLAGS=`$PKG_CONFIG --cflags "ogg" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
-    fi
-else
-	pkg_failed=untried
-fi
-if test -n "$PKG_CONFIG"; then
-    if test -n "$OGG_LIBS"; then
-        pkg_cv_OGG_LIBS="$OGG_LIBS"
-    else
-        if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "ogg") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_OGG_LIBS=`$PKG_CONFIG --libs "ogg" 2>/dev/null`
-else
-  pkg_failed=yes
-fi
-    fi
-else
-	pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-	        OGG_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "ogg"`
-        else
-	        OGG_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "ogg"`
-        fi
-	# Put the nasty error message in config.log where it belongs
-	echo "$OGG_PKG_ERRORS" >&5
-
-	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-                enable_ogg=no
-elif test $pkg_failed = untried; then
-	enable_ogg=no
-else
-	OGG_CFLAGS=$pkg_cv_OGG_CFLAGS
-	OGG_LIBS=$pkg_cv_OGG_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-	enable_ogg=yes
-fi
-fi
-
 
 	if eval "test x`echo '$'enable_mms` != xno"; then
 
@@ -9304,7 +9315,9 @@ else
 fi
 
 
-if test x$enable_flac = xyes; then
+
+
+	if eval "test x`echo '$'enable_flac` != xno"; then
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FLAC" >&5
@@ -9366,18 +9379,62 @@ fi
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                enable_flac=no
+                eval "found_flac=no"
 elif test $pkg_failed = untried; then
-	enable_flac=no
+	eval "found_flac=no"
 else
 	FLAC_CFLAGS=$pkg_cv_FLAC_CFLAGS
 	FLAC_LIBS=$pkg_cv_FLAC_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
+	eval "found_flac=yes"
+fi
+	fi
+
+
+	name="flac"
+	var="enable_flac"
+	found="found_$name"
+	feature="FLAC decoder"
+	msg="libFLAC not found"
+
+	if eval "test x`echo '$'$var` = xno"; then
+		eval "$found=no"
+	fi
+
+	if eval "test x`echo '$'$found` = xyes"; then
+
+	var="enable_$name"
+	feature="$feature"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: auto-detected $feature" >&5
+$as_echo "$as_me: auto-detected $feature" >&6;}
+		eval "$var=yes"
+	fi
+
+	else
+
+	var="enable_$name"
+	feature="$feature"
+	msg="$msg"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $msg -- disabling $feature" >&5
+$as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
+		eval "$var=no"
+	elif eval "test x`echo '$'$var` = xyes"; then
+		as_fn_error $? "$feature: $msg" "$LINENO" 5
+	fi
+
+	fi
+
+
+
+if test x$enable_flac = xyes; then
 
 $as_echo "#define HAVE_FLAC 1" >>confdefs.h
 
-fi
 
 	oldcflags="$CFLAGS"
 	oldlibs="$LIBS"
@@ -9395,13 +9452,81 @@ fi
 	LIBS="$oldlibs"
 
 	if test x$enable_oggflac = xflac; then
-		if test x$enable_ogg = xyes; then
-			FLAC_LIBS="${FLAC_LIBS} -logg"
-		else
-			enable_oggflac=yes
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OGG" >&5
+$as_echo_n "checking for OGG... " >&6; }
+
+if test -n "$PKG_CONFIG"; then
+    if test -n "$OGG_CFLAGS"; then
+        pkg_cv_OGG_CFLAGS="$OGG_CFLAGS"
+    else
+        if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "ogg") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_OGG_CFLAGS=`$PKG_CONFIG --cflags "ogg" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+    fi
+else
+	pkg_failed=untried
+fi
+if test -n "$PKG_CONFIG"; then
+    if test -n "$OGG_LIBS"; then
+        pkg_cv_OGG_LIBS="$OGG_LIBS"
+    else
+        if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"ogg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "ogg") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_OGG_LIBS=`$PKG_CONFIG --libs "ogg" 2>/dev/null`
+else
+  pkg_failed=yes
+fi
+    fi
+else
+	pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        OGG_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "ogg"`
+        else
+	        OGG_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "ogg"`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$OGG_PKG_ERRORS" >&5
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+                enable_oggflac=yes;
 			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"FLAC has the ogg API built in" >&5
 $as_echo "$as_me: WARNING: \"FLAC has the ogg API built in" >&2;}
-		fi
+elif test $pkg_failed = untried; then
+	enable_oggflac=yes;
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"FLAC has the ogg API built in" >&5
+$as_echo "$as_me: WARNING: \"FLAC has the ogg API built in" >&2;}
+else
+	OGG_CFLAGS=$pkg_cv_OGG_CFLAGS
+	OGG_LIBS=$pkg_cv_OGG_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	FLAC_LIBS="${FLAC_LIBS} ${OGG_LIBS}" FLAC_CFLAGS="${FLAC_CFLAGS} ${OGG_CFLAGS}"
+fi
 	fi
 fi
 
@@ -9692,9 +9817,91 @@ fi
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                eval "found_mad=no"
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mad_stream_init in -lmad" >&5
+$as_echo_n "checking for mad_stream_init in -lmad... " >&6; }
+if test "${ac_cv_lib_mad_mad_stream_init+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmad  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mad_stream_init ();
+int
+main ()
+{
+return mad_stream_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_mad_mad_stream_init=yes
+else
+  ac_cv_lib_mad_mad_stream_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mad_mad_stream_init" >&5
+$as_echo "$ac_cv_lib_mad_mad_stream_init" >&6; }
+if test "x$ac_cv_lib_mad_mad_stream_init" = x""yes; then :
+  eval "found_mad=yes MAD_LIBS='-lmad' MAD_CFLAGS=''"
+else
+  eval "found_mad=no"
+fi
+
 elif test $pkg_failed = untried; then
-	eval "found_mad=no"
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mad_stream_init in -lmad" >&5
+$as_echo_n "checking for mad_stream_init in -lmad... " >&6; }
+if test "${ac_cv_lib_mad_mad_stream_init+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lmad  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char mad_stream_init ();
+int
+main ()
+{
+return mad_stream_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_mad_mad_stream_init=yes
+else
+  ac_cv_lib_mad_mad_stream_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mad_mad_stream_init" >&5
+$as_echo "$ac_cv_lib_mad_mad_stream_init" >&6; }
+if test "x$ac_cv_lib_mad_mad_stream_init" = x""yes; then :
+  eval "found_mad=yes MAD_LIBS='-lmad' MAD_CFLAGS=''"
+else
+  eval "found_mad=no"
+fi
+
 else
 	MAD_CFLAGS=$pkg_cv_MAD_CFLAGS
 	MAD_LIBS=$pkg_cv_MAD_LIBS
@@ -10534,7 +10741,7 @@ $as_echo "#define HAVE_TREMOR 1" >>confdefs.h
 
 
 $as_echo "#define ENABLE_VORBIS_DECODER 1" >>confdefs.h
-,
+
 else
 	TREMOR_CFLAGS=
 	TREMOR_LIBS=
@@ -10577,12 +10784,17 @@ else
 fi
 
 
-if test x$enable_vorbis = xyes; then
-	if test x$enable_tremor = xyes; then
+
+if test x$enable_tremor = xyes; then
+	if test x$enable_vorbis = xyes; then
 		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"OggTremor detected, could not enable Vorbis.\"" >&5
 $as_echo "$as_me: WARNING: \"OggTremor detected, could not enable Vorbis.\"" >&2;}
-		enable_vorbis=no
-	elif test x$enable_ogg = xyes; then
+	fi
+	enable_vorbis=no
+fi
+
+
+	if eval "test x`echo '$'enable_vorbis` != xno"; then
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for VORBIS" >&5
@@ -10593,12 +10805,12 @@ if test -n "$PKG_CONFIG"; then
         pkg_cv_VORBIS_CFLAGS="$VORBIS_CFLAGS"
     else
         if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis vorbisfile\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "vorbis vorbisfile") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis vorbisfile ogg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "vorbis vorbisfile ogg") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_VORBIS_CFLAGS=`$PKG_CONFIG --cflags "vorbis vorbisfile" 2>/dev/null`
+  pkg_cv_VORBIS_CFLAGS=`$PKG_CONFIG --cflags "vorbis vorbisfile ogg" 2>/dev/null`
 else
   pkg_failed=yes
 fi
@@ -10611,12 +10823,12 @@ if test -n "$PKG_CONFIG"; then
         pkg_cv_VORBIS_LIBS="$VORBIS_LIBS"
     else
         if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis vorbisfile\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "vorbis vorbisfile") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"vorbis vorbisfile ogg\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "vorbis vorbisfile ogg") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_VORBIS_LIBS=`$PKG_CONFIG --libs "vorbis vorbisfile" 2>/dev/null`
+  pkg_cv_VORBIS_LIBS=`$PKG_CONFIG --libs "vorbis vorbisfile ogg" 2>/dev/null`
 else
   pkg_failed=yes
 fi
@@ -10635,32 +10847,70 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-	        VORBIS_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "vorbis vorbisfile"`
+	        VORBIS_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "vorbis vorbisfile ogg"`
         else
-	        VORBIS_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "vorbis vorbisfile"`
+	        VORBIS_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "vorbis vorbisfile ogg"`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$VORBIS_PKG_ERRORS" >&5
 
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-                enable_vorbis=no
+                eval "found_vorbis=no"
 elif test $pkg_failed = untried; then
-	enable_vorbis=no
+	eval "found_vorbis=no"
 else
 	VORBIS_CFLAGS=$pkg_cv_VORBIS_CFLAGS
 	VORBIS_LIBS=$pkg_cv_VORBIS_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
+	eval "found_vorbis=yes"
+fi
+	fi
 
-$as_echo "#define ENABLE_VORBIS_DECODER 1" >>confdefs.h
 
-fi
+	name="vorbis"
+	var="enable_vorbis"
+	found="found_$name"
+	feature="Ogg Vorbis decoder"
+	msg="libvorbis not found"
+
+	if eval "test x`echo '$'$var` = xno"; then
+		eval "$found=no"
+	fi
+
+	if eval "test x`echo '$'$found` = xyes"; then
+
+	var="enable_$name"
+	feature="$feature"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: auto-detected $feature" >&5
+$as_echo "$as_me: auto-detected $feature" >&6;}
+		eval "$var=yes"
+	fi
+
 	else
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \"Ogg not detected, could not enable Vorbis.\"" >&5
-$as_echo "$as_me: WARNING: \"Ogg not detected, could not enable Vorbis.\"" >&2;}
-		enable_vorbis=no
+
+	var="enable_$name"
+	feature="$feature"
+	msg="$msg"
+
+	if eval "test x`echo '$'$var` = xauto"; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $msg -- disabling $feature" >&5
+$as_echo "$as_me: WARNING: $msg -- disabling $feature" >&2;}
+		eval "$var=no"
+	elif eval "test x`echo '$'$var` = xyes"; then
+		as_fn_error $? "$feature: $msg" "$LINENO" 5
 	fi
+
+	fi
+
+
+if test x$enable_vorbis = xyes; then
+
+$as_echo "#define ENABLE_VORBIS_DECODER 1" >>confdefs.h
+
 fi
 
  if test x$enable_vorbis = xyes || test x$enable_tremor = xyes; then
@@ -14320,14 +14570,14 @@ if test -z "${HAVE_ID3TAG_TRUE}" && test -z "${HAVE_ID3TAG_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_ID3TAG\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${HAVE_ZEROCONF_TRUE}" && test -z "${HAVE_ZEROCONF_FALSE}"; then
-  as_fn_error $? "conditional \"HAVE_ZEROCONF\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
 if test -z "${HAVE_AVAHI_TRUE}" && test -z "${HAVE_AVAHI_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_AVAHI\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${HAVE_ZEROCONF_TRUE}" && test -z "${HAVE_ZEROCONF_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_ZEROCONF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${HAVE_BONJOUR_TRUE}" && test -z "${HAVE_BONJOUR_FALSE}"; then
   as_fn_error $? "conditional \"HAVE_BONJOUR\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -14972,7 +15222,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by mpd $as_me 0.16.3, which was
+This file was extended by mpd $as_me 0.16.4, which was
 generated by GNU Autoconf 2.67.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -15038,7 +15288,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-mpd config.status 0.16.3
+mpd config.status 0.16.4
 configured by $0, generated by GNU Autoconf 2.67,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 0aed23b..49233f4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
 AC_PREREQ(2.60)
-AC_INIT(mpd, 0.16.3, musicpd-dev-team at lists.sourceforge.net)
+AC_INIT(mpd, 0.16.4, musicpd-dev-team at lists.sourceforge.net)
 AC_CONFIG_SRCDIR([src/main.c])
 AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
 AM_CONFIG_HEADER(config.h)
@@ -171,9 +171,9 @@ AC_ARG_ENABLE(fifo,
 	enable_fifo=yes)
 
 AC_ARG_ENABLE(flac,
-	AS_HELP_STRING([--disable-flac],
-		[disable flac support (default: enable)]),,
-	enable_flac=yes)
+	AS_HELP_STRING([--enable-flac],
+		[enable FLAC decoder]),,
+	enable_flac=auto)
 
 AC_ARG_ENABLE(fluidsynth,
 	AS_HELP_STRING([--enable-fluidsynth],
@@ -196,9 +196,9 @@ AC_ARG_ENABLE(httpd-output,
 	[enable_httpd_output=auto])
 
 AC_ARG_ENABLE(id3,
-	AS_HELP_STRING([--disable-id3],
-		[disable id3 support (default: enable)]),,
-	enable_id3=yes)
+	AS_HELP_STRING([--enable-id3],
+		[disable id3 support]),,
+	enable_id3=auto)
 
 AC_ARG_ENABLE(inotify,
 	AS_HELP_STRING([--disable-inotify],
@@ -353,9 +353,9 @@ AC_ARG_ENABLE(un,
 	[enable_un=yes])
 
 AC_ARG_ENABLE(vorbis,
-	AS_HELP_STRING([--disable-vorbis],
-		[disable Ogg Vorbis support (default: enable)]),,
-	enable_vorbis=yes)
+	AS_HELP_STRING([--enable-vorbis],
+		[enable Ogg Vorbis decoder]),,
+	enable_vorbis=auto)
 
 AC_ARG_ENABLE(vorbis-encoder,
 	AS_HELP_STRING([--enable-vorbis-encoder],
@@ -510,13 +510,8 @@ fi
 AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes)
 
 dnl -------------------------------- libid3tag --------------------------------
-if test x$enable_id3 = xyes; then
-	PKG_CHECK_MODULES([ID3TAG], [id3tag],,
-		AC_CHECK_LIB(id3tag, id3_file_open,
-			[ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""],
-			enable_id3=no))
-fi
-
+MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [],
+	[id3tag], [libid3tag not found])
 if test x$enable_id3 = xyes; then
 	AC_DEFINE(HAVE_ID3TAG, 1, [Define to use id3tag])
 fi
@@ -530,36 +525,39 @@ dnl ---------------------------------------------------------------------------
 dnl --------------------------------- zeroconf --------------------------------
 
 case $with_zeroconf in
-no|avahi|bonjour)
+no|bonjour)
+	enable_avahi=no
 	;;
+
+avahi)
+	enable_avahi=yes
+	;;
+
 *)
 	with_zeroconf=auto
+	enable_avahi=auto
 	;;
 esac
 
-if test x$with_zeroconf != xno; then
-	if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then
-		PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib],
-			 [found_avahi=1;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]
-			 MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS",
-			 [found_avahi=0])
-	fi
+MPD_AUTO_PKG(avahi, AVAHI, [avahi-client avahi-glib],
+	[avahi client library], [avahi client+glib not found])
+if test x$enable_avahi = xyes; then
+	AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])
+	with_zeroconf=avahi
+fi
 
-	if test x$found_avahi = x1; then
-		with_zeroconf=avahi
-	elif test x$with_zeroconf = xavahi; then
-		AC_MSG_ERROR([Avahi support requested but not found])
-	fi
+AM_CONDITIONAL(HAVE_AVAHI, test x$enable_avahi = xyes)
 
+enable_bounjour=no
+if test x$with_zeroconf != xno; then
 	if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then
 		AC_CHECK_HEADER(dns_sd.h,
-			[found_bonjour=1;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])],
-			[found_bonjour=0])
+			[enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])])
 		AC_CHECK_LIB(dns_sd, DNSServiceRegister,
 			MPD_LIBS="$MPD_LIBS -ldns_sd")
 	fi
 
-	if test x$found_bonjour = x1; then
+	if test x$enable_bonjour = xyes; then
 		with_zeroconf=bonjour
 	elif test x$with_zeroconf = xbonjour; then
 		AC_MSG_ERROR([Bonjour support requested but not found])
@@ -574,7 +572,6 @@ if test x$with_zeroconf != xno; then
 fi
 
 AM_CONDITIONAL(HAVE_ZEROCONF, test x$with_zeroconf != xno)
-AM_CONDITIONAL(HAVE_AVAHI, test x$with_zeroconf = xavahi)
 AM_CONDITIONAL(HAVE_BONJOUR, test x$with_zeroconf = xbonjour)
 
 dnl ---------------------------------------------------------------------------
@@ -634,11 +631,6 @@ if test x$enable_lastfm = xyes; then
 fi
 AM_CONDITIONAL(ENABLE_LASTFM, test x$enable_lastfm = xyes)
 
-dnl ---------------------------------- libogg ---------------------------------
-if test x$with_tremor = xno || test -z $with_tremor; then
-	PKG_CHECK_MODULES(OGG, [ogg], enable_ogg=yes, enable_ogg=no)
-fi
-
 dnl ---------------------------------- libmms ---------------------------------
 MPD_AUTO_PKG(mms, MMS, [libmms >= 0.4],
 	[libmms mms:// protocol support], [libmms not found])
@@ -753,10 +745,12 @@ fi
 AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes)
 
 dnl ----------------------------------- FLAC ----------------------------------
+
+MPD_AUTO_PKG(flac, FLAC, [flac >= 1.1],
+	[FLAC decoder], [libFLAC not found])
+
 if test x$enable_flac = xyes; then
-	PKG_CHECK_MODULES(FLAC, [flac >= 1.1],
-		AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support]),
-		enable_flac=no)
+	AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support])
 
 	oldcflags="$CFLAGS"
 	oldlibs="$LIBS"
@@ -771,12 +765,10 @@ if test x$enable_flac = xyes; then
 	LIBS="$oldlibs"
 
 	if test x$enable_oggflac = xflac; then
-		if test x$enable_ogg = xyes; then
-			FLAC_LIBS="${FLAC_LIBS} -logg"
-		else
-			enable_oggflac=yes
-			AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")
-		fi
+		PKG_CHECK_MODULES(OGG, [ogg],
+			[FLAC_LIBS="${FLAC_LIBS} ${OGG_LIBS}" FLAC_CFLAGS="${FLAC_CFLAGS} ${OGG_CFLAGS}"],
+			[enable_oggflac=yes;
+			AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")])
 	fi
 fi
 
@@ -802,7 +794,8 @@ if test x$enable_gme = xyes; then
 fi
 
 dnl ---------------------------------- libmad ---------------------------------
-MPD_AUTO_PKG(mad, MAD, [mad],
+MPD_AUTO_PKG_LIB(mad, MAD, [mad],
+	mad, mad_stream_init, [-lmad], [],
 	[libmad MP3 decoder plugin], [libmad not found])
 if test x$enable_mad = xyes; then
 	AC_DEFINE(HAVE_MAD, 1, [Define to use libmad])
@@ -943,7 +936,7 @@ fi
 if test x$enable_tremor = xyes; then
 	AC_DEFINE(HAVE_TREMOR,1,
 		[Define to use tremor (libvorbisidec) for ogg support])
-	AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]),
+	AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support])
 else
 	TREMOR_CFLAGS=
 	TREMOR_LIBS=
@@ -972,18 +965,18 @@ fi
 AM_CONDITIONAL(HAVE_OGGFLAC, test x$enable_oggflac = xyes)
 
 dnl -------------------------------- Ogg Vorbis -------------------------------
-if test x$enable_vorbis = xyes; then
-	if test x$enable_tremor = xyes; then
+
+if test x$enable_tremor = xyes; then
+	if test x$enable_vorbis = xyes; then
 		AC_MSG_WARN(["OggTremor detected, could not enable Vorbis."])
-		enable_vorbis=no
-	elif test x$enable_ogg = xyes; then
-		PKG_CHECK_MODULES(VORBIS, [vorbis vorbisfile],
-			AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]),
-			enable_vorbis=no)
-	else
-		AC_MSG_WARN(["Ogg not detected, could not enable Vorbis."])
-		enable_vorbis=no
 	fi
+	enable_vorbis=no
+fi
+
+MPD_AUTO_PKG(vorbis, VORBIS, [vorbis vorbisfile ogg],
+	[Ogg Vorbis decoder], [libvorbis not found])
+if test x$enable_vorbis = xyes; then
+	AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support])
 fi
 
 AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes)
diff --git a/doc/developer.xml b/doc/developer.xml
index c63e2c2..010b850 100644
--- a/doc/developer.xml
+++ b/doc/developer.xml
@@ -57,7 +57,7 @@
           Some example code:
         </para>
 
-        <programlisting lang="C">static inline bool
+        <programlisting lang="C">static inline int
 foo(const char *abc, int xyz)
 {
         if (abc == NULL) {
diff --git a/doc/protocol.xml b/doc/protocol.xml
index 3eb5aa9..0b4f0d1 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -8,12 +8,38 @@
     <title>General protocol syntax</title>
 
     <section>
-      <title>Requests</title>
+      <title>Protocol overview</title>
+
+      <para>
+        The MPD command protocol exchanges line-based text records
+        between client and server over TCP.  Once the client is
+        connected to the server, they conduct a conversation until the
+        client closes the connection. The conversation flow is always
+        initiated by the client.
+      </para>
+
+      <para>
+        The client transmits a command sequence, terminated by the
+        newline character <constant>\n</constant>.  The server will
+        respond with one or more lines, the last of which will be a
+        completion code.
+      </para>
 
       <para>
-        If arguments contain spaces, they should be surrounded by double quotation
-        marks.
+        When the client connects to the server, the server will answer
+        with the following line:
+
+        <synopsis>OK MPD version</synopsis>
+
+        where <varname>version</varname> is a version identifier such as
+        0.12.2.  This version identifier is the version of the protocol
+        spoken, not the real version of the daemon.  (There is no way to
+        retrieve this real version identifier from the connection.)
       </para>
+    </section>
+
+    <section>
+      <title>Requests</title>
 
       <cmdsynopsis>
         <command>COMMAND</command>
@@ -21,6 +47,16 @@
       </cmdsynopsis>
 
       <para>
+        If arguments contain spaces, they should be surrounded by double
+        quotation marks.
+      </para>
+
+      <para>
+        Argument strings are separated from the command and any other
+        arguments by linear white-space (' ' or '\t').
+      </para>
+
+      <para>
         All data between the client and the server is encoded in
         UTF-8. (Note: In UTF-8 all standard ansi characters, 0-127 are
         the same as a standard ansi encoding.  Also, no ansi character
@@ -38,13 +74,97 @@
       <title>Responses</title>
 
       <para>
-        A command returns <returnvalue>OK</returnvalue> on completion
-        or <returnvalue>ACK some error</returnvalue> on failure.
-        These denote the end of command execution.
+        A command returns <returnvalue>OK</returnvalue> on completion or
+        <returnvalue>ACK some error</returnvalue> on failure.  These
+        denote the end of command execution.
       </para>
+
+      <section>
+        <title>Failure responses</title>
+
+        <para>
+          The nature of the error can be gleaned from the information
+          that follows the <returnvalue>ACK</returnvalue>.
+          <returnvalue>ACK</returnvalue> lines are of the form:
+
+          <synopsis>ACK [error at command_listNum] {current_command} message_text\n</synopsis>
+
+          These responses are generated by a call to
+          <function>commandError</function>. They contain four separate
+          terms. Let's look at each of them:
+
+          <itemizedlist>
+            <listitem>
+              <para>
+                <returnvalue>error</returnvalue>: numeric value of one
+                of the <constant>ACK_ERROR</constant> constants defined
+                in <filename>ack.h</filename>.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>command_listNum</returnvalue>:
+                offset of the command that caused the error in a <link
+                  linkend="command_lists">Command List</link>.
+                An error will always cause a command list to terminate
+                at the command that causes the error.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>current_command</returnvalue>:
+                name of the command, in a <link
+                  linkend="command_lists">Command List</link>,
+                that was executing when the error occurred.
+              </para>
+            </listitem>
+            <listitem>
+              <para>
+                <returnvalue>message_text</returnvalue>:
+                some (hopefully) informative text that describes the
+                nature of the error.
+              </para>
+            </listitem>
+          </itemizedlist>
+        </para>
+
+        <example>
+          <title>foo</title>
+          <para>
+            An example might help. Consider the following sequence
+            sent from the client to the server.
+
+            <synopsis>
+              command_list_begin
+              volume 86
+              play 10240
+              status
+              command_list_end
+            </synopsis>
+          </para>
+
+          <para>
+            The server responds with:
+
+            <returnvalue>
+              ACK [50 at 1] {play} song doesn't exist: "10240"
+            </returnvalue>
+          </para>
+
+          <para>
+            This tells us that the play command, which was the
+            second in the list (the first or only command is
+            numbered 0), failed with error 50.  The number 50
+            translates to <constant>ACK_ERROR_NO_EXIST</constant>--the
+            song doesn't exist.  This is reiterated by the message text
+            which also tells us which song doesn't exist.
+          </para>
+
+        </example>
+      </section>
     </section>
 
-    <section>
+    <section id="command_lists">
       <title>Command lists</title>
 
       <para>
diff --git a/doc/user.xml b/doc/user.xml
index 17bbdf9..6a98710 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -446,7 +446,7 @@ cd mpd-version</programlisting>
       </para>
 
       <para>
-        To configure a filter, add a
+        To configure a playlist plugin, add a
         <varname>playlist_plugin</varname> block to
         <filename>mpd.conf</filename>:
       </para>
diff --git a/m4/mpd_auto.m4 b/m4/mpd_auto.m4
index 3f23393..23713d5 100644
--- a/m4/mpd_auto.m4
+++ b/m4/mpd_auto.m4
@@ -63,3 +63,18 @@ AC_DEFUN([MPD_AUTO_PKG], [
 
 	MPD_AUTO_RESULT([$1], [$4], [$5])
 ])
+
+dnl Check with pkg-config first, fall back to AC_CHECK_LIB.
+dnl
+dnl Parameters: varname1, varname2, pkgname, libname, symname, libs, cflags, description, errmsg
+AC_DEFUN([MPD_AUTO_PKG_LIB], [
+	if eval "test x`echo '$'enable_$1` != xno"; then
+		PKG_CHECK_MODULES([$2], [$3],
+			[eval "found_$1=yes"],
+			AC_CHECK_LIB($4, $5,
+				[eval "found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'"],
+				[eval "found_$1=no"]))
+	fi
+
+	MPD_AUTO_RESULT([$1], [$8], [$9])
+])
diff --git a/scripts/makedist.sh b/scripts/makedist.sh
index d342cea..7f8624d 100755
--- a/scripts/makedist.sh
+++ b/scripts/makedist.sh
@@ -3,7 +3,7 @@ PWD=`pwd`
 
 ## If we're not in the scripts directory
 ## assume the base directory.
-if test "`basename $PWD`" == "scripts"; then
+if test "`basename $PWD`" = "scripts"; then
 	cd ../
 else
 	MYOLDPWD=`pwd`
@@ -18,7 +18,7 @@ fi
 make
 make dist
 
-if test "`basename $PWD`" == "scripts"; then
+if test "`basename $PWD`" = "scripts"; then
 	cd contrib/
 else
 	cd $MYOLDPWD
diff --git a/src/ape.c b/src/ape.c
index 5fca98e..5f4da3f 100644
--- a/src/ape.c
+++ b/src/ape.c
@@ -60,8 +60,10 @@ ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx)
 	assert(remaining > 10);
 
 	char *buffer = g_malloc(remaining);
-	if (fread(buffer, 1, remaining, fp) != remaining)
+	if (fread(buffer, 1, remaining, fp) != remaining) {
+		g_free(buffer);
 		return false;
+	}
 
 	/* read tags */
 	unsigned n = GUINT32_FROM_LE(footer.count);
diff --git a/src/conf.c b/src/conf.c
index 7059420..14dac93 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -367,6 +367,7 @@ config_read_file(const char *file, GError **error_r)
 			assert(*line != 0);
 			g_propagate_prefixed_error(error_r, error,
 						   "line %i: ", count);
+			fclose(fp);
 			return false;
 		}
 
@@ -378,6 +379,7 @@ config_read_file(const char *file, GError **error_r)
 			g_set_error(error_r, config_quark(), 0,
 				    "unrecognized parameter in config file at "
 				    "line %i: %s\n", count, name);
+			fclose(fp);
 			return false;
 		}
 
@@ -387,6 +389,7 @@ config_read_file(const char *file, GError **error_r)
 				    "config parameter \"%s\" is first defined "
 				    "on line %i and redefined on line %i\n",
 				    name, param->line, count);
+			fclose(fp);
 			return false;
 		}
 
@@ -398,6 +401,7 @@ config_read_file(const char *file, GError **error_r)
 			if (*line != '{') {
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: '{' expected", count);
+				fclose(fp);
 				return false;
 			}
 
@@ -406,12 +410,15 @@ config_read_file(const char *file, GError **error_r)
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: Unknown tokens after '{'",
 					    count);
+				fclose(fp);
 				return false;
 			}
 
 			param = config_read_block(fp, &count, string, error_r);
-			if (param == NULL)
+			if (param == NULL) {
+				fclose(fp);
 				return false;
+			}
 		} else {
 			/* a string value */
 
@@ -428,6 +435,7 @@ config_read_file(const char *file, GError **error_r)
 					g_error_free(error);
 				}
 
+				fclose(fp);
 				return false;
 			}
 
@@ -435,6 +443,7 @@ config_read_file(const char *file, GError **error_r)
 				g_set_error(error_r, config_quark(), 0,
 					    "line %i: Unknown tokens after value",
 					    count);
+				fclose(fp);
 				return false;
 			}
 
diff --git a/src/database.c b/src/database.c
index f255d6c..9f29f95 100644
--- a/src/database.c
+++ b/src/database.c
@@ -180,7 +180,7 @@ db_check(void)
 		}
 
 		/* Check if we can write to the directory */
-		if (access(dirPath, R_OK | W_OK)) {
+		if (access(dirPath, X_OK | W_OK)) {
 			g_warning("Can't create db file in \"%s\": %s",
 				  dirPath, strerror(errno));
 			g_free(dirPath);
diff --git a/src/decoder/ffmpeg_decoder_plugin.c b/src/decoder/ffmpeg_decoder_plugin.c
index 6d794db..70628df 100644
--- a/src/decoder/ffmpeg_decoder_plugin.c
+++ b/src/decoder/ffmpeg_decoder_plugin.c
@@ -89,7 +89,11 @@ struct mpd_ffmpeg_stream {
 	struct decoder *decoder;
 	struct input_stream *input;
 
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
+	AVIOContext *io;
+#else
 	ByteIOContext *io;
+#endif
 	unsigned char buffer[8192];
 };
 
@@ -135,6 +139,33 @@ mpd_ffmpeg_stream_open(struct decoder *decoder, struct input_stream *input)
 	return stream;
 }
 
+/**
+ * API compatibility wrapper for av_open_input_stream() and
+ * avformat_open_input().
+ */
+static int
+mpd_ffmpeg_open_input(AVFormatContext **ic_ptr,
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(52,101,0)
+		      AVIOContext *pb,
+#else
+		      ByteIOContext *pb,
+#endif
+		      const char *filename,
+		      AVInputFormat *fmt)
+{
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53,1,3)
+	AVFormatContext *context = avformat_alloc_context();
+	if (context == NULL)
+		return AVERROR(ENOMEM);
+
+	context->pb = pb;
+	*ic_ptr = context;
+	return avformat_open_input(ic_ptr, filename, fmt, NULL);
+#else
+	return av_open_input_stream(ic_ptr, pb, filename, fmt, NULL);
+#endif
+}
+
 static void
 mpd_ffmpeg_stream_close(struct mpd_ffmpeg_stream *stream)
 {
@@ -321,9 +352,9 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
 	}
 
 	//ffmpeg works with ours "fileops" helper
-	AVFormatContext *format_context;
-	if (av_open_input_stream(&format_context, stream->io, input->uri,
-				 input_format, NULL) != 0) {
+	AVFormatContext *format_context = NULL;
+	if (mpd_ffmpeg_open_input(&format_context, stream->io, input->uri,
+				  input_format) != 0) {
 		g_warning("Open failed\n");
 		mpd_ffmpeg_stream_close(stream);
 		return;
@@ -446,13 +477,26 @@ static const ffmpeg_tag_map ffmpeg_tag_maps[] = {
 };
 
 static bool
-ffmpeg_copy_metadata(struct tag *tag, AVMetadata *m,
+ffmpeg_copy_metadata(struct tag *tag,
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
+		     AVDictionary *m,
+#else
+		     AVMetadata *m,
+#endif
 		     const ffmpeg_tag_map tag_map)
 {
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(53,1,0)
+	AVDictionaryEntry *mt = NULL;
+
+	while ((mt = av_dict_get(m, tag_map.name, mt, 0)) != NULL)
+		tag_add_item(tag, tag_map.type, mt->value);
+#else
 	AVMetadataTag *mt = NULL;
 
 	while ((mt = av_metadata_get(m, tag_map.name, mt, 0)) != NULL)
 		tag_add_item(tag, tag_map.type, mt->value);
+#endif
+
 	return mt != NULL;
 }
 
@@ -470,9 +514,9 @@ ffmpeg_stream_tag(struct input_stream *is)
 	if (stream == NULL)
 		return NULL;
 
-	AVFormatContext *f;
-	if (av_open_input_stream(&f, stream->io, is->uri,
-				 input_format, NULL) != 0) {
+	AVFormatContext *f = NULL;
+	if (mpd_ffmpeg_open_input(&f, stream->io, is->uri,
+				  input_format) != 0) {
 		mpd_ffmpeg_stream_close(stream);
 		return NULL;
 	}
diff --git a/src/decoder/flac_metadata.c b/src/decoder/flac_metadata.c
index f2f2f95..5b94fd4 100644
--- a/src/decoder/flac_metadata.c
+++ b/src/decoder/flac_metadata.c
@@ -224,7 +224,8 @@ flac_tag_apply_metadata(struct tag *tag, const char *track,
 		break;
 
 	case FLAC__METADATA_TYPE_STREAMINFO:
-		tag->time = flac_duration(&block->data.stream_info);
+		if (block->data.stream_info.sample_rate > 0)
+			tag->time = flac_duration(&block->data.stream_info);
 		break;
 
 	default:
diff --git a/src/decoder/flac_metadata.h b/src/decoder/flac_metadata.h
index 06e691d..e52b0fb 100644
--- a/src/decoder/flac_metadata.h
+++ b/src/decoder/flac_metadata.h
@@ -20,6 +20,7 @@
 #ifndef MPD_FLAC_METADATA_H
 #define MPD_FLAC_METADATA_H
 
+#include <assert.h>
 #include <stdbool.h>
 #include <FLAC/metadata.h>
 
@@ -29,6 +30,8 @@ struct replay_gain_info;
 static inline unsigned
 flac_duration(const FLAC__StreamMetadata_StreamInfo *stream_info)
 {
+	assert(stream_info->sample_rate > 0);
+
 	return (stream_info->total_samples + stream_info->sample_rate - 1) /
 		stream_info->sample_rate;
 }
diff --git a/src/decoder/mpcdec_decoder_plugin.c b/src/decoder/mpcdec_decoder_plugin.c
index 4df8dd2..eaf470a 100644
--- a/src/decoder/mpcdec_decoder_plugin.c
+++ b/src/decoder/mpcdec_decoder_plugin.c
@@ -153,7 +153,6 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
 	mpc_uint32_t ret;
 	int32_t chunk[G_N_ELEMENTS(sample_buffer)];
 	long bit_rate = 0;
-	mpc_uint32_t vbr_update_acc;
 	mpc_uint32_t vbr_update_bits;
 	enum decoder_command cmd = DECODE_COMMAND_NONE;
 
@@ -243,10 +242,11 @@ mpcdec_decode(struct decoder *mpd_decoder, struct input_stream *is)
 				decoder_seek_error(mpd_decoder);
 		}
 
-		vbr_update_acc = 0;
 		vbr_update_bits = 0;
 
 #ifdef MPC_IS_OLD_API
+		mpc_uint32_t vbr_update_acc = 0;
+
 		ret = mpc_decoder_decode(&decoder, sample_buffer,
 					 &vbr_update_acc, &vbr_update_bits);
 		if (ret == 0 || ret == (mpc_uint32_t)-1)
diff --git a/src/decoder/wavpack_decoder_plugin.c b/src/decoder/wavpack_decoder_plugin.c
index efed988..24d0c17 100644
--- a/src/decoder/wavpack_decoder_plugin.c
+++ b/src/decoder/wavpack_decoder_plugin.c
@@ -34,9 +34,6 @@
 #undef G_LOG_DOMAIN
 #define G_LOG_DOMAIN "wavpack"
 
-/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */
-#define CHUNK_SIZE		1020
-
 #define ERRORLEN 80
 
 static struct {
@@ -162,8 +159,6 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
 	enum sample_format sample_format;
 	struct audio_format audio_format;
 	format_samples_t format_samples;
-	char chunk[CHUNK_SIZE];
-	int samples_requested, samples_got;
 	float total_time;
 	int bytes_per_sample, output_sample_size;
 
@@ -193,12 +188,15 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
 	output_sample_size = audio_format_frame_size(&audio_format);
 
 	/* wavpack gives us all kind of samples in a 32-bit space */
-	samples_requested = sizeof(chunk) / (4 * audio_format.channels);
+	int32_t chunk[1024];
+	const uint32_t samples_requested = G_N_ELEMENTS(chunk) /
+		audio_format.channels;
 
 	decoder_initialized(decoder, &audio_format, can_seek, total_time);
 
-	do {
-		if (decoder_get_command(decoder) == DECODE_COMMAND_SEEK) {
+	enum decoder_command cmd = decoder_get_command(decoder);
+	while (cmd != DECODE_COMMAND_STOP) {
+		if (cmd == DECODE_COMMAND_SEEK) {
 			if (can_seek) {
 				unsigned where = decoder_seek_where(decoder) *
 					audio_format.sample_rate;
@@ -213,29 +211,20 @@ wavpack_decode(struct decoder *decoder, WavpackContext *wpc, bool can_seek)
 			}
 		}
 
-		if (decoder_get_command(decoder) == DECODE_COMMAND_STOP) {
+		uint32_t samples_got = WavpackUnpackSamples(wpc, chunk,
+							    samples_requested);
+		if (samples_got == 0)
 			break;
-		}
 
-		samples_got = WavpackUnpackSamples(
-			wpc, (int32_t *)chunk, samples_requested
-		);
-		if (samples_got > 0) {
-			int bitrate = (int)(WavpackGetInstantBitrate(wpc) /
-			              1000 + 0.5);
-
-			format_samples(
-				bytes_per_sample, chunk,
-				samples_got * audio_format.channels
-			);
-
-			decoder_data(
-				decoder, NULL, chunk,
-				samples_got * output_sample_size,
-				bitrate
-			);
-		}
-	} while (samples_got > 0);
+		int bitrate = (int)(WavpackGetInstantBitrate(wpc) / 1000 +
+				    0.5);
+		format_samples(bytes_per_sample, chunk,
+			       samples_got * audio_format.channels);
+
+		cmd = decoder_data(decoder, NULL, chunk,
+				   samples_got * output_sample_size,
+				   bitrate);
+	}
 }
 
 /**
diff --git a/src/encoder/vorbis_encoder.c b/src/encoder/vorbis_encoder.c
index 08147be..38a998b 100644
--- a/src/encoder/vorbis_encoder.c
+++ b/src/encoder/vorbis_encoder.c
@@ -266,6 +266,15 @@ vorbis_encoder_flush(struct encoder *_encoder, G_GNUC_UNUSED GError **error)
 {
 	struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
 
+	encoder->flush = true;
+	return true;
+}
+
+static bool
+vorbis_encoder_pre_tag(struct encoder *_encoder, G_GNUC_UNUSED GError **error)
+{
+	struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+
 	vorbis_analysis_wrote(&encoder->vd, 0);
 	vorbis_encoder_blockout(encoder);
 
@@ -366,6 +375,7 @@ vorbis_encoder_read(struct encoder *_encoder, void *_dest, size_t length)
 	if (ret == 0 && encoder->flush) {
 		encoder->flush = false;
 		ret = ogg_stream_flush(&encoder->os, &page);
+
 	}
 
 	if (ret == 0)
@@ -398,6 +408,7 @@ const struct encoder_plugin vorbis_encoder_plugin = {
 	.open = vorbis_encoder_open,
 	.close = vorbis_encoder_close,
 	.flush = vorbis_encoder_flush,
+	.pre_tag = vorbis_encoder_pre_tag,
 	.tag = vorbis_encoder_tag,
 	.write = vorbis_encoder_write,
 	.read = vorbis_encoder_read,
diff --git a/src/encoder_plugin.h b/src/encoder_plugin.h
index 13fb231..fb00413 100644
--- a/src/encoder_plugin.h
+++ b/src/encoder_plugin.h
@@ -50,6 +50,8 @@ struct encoder_plugin {
 
 	bool (*flush)(struct encoder *encoder, GError **error);
 
+	bool (*pre_tag)(struct encoder *encoder, GError **error);
+
 	bool (*tag)(struct encoder *encoder, const struct tag *tag,
 		    GError **error);
 
@@ -148,8 +150,30 @@ encoder_flush(struct encoder *encoder, GError **error)
 }
 
 /**
+ * Prepare for sending a tag to the encoder.  This is used by some
+ * encoders to flush the previous sub-stream, in preparation to begin
+ * a new one.
+ *
+ * @param encoder the encoder
+ * @param tag the tag object
+ * @param error location to store the error occuring, or NULL to ignore errors.
+ * @return true on success
+ */
+static inline bool
+encoder_pre_tag(struct encoder *encoder, GError **error)
+{
+	/* this method is optional */
+	return encoder->plugin->pre_tag != NULL
+		? encoder->plugin->pre_tag(encoder, error)
+		: true;
+}
+
+/**
  * Sends a tag to the encoder.
  *
+ * Instructions: call encoder_pre_tag(); then obtain flushed data with
+ * encoder_read(); finally call encoder_tag().
+ *
  * @param encoder the encoder
  * @param tag the tag object
  * @param error location to store the error occuring, or NULL to ignore errors.
diff --git a/src/input/curl_input_plugin.c b/src/input/curl_input_plugin.c
index ae645bd..2c4ac2f 100644
--- a/src/input/curl_input_plugin.c
+++ b/src/input/curl_input_plugin.c
@@ -43,6 +43,13 @@
 #define G_LOG_DOMAIN "input_curl"
 
 /**
+ * Do not buffer more than this number of bytes.  It should be a
+ * reasonable limit that doesn't make low-end machines suffer too
+ * much, but doesn't cause stuttering on high-latency lines.
+ */
+static const size_t CURL_MAX_BUFFERED = 512 * 1024;
+
+/**
  * Buffers created by input_curl_writefunction().
  */
 struct buffer {
@@ -144,6 +151,25 @@ input_curl_finish(void)
 	curl_global_cleanup();
 }
 
+/**
+ * Determine the total sizes of all buffers, including portions that
+ * have already been consumed.
+ */
+G_GNUC_PURE
+static size_t
+curl_total_buffer_size(const struct input_curl *c)
+{
+	size_t total = 0;
+
+	for (GList *i = g_queue_peek_head_link(c->buffers);
+	     i != NULL; i = g_list_next(i)) {
+		struct buffer *buffer = i->data;
+		total += buffer->size;
+	}
+
+	return total;
+}
+
 static void
 buffer_free_callback(gpointer data, G_GNUC_UNUSED gpointer user_data)
 {
@@ -473,6 +499,10 @@ static int
 input_curl_buffer(struct input_stream *is, GError **error_r)
 {
 	struct input_curl *c = (struct input_curl *)is;
+
+	if (curl_total_buffer_size(c) >= CURL_MAX_BUFFERED)
+		return 0;
+
 	CURLMcode mcode;
 	int running_handles;
 	bool ret;
@@ -650,6 +680,9 @@ input_curl_easy_init(struct input_curl *c, GError **error_r)
 	curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5);
 	curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true);
 	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);
+	curl_easy_setopt(c->easy, CURLOPT_CONNECTTIMEOUT, 10l);
 
 	if (proxy != NULL)
 		curl_easy_setopt(c->easy, CURLOPT_PROXY, proxy);
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c
index 9177fab..422264f 100644
--- a/src/output/alsa_plugin.c
+++ b/src/output/alsa_plugin.c
@@ -508,6 +508,14 @@ configure_hw:
 	g_debug("buffer_size=%u period_size=%u",
 		(unsigned)alsa_buffer_size, (unsigned)alsa_period_size);
 
+	if (alsa_period_size == 0)
+		/* this works around a SIGFPE bug that occurred when
+		   an ALSA driver indicated period_size==0; this
+		   caused a division by zero in alsa_play().  By using
+		   the fallback "1", we make sure that this won't
+		   happen again. */
+		alsa_period_size = 1;
+
 	ad->period_frames = alsa_period_size;
 	ad->period_position = 0;
 
diff --git a/src/output/ao_plugin.c b/src/output/ao_plugin.c
index 6fedbc6..42ece5a 100644
--- a/src/output/ao_plugin.c
+++ b/src/output/ao_plugin.c
@@ -106,12 +106,14 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 		g_set_error(error, ao_output_quark(), 0,
 			    "\"%s\" is not a valid ao driver",
 			    value);
+		g_free(ad);
 		return NULL;
 	}
 
 	if ((ai = ao_driver_info(ad->driver)) == NULL) {
 		g_set_error(error, ao_output_quark(), 0,
 			    "problems getting driver info");
+		g_free(ad);
 		return NULL;
 	}
 
@@ -129,6 +131,7 @@ ao_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 				g_set_error(error, ao_output_quark(), 0,
 					    "problems parsing options \"%s\"",
 					    options[i]);
+				g_free(ad);
 				return NULL;
 			}
 
diff --git a/src/output/httpd_client.c b/src/output/httpd_client.c
index f5e1492..1119a78 100644
--- a/src/output/httpd_client.c
+++ b/src/output/httpd_client.c
@@ -143,6 +143,8 @@ httpd_client_unref_page(gpointer data, G_GNUC_UNUSED gpointer user_data)
 void
 httpd_client_free(struct httpd_client *client)
 {
+	assert(client != NULL);
+
 	if (client->state == RESPONSE) {
 		if (client->write_source_id != 0)
 			g_source_remove(client->write_source_id);
@@ -169,6 +171,8 @@ httpd_client_free(struct httpd_client *client)
 static void
 httpd_client_close(struct httpd_client *client)
 {
+	assert(client != NULL);
+
 	httpd_output_remove_client(client->httpd, client);
 	httpd_client_free(client);
 }
@@ -179,6 +183,9 @@ httpd_client_close(struct httpd_client *client)
 static void
 httpd_client_begin_response(struct httpd_client *client)
 {
+	assert(client != NULL);
+	assert(client->state != RESPONSE);
+
 	client->state = RESPONSE;
 	client->write_source_id = 0;
 	client->pages = g_queue_new();
@@ -239,6 +246,9 @@ httpd_client_handle_line(struct httpd_client *client, const char *line)
 static char *
 httpd_client_read_line(struct httpd_client *client)
 {
+	assert(client != NULL);
+	assert(client->state != RESPONSE);
+
 	const char *p, *newline;
 	size_t length;
 	char *line;
@@ -271,6 +281,7 @@ httpd_client_send_response(struct httpd_client *client)
 	GIOStatus status;
 	gsize bytes_written;
 
+	assert(client != NULL);
 	assert(client->state == RESPONSE);
 
 	if (!client->metadata_requested) {
@@ -334,14 +345,19 @@ httpd_client_send_response(struct httpd_client *client)
 static bool
 httpd_client_received(struct httpd_client *client)
 {
+	assert(client != NULL);
+	assert(client->state != RESPONSE);
+
 	char *line;
 	bool success;
 
 	while ((line = httpd_client_read_line(client)) != NULL) {
 		success = httpd_client_handle_line(client, line);
 		g_free(line);
-		if (!success)
+		if (!success) {
+			assert(client->state != RESPONSE);
 			return false;
+		}
 
 		if (client->state == RESPONSE) {
 			if (!fifo_buffer_is_empty(client->input)) {
@@ -370,7 +386,14 @@ httpd_client_read(struct httpd_client *client)
 	if (client->state == RESPONSE) {
 		/* the client has already sent the request, and he
 		   must not send more */
-		g_warning("unexpected input from client");
+		char buffer[1];
+
+		status = g_io_channel_read_chars(client->channel, buffer,
+						 sizeof(buffer), &bytes_read,
+						 NULL);
+		if (status == G_IO_STATUS_NORMAL)
+			g_warning("unexpected input from client");
+
 		return false;
 	}
 
diff --git a/src/output/httpd_output_plugin.c b/src/output/httpd_output_plugin.c
index 6650d89..40ad05c 100644
--- a/src/output/httpd_output_plugin.c
+++ b/src/output/httpd_output_plugin.c
@@ -103,6 +103,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 	if (encoder_plugin == NULL) {
 		g_set_error(error, httpd_output_quark(), 0,
 			    "No such encoder: %s", encoder_name);
+		g_free(httpd);
 		return NULL;
 	}
 
@@ -492,7 +493,8 @@ httpd_output_pause(void *data)
 
 	if (has_clients) {
 		static const char silence[1020];
-		return httpd_output_play(data, silence, sizeof(silence), NULL);
+		return httpd_output_play(data, silence, sizeof(silence),
+					 NULL) > 0;
 	} else {
 		g_usleep(100000);
 		return true;
@@ -521,7 +523,7 @@ httpd_output_tag(void *data, const struct tag *tag)
 
 		/* flush the current stream, and end it */
 
-		encoder_flush(httpd->encoder, NULL);
+		encoder_pre_tag(httpd->encoder, NULL);
 		httpd_output_encoder_to_clients(httpd);
 
 		/* send the tag to the encoder - which starts a new
diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c
index ce82656..7639f3b 100644
--- a/src/output/osx_plugin.c
+++ b/src/output/osx_plugin.c
@@ -95,12 +95,6 @@ static void osx_output_close(void *data)
 {
 	struct osx_output *od = data;
 
-	g_mutex_lock(od->mutex);
-	while (od->len) {
-		g_cond_wait(od->condition, od->mutex);
-	}
-	g_mutex_unlock(od->mutex);
-
 	AudioOutputUnitStop(od->au);
 	AudioUnitUninitialize(od->au);
 	CloseComponent(od->au);
@@ -143,8 +137,8 @@ osx_render(void *vdata,
 	if (od->pos >= od->buffer_size)
 		od->pos = 0;
 
-	g_mutex_unlock(od->mutex);
 	g_cond_signal(od->condition);
+	g_mutex_unlock(od->mutex);
 
 	buffer->mDataByteSize = buffer_size;
 
diff --git a/src/output/pulse_output_plugin.c b/src/output/pulse_output_plugin.c
index d29fbd7..34d7365 100644
--- a/src/output/pulse_output_plugin.c
+++ b/src/output/pulse_output_plugin.c
@@ -207,6 +207,9 @@ pulse_output_subscribe_cb(pa_context *context,
 static bool
 pulse_output_connect(struct pulse_output *po, GError **error_r)
 {
+	assert(po != NULL);
+	assert(po->context != NULL);
+
 	int error;
 
 	error = pa_context_connect(po->context, po->server,
@@ -222,6 +225,44 @@ pulse_output_connect(struct pulse_output *po, GError **error_r)
 }
 
 /**
+ * Frees and clears the stream.
+ */
+static void
+pulse_output_delete_stream(struct pulse_output *po)
+{
+	assert(po != NULL);
+	assert(po->stream != NULL);
+
+#if PA_CHECK_VERSION(0,9,8)
+	pa_stream_set_suspended_callback(po->stream, NULL, NULL);
+#endif
+
+	pa_stream_set_state_callback(po->stream, NULL, NULL);
+	pa_stream_set_write_callback(po->stream, NULL, NULL);
+
+	pa_stream_disconnect(po->stream);
+	pa_stream_unref(po->stream);
+	po->stream = NULL;
+}
+
+/**
+ * Frees and clears the context.
+ */
+static void
+pulse_output_delete_context(struct pulse_output *po)
+{
+	assert(po != NULL);
+	assert(po->context != NULL);
+
+	pa_context_set_state_callback(po->context, NULL, NULL);
+	pa_context_set_subscribe_callback(po->context, NULL, NULL);
+
+	pa_context_disconnect(po->context);
+	pa_context_unref(po->context);
+	po->context = NULL;
+}
+
+/**
  * Create, set up and connect a context.
  *
  * @return true on success, false on error
@@ -229,6 +270,9 @@ pulse_output_connect(struct pulse_output *po, GError **error_r)
 static bool
 pulse_output_setup_context(struct pulse_output *po, GError **error_r)
 {
+	assert(po != NULL);
+	assert(po->mainloop != NULL);
+
 	po->context = pa_context_new(pa_threaded_mainloop_get_api(po->mainloop),
 				     MPD_PULSE_NAME);
 	if (po->context == NULL) {
@@ -243,25 +287,13 @@ pulse_output_setup_context(struct pulse_output *po, GError **error_r)
 					  pulse_output_subscribe_cb, po);
 
 	if (!pulse_output_connect(po, error_r)) {
-		pa_context_unref(po->context);
-		po->context = NULL;
+		pulse_output_delete_context(po);
 		return false;
 	}
 
 	return true;
 }
 
-/**
- * Frees and clears the context.
- */
-static void
-pulse_output_delete_context(struct pulse_output *po)
-{
-	pa_context_disconnect(po->context);
-	pa_context_unref(po->context);
-	po->context = NULL;
-}
-
 static void *
 pulse_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 		  const struct config_param *param,
@@ -347,6 +379,8 @@ pulse_output_disable(void *data)
 {
 	struct pulse_output *po = data;
 
+	assert(po->mainloop != NULL);
+
 	pa_threaded_mainloop_stop(po->mainloop);
 	if (po->context != NULL)
 		pulse_output_delete_context(po);
@@ -363,6 +397,8 @@ pulse_output_disable(void *data)
 static bool
 pulse_output_wait_connection(struct pulse_output *po, GError **error_r)
 {
+	assert(po->mainloop != NULL);
+
 	pa_context_state_t state;
 
 	pa_threaded_mainloop_lock(po->mainloop);
@@ -399,11 +435,32 @@ pulse_output_wait_connection(struct pulse_output *po, GError **error_r)
 	}
 }
 
+#if PA_CHECK_VERSION(0,9,8)
+
+static void
+pulse_output_stream_suspended_cb(G_GNUC_UNUSED pa_stream *stream, void *userdata)
+{
+	struct pulse_output *po = userdata;
+
+	assert(stream == po->stream || po->stream == NULL);
+	assert(po->mainloop != NULL);
+
+	/* wake up the main loop to break out of the loop in
+	   pulse_output_play() */
+	pa_threaded_mainloop_signal(po->mainloop, 0);
+}
+
+#endif
+
 static void
 pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
 {
 	struct pulse_output *po = userdata;
 
+	assert(stream == po->stream || po->stream == NULL);
+	assert(po->mainloop != NULL);
+	assert(po->context != NULL);
+
 	switch (pa_stream_get_state(stream)) {
 	case PA_STREAM_READY:
 		if (po->mixer != NULL)
@@ -432,6 +489,8 @@ pulse_output_stream_write_cb(G_GNUC_UNUSED pa_stream *stream, size_t nbytes,
 {
 	struct pulse_output *po = userdata;
 
+	assert(po->mainloop != NULL);
+
 	po->writable = nbytes;
 	pa_threaded_mainloop_signal(po->mainloop, 0);
 }
@@ -444,6 +503,8 @@ pulse_output_open(void *data, struct audio_format *audio_format,
 	pa_sample_spec ss;
 	int error;
 
+	assert(po->mainloop != NULL);
+
 	if (po->context != NULL) {
 		switch (pa_context_get_state(po->context)) {
 		case PA_CONTEXT_UNCONNECTED:
@@ -487,6 +548,11 @@ pulse_output_open(void *data, struct audio_format *audio_format,
 		return false;
 	}
 
+#if PA_CHECK_VERSION(0,9,8)
+	pa_stream_set_suspended_callback(po->stream,
+					 pulse_output_stream_suspended_cb, po);
+#endif
+
 	pa_stream_set_state_callback(po->stream,
 				     pulse_output_stream_state_cb, po);
 	pa_stream_set_write_callback(po->stream,
@@ -497,8 +563,7 @@ pulse_output_open(void *data, struct audio_format *audio_format,
 	error = pa_stream_connect_playback(po->stream, po->sink,
 					   NULL, 0, NULL, NULL);
 	if (error < 0) {
-		pa_stream_unref(po->stream);
-		po->stream = NULL;
+		pulse_output_delete_stream(po);
 
 		g_set_error(error_r, pulse_output_quark(), 0,
 			    "pa_stream_connect_playback() has failed: %s",
@@ -522,6 +587,8 @@ pulse_output_close(void *data)
 	struct pulse_output *po = data;
 	pa_operation *o;
 
+	assert(po->mainloop != NULL);
+
 	pa_threaded_mainloop_lock(po->mainloop);
 
 	if (pa_stream_get_state(po->stream) == PA_STREAM_READY) {
@@ -534,9 +601,7 @@ pulse_output_close(void *data)
 			pulse_wait_for_operation(po->mainloop, o);
 	}
 
-	pa_stream_disconnect(po->stream);
-	pa_stream_unref(po->stream);
-	po->stream = NULL;
+	pulse_output_delete_stream(po);
 
 	if (po->context != NULL &&
 	    pa_context_get_state(po->context) != PA_CONTEXT_READY)
@@ -556,6 +621,8 @@ pulse_output_check_stream(struct pulse_output *po)
 {
 	pa_stream_state_t state = pa_stream_get_state(po->stream);
 
+	assert(po->mainloop != NULL);
+
 	switch (state) {
 	case PA_STREAM_READY:
 	case PA_STREAM_FAILED:
@@ -637,6 +704,8 @@ pulse_output_stream_pause(struct pulse_output *po, bool pause,
 {
 	pa_operation *o;
 
+	assert(po->mainloop != NULL);
+	assert(po->context != NULL);
 	assert(po->stream != NULL);
 
 	o = pa_stream_cork(po->stream, pause,
@@ -667,6 +736,7 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r)
 	struct pulse_output *po = data;
 	int error;
 
+	assert(po->mainloop != NULL);
 	assert(po->stream != NULL);
 
 	pa_threaded_mainloop_lock(po->mainloop);
@@ -683,19 +753,30 @@ pulse_output_play(void *data, const void *chunk, size_t size, GError **error_r)
 	/* unpause if previously paused */
 
 	if (pulse_output_stream_is_paused(po) &&
-	    !pulse_output_stream_pause(po, false, error_r))
+	    !pulse_output_stream_pause(po, false, error_r)) {
+		pa_threaded_mainloop_unlock(po->mainloop);
 		return 0;
+	}
 
 	/* wait until the server allows us to write */
 
 	while (po->writable == 0) {
+#if PA_CHECK_VERSION(0,9,8)
+		if (pa_stream_is_suspended(po->stream)) {
+			pa_threaded_mainloop_unlock(po->mainloop);
+			g_set_error(error_r, pulse_output_quark(), 0,
+				    "suspended");
+			return 0;
+		}
+#endif
+
 		pa_threaded_mainloop_wait(po->mainloop);
 
 		if (pa_stream_get_state(po->stream) != PA_STREAM_READY) {
 			pa_threaded_mainloop_unlock(po->mainloop);
 			g_set_error(error_r, pulse_output_quark(), 0,
 				    "disconnected");
-			return false;
+			return 0;
 		}
 	}
 
@@ -725,6 +806,7 @@ pulse_output_cancel(void *data)
 	struct pulse_output *po = data;
 	pa_operation *o;
 
+	assert(po->mainloop != NULL);
 	assert(po->stream != NULL);
 
 	pa_threaded_mainloop_lock(po->mainloop);
@@ -756,6 +838,7 @@ pulse_output_pause(void *data)
 	struct pulse_output *po = data;
 	GError *error = NULL;
 
+	assert(po->mainloop != NULL);
 	assert(po->stream != NULL);
 
 	pa_threaded_mainloop_lock(po->mainloop);
diff --git a/src/output/recorder_output_plugin.c b/src/output/recorder_output_plugin.c
index c01d927..10d6410 100644
--- a/src/output/recorder_output_plugin.c
+++ b/src/output/recorder_output_plugin.c
@@ -79,23 +79,27 @@ recorder_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
 	if (encoder_plugin == NULL) {
 		g_set_error(error_r, recorder_output_quark(), 0,
 			    "No such encoder: %s", encoder_name);
-		return NULL;
+		goto failure;
 	}
 
 	recorder->path = config_get_block_string(param, "path", NULL);
 	if (recorder->path == NULL) {
 		g_set_error(error_r, recorder_output_quark(), 0,
 			    "'path' not configured");
-		return NULL;
+		goto failure;
 	}
 
 	/* initialize encoder */
 
 	recorder->encoder = encoder_init(encoder_plugin, param, error_r);
 	if (recorder->encoder == NULL)
-		return NULL;
+		goto failure;
 
 	return recorder;
+
+failure:
+	g_free(recorder);
+	return NULL;
 }
 
 static void
diff --git a/src/output/shout_plugin.c b/src/output/shout_plugin.c
index baaeccf..35efd9f 100644
--- a/src/output/shout_plugin.c
+++ b/src/output/shout_plugin.c
@@ -152,7 +152,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	if (port == 0) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "shout port must be configured");
-		return NULL;
+		goto failure;
 	}
 
 	check_block_param("password");
@@ -174,21 +174,21 @@ my_shout_init_driver(const struct audio_format *audio_format,
 				    "shout quality \"%s\" is not a number in the "
 				    "range -1 to 10, line %i",
 				    value, param->line);
-			return NULL;
+			goto failure;
 		}
 
 		if (config_get_block_string(param, "bitrate", NULL) != NULL) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "quality and bitrate are "
 				    "both defined");
-			return NULL;
+			goto failure;
 		}
 	} else {
 		value = config_get_block_string(param, "bitrate", NULL);
 		if (value == NULL) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "neither bitrate nor quality defined");
-			return NULL;
+			goto failure;
 		}
 
 		sd->bitrate = strtol(value, &test, 10);
@@ -196,7 +196,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 		if (*test != '\0' || sd->bitrate <= 0) {
 			g_set_error(error, shout_output_quark(), 0,
 				    "bitrate must be a positive integer");
-			return NULL;
+			goto failure;
 		}
 	}
 
@@ -206,12 +206,12 @@ my_shout_init_driver(const struct audio_format *audio_format,
 		g_set_error(error, shout_output_quark(), 0,
 			    "couldn't find shout encoder plugin \"%s\"",
 			    encoding);
-		return NULL;
+		goto failure;
 	}
 
 	sd->encoder = encoder_init(encoder_plugin, param, error);
 	if (sd->encoder == NULL)
-		return NULL;
+		goto failure;
 
 	if (strcmp(encoding, "mp3") == 0 || strcmp(encoding, "lame") == 0)
 		shout_format = SHOUT_FORMAT_MP3;
@@ -225,7 +225,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 			g_set_error(error, shout_output_quark(), 0,
 				    "you cannot stream \"%s\" to shoutcast, use mp3",
 				    encoding);
-			return NULL;
+			goto failure;
 		} else if (0 == strcmp(value, "shoutcast"))
 			protocol = SHOUT_PROTOCOL_ICY;
 		else if (0 == strcmp(value, "icecast1"))
@@ -237,7 +237,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 				    "shout protocol \"%s\" is not \"shoutcast\" or "
 				    "\"icecast1\"or \"icecast2\"",
 				    value);
-			return NULL;
+			goto failure;
 		}
 	} else {
 		protocol = SHOUT_PROTOCOL_HTTP;
@@ -256,7 +256,7 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	    shout_set_agent(sd->shout_conn, "MPD") != SHOUTERR_SUCCESS) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	/* optional paramters */
@@ -267,14 +267,14 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	if (value != NULL && shout_set_genre(sd->shout_conn, value)) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	value = config_get_block_string(param, "description", NULL);
 	if (value != NULL && shout_set_description(sd->shout_conn, value)) {
 		g_set_error(error, shout_output_quark(), 0,
 			    "%s", shout_get_error(sd->shout_conn));
-		return NULL;
+		goto failure;
 	}
 
 	{
@@ -300,6 +300,10 @@ my_shout_init_driver(const struct audio_format *audio_format,
 	}
 
 	return sd;
+
+failure:
+	free_shout_data(sd);
+	return NULL;
 }
 
 static bool
@@ -507,7 +511,7 @@ static void my_shout_set_tag(void *data,
 	if (sd->encoder->plugin->tag != NULL) {
 		/* encoder plugin supports stream tags */
 
-		ret = encoder_flush(sd->encoder, &error);
+		ret = encoder_pre_tag(sd->encoder, &error);
 		if (!ret) {
 			g_warning("%s", error->message);
 			g_error_free(error);
diff --git a/src/output_all.c b/src/output_all.c
index 19c0f01..4e0b2eb 100644
--- a/src/output_all.c
+++ b/src/output_all.c
@@ -206,26 +206,13 @@ static void audio_output_wait_all(void)
 }
 
 /**
- * Signals the audio output if it is open.  This function locks the
- * mutex.
- */
-static void
-audio_output_lock_signal(struct audio_output *ao)
-{
-	g_mutex_lock(ao->mutex);
-	if (audio_output_is_open(ao))
-		g_cond_signal(ao->cond);
-	g_mutex_unlock(ao->mutex);
-}
-
-/**
  * Signals all audio outputs which are open.
  */
 static void
-audio_output_signal_all(void)
+audio_output_allow_play_all(void)
 {
 	for (unsigned i = 0; i < num_audio_outputs; ++i)
-		audio_output_lock_signal(&audio_outputs[i]);
+		audio_output_allow_play(&audio_outputs[i]);
 }
 
 static void
@@ -530,7 +517,7 @@ audio_output_all_cancel(void)
 	/* the audio outputs are now waiting for a signal, to
 	   synchronize the cleared music pipe */
 
-	audio_output_signal_all();
+	audio_output_allow_play_all();
 
 	/* invalidate elapsed_time */
 
diff --git a/src/output_control.c b/src/output_control.c
index 0823b66..f8c5cd8 100644
--- a/src/output_control.c
+++ b/src/output_control.c
@@ -115,6 +115,8 @@ audio_output_open(struct audio_output *ao,
 {
 	bool open;
 
+	assert(ao != NULL);
+	assert(ao->allow_play);
 	assert(audio_format_valid(audio_format));
 	assert(mp != NULL);
 
@@ -140,10 +142,6 @@ audio_output_open(struct audio_output *ao,
 			/* we're not using audio_output_cancel() here,
 			   because that function is asynchronous */
 			ao_command(ao, AO_COMMAND_CANCEL);
-
-			/* the audio output is now waiting for a
-			   signal; wake it up immediately */
-			g_cond_signal(ao->cond);
 		}
 
 		return true;
@@ -181,6 +179,7 @@ static void
 audio_output_close_locked(struct audio_output *ao)
 {
 	assert(ao != NULL);
+	assert(ao->allow_play);
 
 	if (ao->mixer != NULL)
 		mixer_auto_close(ao->mixer);
@@ -223,6 +222,8 @@ audio_output_play(struct audio_output *ao)
 {
 	g_mutex_lock(ao->mutex);
 
+	assert(ao->allow_play);
+
 	if (audio_output_is_open(ao))
 		g_cond_signal(ao->cond);
 
@@ -238,6 +239,7 @@ void audio_output_pause(struct audio_output *ao)
 		mixer_auto_close(ao->mixer);
 
 	g_mutex_lock(ao->mutex);
+	assert(ao->allow_play);
 	if (audio_output_is_open(ao))
 		ao_command_async(ao, AO_COMMAND_PAUSE);
 	g_mutex_unlock(ao->mutex);
@@ -247,6 +249,7 @@ void
 audio_output_drain_async(struct audio_output *ao)
 {
 	g_mutex_lock(ao->mutex);
+	assert(ao->allow_play);
 	if (audio_output_is_open(ao))
 		ao_command_async(ao, AO_COMMAND_DRAIN);
 	g_mutex_unlock(ao->mutex);
@@ -255,8 +258,24 @@ audio_output_drain_async(struct audio_output *ao)
 void audio_output_cancel(struct audio_output *ao)
 {
 	g_mutex_lock(ao->mutex);
-	if (audio_output_is_open(ao))
+
+	if (audio_output_is_open(ao)) {
+		ao->allow_play = false;
 		ao_command_async(ao, AO_COMMAND_CANCEL);
+	}
+
+	g_mutex_unlock(ao->mutex);
+}
+
+void
+audio_output_allow_play(struct audio_output *ao)
+{
+	g_mutex_lock(ao->mutex);
+
+	ao->allow_play = true;
+	if (audio_output_is_open(ao))
+		g_cond_signal(ao->cond);
+
 	g_mutex_unlock(ao->mutex);
 }
 
@@ -287,6 +306,7 @@ void audio_output_finish(struct audio_output *ao)
 
 	if (ao->thread != NULL) {
 		g_mutex_lock(ao->mutex);
+		assert(ao->allow_play);
 		ao_command(ao, AO_COMMAND_KILL);
 		g_mutex_unlock(ao->mutex);
 		g_thread_join(ao->thread);
diff --git a/src/output_control.h b/src/output_control.h
index 7f4f4a5..f0e317d 100644
--- a/src/output_control.h
+++ b/src/output_control.h
@@ -70,8 +70,19 @@ void audio_output_pause(struct audio_output *ao);
 void
 audio_output_drain_async(struct audio_output *ao);
 
+/**
+ * Clear the "allow_play" flag and send the "CANCEL" command
+ * asynchronously.  To finish the operation, the caller has to call
+ * audio_output_allow_play().
+ */
 void audio_output_cancel(struct audio_output *ao);
 
+/**
+ * Set the "allow_play" and signal the thread.
+ */
+void
+audio_output_allow_play(struct audio_output *ao);
+
 void audio_output_close(struct audio_output *ao);
 
 /**
diff --git a/src/output_init.c b/src/output_init.c
index f4700df..96f87f5 100644
--- a/src/output_init.c
+++ b/src/output_init.c
@@ -189,6 +189,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
 	ao->really_enabled = false;
 	ao->open = false;
 	ao->pause = false;
+	ao->allow_play = true;
 	ao->fail_timer = NULL;
 
 	pcm_buffer_init(&ao->cross_fade_buffer);
diff --git a/src/output_internal.h b/src/output_internal.h
index 18d4313..7102ea5 100644
--- a/src/output_internal.h
+++ b/src/output_internal.h
@@ -110,6 +110,15 @@ struct audio_output {
 	bool pause;
 
 	/**
+	 * When this flag is set, the output thread will not do any
+	 * playback.  It will wait until the flag is cleared.
+	 *
+	 * This is used to synchronize the "clear" operation on the
+	 * shared music pipe during the CANCEL command.
+	 */
+	bool allow_play;
+
+	/**
 	 * If not NULL, the device has failed, and this timer is used
 	 * to estimate how long it should stay disabled (unless
 	 * explicitly reopened with "play").
diff --git a/src/output_thread.c b/src/output_thread.c
index 4e04467..bf56ca9 100644
--- a/src/output_thread.c
+++ b/src/output_thread.c
@@ -640,15 +640,14 @@ static gpointer audio_output_task(gpointer arg)
 
 		case AO_COMMAND_CANCEL:
 			ao->chunk = NULL;
-			if (ao->open)
+
+			if (ao->open) {
+				g_mutex_unlock(ao->mutex);
 				ao_plugin_cancel(ao->plugin, ao->data);
-			ao_command_finished(ao);
+				g_mutex_lock(ao->mutex);
+			}
 
-			/* the player thread will now clear our music
-			   pipe - wait for a notify, to give it some
-			   time */
-			if (ao->command == AO_COMMAND_NONE)
-				g_cond_wait(ao->cond, ao->mutex);
+			ao_command_finished(ao);
 			continue;
 
 		case AO_COMMAND_KILL:
@@ -658,7 +657,7 @@ static gpointer audio_output_task(gpointer arg)
 			return NULL;
 		}
 
-		if (ao->open && ao_play(ao))
+		if (ao->open && ao->allow_play && ao_play(ao))
 			/* don't wait for an event if there are more
 			   chunks in the pipe */
 			continue;
diff --git a/src/pipe.c b/src/pipe.c
index 7e4b0d0..2f5f70e 100644
--- a/src/pipe.c
+++ b/src/pipe.c
@@ -187,5 +187,8 @@ music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk)
 unsigned
 music_pipe_size(const struct music_pipe *mp)
 {
-	return mp->size;
+	g_mutex_lock(mp->mutex);
+	unsigned size = mp->size;
+	g_mutex_unlock(mp->mutex);
+	return size;
 }
diff --git a/src/pipe.h b/src/pipe.h
index f9540a3..efa7a84 100644
--- a/src/pipe.h
+++ b/src/pipe.h
@@ -20,6 +20,7 @@
 #ifndef MPD_PIPE_H
 #define MPD_PIPE_H
 
+#include <glib.h>
 #include <stdbool.h>
 
 #ifndef NDEBUG
@@ -38,6 +39,7 @@ struct music_pipe;
 /**
  * Creates a new #music_pipe object.  It is empty.
  */
+G_GNUC_MALLOC
 struct music_pipe *
 music_pipe_new(void);
 
@@ -70,6 +72,7 @@ music_pipe_contains(const struct music_pipe *mp,
  * Returns the first #music_chunk from the pipe.  Returns NULL if the
  * pipe is empty.
  */
+G_GNUC_PURE
 const struct music_chunk *
 music_pipe_peek(const struct music_pipe *mp);
 
@@ -96,9 +99,11 @@ music_pipe_push(struct music_pipe *mp, struct music_chunk *chunk);
 /**
  * Returns the number of chunks currently in this pipe.
  */
+G_GNUC_PURE
 unsigned
 music_pipe_size(const struct music_pipe *mp);
 
+G_GNUC_PURE
 static inline bool
 music_pipe_empty(const struct music_pipe *mp)
 {
diff --git a/src/player_thread.c b/src/player_thread.c
index cce51c1..a89e599 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -618,7 +618,9 @@ play_chunk(struct song *song, struct music_chunk *chunk,
 		return true;
 	}
 
+	player_lock();
 	pc.bit_rate = chunk->bit_rate;
+	player_unlock();
 
 	/* send the chunk to the audio outputs */
 
diff --git a/src/playlist_control.c b/src/playlist_control.c
index ce9bc84..76066d2 100644
--- a/src/playlist_control.c
+++ b/src/playlist_control.c
@@ -222,10 +222,12 @@ playlist_seek_song(struct playlist *playlist, unsigned song, float seek_time)
 	playlist->error_count = 0;
 
 	if (!playlist->playing || (unsigned)playlist->current != i) {
-		/* seeking is not within the current song - first
-		   start playing the new song */
+		/* seeking is not within the current song - prepare
+		   song change */
+
+		playlist->playing = true;
+		playlist->current = i;
 
-		playlist_play_order(playlist, i);
 		queued = NULL;
 	}
 
diff --git a/src/sticker.c b/src/sticker.c
index c59cdd0..f6cd043 100644
--- a/src/sticker.c
+++ b/src/sticker.c
@@ -579,8 +579,10 @@ sticker_load(const char *type, const char *uri)
 	bool success;
 
 	success = sticker_list_values(sticker->table, type, uri);
-	if (!success)
+	if (!success) {
+		sticker_free(sticker);
 		return NULL;
+	}
 
 	if (g_hash_table_size(sticker->table) == 0) {
 		/* don't return empty sticker objects */
diff --git a/src/update_walk.c b/src/update_walk.c
index 845f152..bf3c8f5 100644
--- a/src/update_walk.c
+++ b/src/update_walk.c
@@ -714,8 +714,14 @@ skip_symlink(const struct directory *directory, const char *utf8_name)
 		return false;
 	}
 
-	if (buffer[0] == '/')
-		return !follow_outside_symlinks;
+	if (g_path_is_absolute(buffer)) {
+		/* if the symlink points to an absolute path, see if
+		   that path is inside the music directory */
+		const char *relative = map_to_relative_path(buffer);
+		return relative > buffer
+			? !follow_inside_symlinks
+			: !follow_outside_symlinks;
+	}
 
 	p = buffer;
 	while (*p == '.') {
diff --git a/test/read_conf.c b/test/read_conf.c
index 4f43e6a..f1b38ca 100644
--- a/test/read_conf.c
+++ b/test/read_conf.c
@@ -37,30 +37,28 @@ my_log_func(G_GNUC_UNUSED const gchar *log_domain,
 
 int main(int argc, char **argv)
 {
-	const char *path, *name, *value;
-	GError *error = NULL;
-	bool success;
-	int ret;
-
 	if (argc != 3) {
 		g_printerr("Usage: read_conf FILE SETTING\n");
 		return 1;
 	}
 
-	path = argv[1];
-	name = argv[2];
+	const char *path = argv[1];
+	const char *name = argv[2];
 
 	g_log_set_default_handler(my_log_func, NULL);
 
 	config_global_init();
-	success = config_read_file(path, &error);
+
+	GError *error = NULL;
+	bool success = config_read_file(path, &error);
 	if (!success) {
 		g_printerr("%s:", error->message);
 		g_error_free(error);
 		return 1;
 	}
 
-	value = config_get_string(name, NULL);
+	const char *value = config_get_string(name, NULL);
+	int ret;
 	if (value != NULL) {
 		g_print("%s\n", value);
 		ret = 0;
@@ -70,5 +68,5 @@ int main(int argc, char **argv)
 	}
 
 	config_global_finish();
-	return 0;
+	return ret;
 }
diff --git a/test/run_filter.c b/test/run_filter.c
index ee2445e..3758eb5 100644
--- a/test/run_filter.c
+++ b/test/run_filter.c
@@ -106,7 +106,6 @@ int main(int argc, char **argv)
 	struct filter *filter;
 	const struct audio_format *out_audio_format;
 	char buffer[4096];
-	size_t frame_size;
 
 	if (argc < 3 || argc > 4) {
 		g_printerr("Usage: run_filter CONFIG NAME [FORMAT] <IN\n");
@@ -162,8 +161,6 @@ int main(int argc, char **argv)
 	g_printerr("audio_format=%s\n",
 		   audio_format_to_string(out_audio_format, &af_string));
 
-	frame_size = audio_format_frame_size(&audio_format);
-
 	/* play */
 
 	while (true) {

-- 
Git repository for pkg-mpd



More information about the Pkg-mpd-commits mailing list