Bug#767846: unblock: mpd/0.19.3-1
in the meantime, another bugfix release, mpd 0.19.3 was released;
changelog below, debdiff attached. This upload would additionally fix
#768094 (important: "crashes with std::logic_error on database update")
and #769436 (normal: "Fails to play some audio streams")
ver 0.19.3 (2014/11/11)
* protocol
- fix "(null)" result string to "list" when AlbumArtist is disabled
* database
- upnp: fix breakage due to malformed URIs
* input
- curl: another fix for redirected streams
* decoder
- audiofile: fix crash while playing streams
- audiofile: fix bit rate calculation
- ffmpeg: support opus
- opus: fix bogus duration on streams
- opus: support chained streams
- opus: improved error logging
* fix distorted audio with soxr resampler
* fix build failure on Mac OS X with non-Apple compilers
(auto-generated files removed)
diff -Nru mpd-0.19.1/aclocal.m4 mpd-0.19.3/aclocal.m4
--- mpd-0.19.1/aclocal.m4 2014-10-11 20:26:11.000000000 +0200
+++ mpd-0.19.3/aclocal.m4 2014-11-05 18:24:19.000000000 +0100
@@ -1160,6 +1160,7 @@
m4_include([m4/faad.m4])
m4_include([m4/libwrap.m4])
m4_include([m4/mpd_auto.m4])
+m4_include([m4/mpd_depends.m4])
m4_include([m4/mpd_func.m4])
m4_include([m4/pkg.m4])
m4_include([m4/pretty_print.m4])
diff -Nru mpd-0.19.1/config.h.in mpd-0.19.3/config.h.in
--- mpd-0.19.1/config.h.in 2014-10-11 20:26:20.000000000 +0200
+++ mpd-0.19.3/config.h.in 2014-11-05 18:24:30.000000000 +0100
@@ -138,9 +138,6 @@
/* Define to use FAAD2 for AAC decoding */
#undef HAVE_FAAD
-/* Define if faad.h uses the broken "unsigned long" pointers */
-#undef HAVE_FAAD_LONG
-
/* Define for FFMPEG support */
#undef HAVE_FFMPEG
diff -Nru mpd-0.19.1/configure.ac mpd-0.19.3/configure.ac
--- mpd-0.19.1/configure.ac 2014-10-11 20:25:57.000000000 +0200
+++ mpd-0.19.3/configure.ac 2014-11-05 18:24:15.000000000 +0100
@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
-AC_INIT(mpd, 0.19.1, musicpd-dev-team@lists.sourceforge.net)
+AC_INIT(mpd, 0.19.3, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=19
-VERSION_REVISION=0
+VERSION_REVISION=3
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -293,7 +293,9 @@
AC_ARG_ENABLE(libmpdclient,
AS_HELP_STRING([--enable-libmpdclient],
[enable support for the MPD client]),,
- enable_libmpdclient=$database_auto)
+ enable_libmpdclient=auto)
+MPD_DEPENDS([enable_libmpdclient], [enable_database],
+ [Cannot use --enable-libmpdclient with --disable-database])
AC_ARG_ENABLE(expat,
AS_HELP_STRING([--enable-expat],
@@ -303,7 +305,9 @@
AC_ARG_ENABLE(upnp,
AS_HELP_STRING([--enable-upnp],
[enable UPnP client support (default: auto)]),,
- enable_upnp=$database_auto)
+ enable_upnp=auto)
+MPD_DEPENDS([enable_upnp], [enable_database],
+ [Cannot use --enable-upnp with --disable-database])
AC_ARG_ENABLE(adplug,
AS_HELP_STRING([--enable-adplug],
@@ -323,6 +327,8 @@
AS_HELP_STRING([--enable-ao],
[enable support for libao]),,
enable_ao=auto)
+MPD_DEPENDS([enable_ao], [enable_glib],
+ [Cannot use --enable-ao with --disable-glib])
AC_ARG_ENABLE(audiofile,
AS_HELP_STRING([--enable-audiofile],
@@ -343,6 +349,8 @@
AS_HELP_STRING([--enable-cdio-paranoia],
[enable support for audio CD support]),,
enable_cdio_paranoia=auto)
+MPD_DEPENDS([enable_cdio_paranoia], [enable_glib],
+ [Cannot use --enable-cdio-paranoia with --disable-glib])
AC_ARG_ENABLE(curl,
AS_HELP_STRING([--enable-curl],
@@ -398,11 +406,15 @@
AS_HELP_STRING([--enable-gme],
[enable Blargg's game music emulator plugin]),,
enable_gme=auto)
+MPD_DEPENDS([enable_gme], [enable_glib],
+ [Cannot use --enable-gme with --disable-glib])
AC_ARG_ENABLE(httpd-output,
AS_HELP_STRING([--enable-httpd-output],
[enables the HTTP server output]),,
[enable_httpd_output=auto])
+MPD_DEPENDS([enable_httpd_output], [enable_glib],
+ [Cannot use --enable-httpd-output with --disable-glib])
AC_ARG_ENABLE(id3,
AS_HELP_STRING([--enable-id3],
@@ -428,6 +440,8 @@
AS_HELP_STRING([--enable-jack],
[enable jack support]),,
enable_jack=auto)
+MPD_DEPENDS([enable_jack], [enable_glib],
+ [Cannot use --enable-jack with --disable-glib])
AC_SYS_LARGEFILE
@@ -440,6 +454,8 @@
AS_HELP_STRING([--enable-soundcloud],
[enable support for soundcloud.com]),,
[enable_soundcloud=auto])
+MPD_DEPENDS([enable_soundcloud], [enable_glib],
+ [Cannot use --enable-soundcloud with --disable-glib])
AC_ARG_ENABLE(lame-encoder,
AS_HELP_STRING([--enable-lame-encoder],
@@ -534,6 +550,8 @@
AS_HELP_STRING([--enable-sidplay],
[enable C64 SID support via libsidplay2]),,
enable_sidplay=auto)
+MPD_DEPENDS([enable_sidplay], [enable_glib],
+ [Cannot use --enable-sidplay with --disable-glib])
AC_ARG_ENABLE(shine-encoder,
AS_HELP_STRING([--enable-shine-encoder],
@@ -559,6 +577,8 @@
AS_HELP_STRING([--enable-sqlite],
[enable support for the SQLite database]),,
[enable_sqlite=$database_auto])
+MPD_DEPENDS([enable_sqlite], [enable_glib],
+ [Cannot use --enable-sqlite with --disable-glib])
AC_ARG_ENABLE(systemd-daemon,
AS_HELP_STRING([--enable-systemd-daemon],
@@ -599,6 +619,8 @@
AS_HELP_STRING([--enable-vorbis-encoder],
[enable the Ogg Vorbis encoder]),,
[enable_vorbis_encoder=auto])
+MPD_DEPENDS([enable_vorbis_encoder], [enable_glib],
+ [Cannot use --enable-vorbis-encoder with --disable-glib])
AC_ARG_ENABLE(wave-encoder,
AS_HELP_STRING([--enable-wave-encoder],
@@ -609,6 +631,8 @@
AS_HELP_STRING([--enable-wavpack],
[enable WavPack support]),,
enable_wavpack=auto)
+MPD_DEPENDS([enable_wavpack], [enable_glib],
+ [Cannot use --enable-wavpack with --disable-glib])
AC_ARG_ENABLE(werror,
AS_HELP_STRING([--enable-werror],
@@ -1709,8 +1733,11 @@
dnl ---------------------------------------------------------------------------
if test x$enable_documentation = xyes; then
AC_PATH_PROG(XMLTO, xmlto)
+ if test x$XMLTO = x; then
+ AC_MSG_ERROR([xmlto not found])
+ fi
+
AC_SUBST(XMLTO)
- AM_CONDITIONAL(HAVE_XMLTO, test x$XMLTO != x)
AC_PATH_PROG(DOXYGEN, doxygen)
if test x$DOXYGEN = x; then
@@ -1718,8 +1745,6 @@
fi
AC_SUBST(DOXYGEN)
-else
- AM_CONDITIONAL(HAVE_XMLTO, false)
fi
AM_CONDITIONAL(ENABLE_DOCUMENTATION, test x$enable_documentation = xyes)
@@ -1826,9 +1851,14 @@
results(tcp, "TCP")
results(un,[UNIX Domain Sockets])
+printf '\nStorage support:\n\t'
+results(nfs, [NFS])
+results(smbclient, [SMB])
+
printf '\nFile format support:\n\t'
results(aac, [AAC])
results(adplug, [AdPlug])
+results(dsd, [DSD])
results(sidplay, [C64 SID])
results(ffmpeg, [FFMPEG])
results(flac, [FLAC])
diff -Nru mpd-0.19.1/debian/changelog mpd-0.19.3/debian/changelog
--- mpd-0.19.1/debian/changelog 2014-10-20 00:38:46.000000000 +0200
+++ mpd-0.19.3/debian/changelog 2014-11-13 21:49:32.000000000 +0100
@@ -1,3 +1,11 @@
+mpd (0.19.3-1) unstable; urgency=medium
+
+ * Import Upstream version 0.19.3 (closes: #767684, #769436)
+ * Disable libmp4v2 due to incompatible license (closes: #767504)
+ * Add charset_conversion_crash.patch (closes: #768094)
+
+ -- Florian Schlichting <fsfs@debian.org> Thu, 13 Nov 2014 21:34:28 +0100
+
mpd (0.19.1-1) unstable; urgency=medium
* Import Upstream version 0.19.1
diff -Nru mpd-0.19.1/debian/patches/charset_conversion_crash.patch mpd-0.19.3/debian/patches/charset_conversion_crash.patch
--- mpd-0.19.1/debian/patches/charset_conversion_crash.patch 1970-01-01 01:00:00.000000000 +0100
+++ mpd-0.19.3/debian/patches/charset_conversion_crash.patch 2014-11-13 21:49:32.000000000 +0100
@@ -0,0 +1,19 @@
+Description: fix crash on failed filename charset conversion
+ Construct a Null AllocatedPath if the filename conversion into UTF8 failed
+Origin: http://git.musicpd.org/cgit/master/mpd.git/commit/?id=7e7b403043b55c2e1bb9227fce725ad87626ae97
+
+--- a/src/fs/AllocatedPath.cxx
++++ b/src/fs/AllocatedPath.cxx
+@@ -46,7 +46,11 @@
+ AllocatedPath::FromUTF8(const char *path_utf8)
+ {
+ #ifdef HAVE_GLIB
+- return AllocatedPath(Donate(), ::PathFromUTF8(path_utf8));
++ char *path = ::PathFromUTF8(path_utf8);
++ if (path == nullptr)
++ return AllocatedPath::Null();
++
++ return AllocatedPath(Donate(), path);
+ #else
+ return FromFS(path_utf8);
+ #endif
diff -Nru mpd-0.19.1/debian/patches/series mpd-0.19.3/debian/patches/series
--- mpd-0.19.1/debian/patches/series 2014-10-19 20:59:54.000000000 +0200
+++ mpd-0.19.3/debian/patches/series 2014-11-13 21:49:32.000000000 +0100
@@ -1,2 +1,3 @@
systemd_honor_MPDCONF.patch
+charset_conversion_crash.patch
typo.patch
diff -Nru mpd-0.19.1/doc/doxygen.conf mpd-0.19.3/doc/doxygen.conf
--- mpd-0.19.1/doc/doxygen.conf 2014-10-11 20:26:19.000000000 +0200
+++ mpd-0.19.3/doc/doxygen.conf 2014-11-05 18:24:29.000000000 +0100
@@ -31,7 +31,7 @@
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.19.1
+PROJECT_NUMBER = 0.19.3
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -534,7 +534,7 @@
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = /home/max/git/mpd/src/
+INPUT = /home/max/git/stable-mpd/src/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff -Nru mpd-0.19.1/m4/faad.m4 mpd-0.19.3/m4/faad.m4
--- mpd-0.19.1/m4/faad.m4 2013-07-26 12:08:46.000000000 +0200
+++ mpd-0.19.3/m4/faad.m4 2014-10-27 09:26:34.000000000 +0100
@@ -62,36 +62,7 @@
CPPFLAGS=$oldcppflags
fi
-if test x$enable_aac = xyes; then
- oldcflags=$CFLAGS
- oldlibs=$LIBS
- oldcppflags=$CPPFLAGS
- CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
- LIBS="$LIBS $FAAD_LIBS"
- CPPFLAGS=$CFLAGS
-
- AC_MSG_CHECKING(for broken libfaad headers)
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([
-#include <faad.h>
-#include <stddef.h>
-#include <stdint.h>
-
-int main() {
- unsigned char channels;
- uint32_t sample_rate;
-
- NeAACDecInit2(NULL, NULL, 0, &sample_rate, &channels);
- return 0;
-}
- ])],
- [AC_MSG_RESULT(correct)],
- [AC_MSG_RESULT(broken);
- AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])
-
- CFLAGS=$oldcflags
- LIBS=$oldlibs
- CPPFLAGS=$oldcppflags
-else
+if test x$enable_aac = xno; then
FAAD_LIBS=""
FAAD_CFLAGS=""
fi
diff -Nru mpd-0.19.1/m4/mpd_depends.m4 mpd-0.19.3/m4/mpd_depends.m4
--- mpd-0.19.1/m4/mpd_depends.m4 1970-01-01 01:00:00.000000000 +0100
+++ mpd-0.19.3/m4/mpd_depends.m4 2014-10-27 09:26:34.000000000 +0100
@@ -0,0 +1,9 @@
+AC_DEFUN([MPD_DEPENDS], [
+ if test x$$2 = xno; then
+ if test x$$1 = xauto; then
+ $1=no
+ elif test x$$1 = xyes; then
+ AC_MSG_ERROR([$3])
+ fi
+ fi
+])
diff -Nru mpd-0.19.1/Makefile.am mpd-0.19.3/Makefile.am
--- mpd-0.19.1/Makefile.am 2014-10-12 08:41:09.000000000 +0200
+++ mpd-0.19.3/Makefile.am 2014-11-07 18:42:57.000000000 +0100
@@ -130,7 +130,6 @@
src/IOThread.cxx src/IOThread.hxx \
src/Instance.cxx src/Instance.hxx \
src/win32/Win32Main.cxx \
- src/osx/OSXMain.cxx \
src/GlobalEvents.cxx src/GlobalEvents.hxx \
src/MixRampInfo.hxx \
src/MusicBuffer.cxx src/MusicBuffer.hxx \
@@ -1113,6 +1112,7 @@
#
libinput_a_SOURCES = \
+ src/input/Domain.cxx src/input/Domain.hxx \
src/input/Init.cxx src/input/Init.hxx \
src/input/Registry.cxx src/input/Registry.hxx \
src/input/Open.cxx \
@@ -2141,19 +2141,11 @@
developerdir = $(docdir)/developer
developer_DATA = $(wildcard doc/developer/*.html)
-if HAVE_XMLTO
-
DOCBOOK_HTML = $(patsubst %.xml,%/index.html,$(DOCBOOK_FILES))
$(DOCBOOK_HTML): %/index.html: %.xml
$(XMLTO) -o $(@D) --stringparam chunker.output.encoding=utf-8 html --stringparam use.id.as.filename=1 $<
-else
-
-DOCBOOK_HTML =
-
-endif
-
doc/api/html/index.html: doc/doxygen.conf
@$(MKDIR_P) $(@D)
$(DOXYGEN) $<
diff -Nru mpd-0.19.1/NEWS mpd-0.19.3/NEWS
--- mpd-0.19.1/NEWS 2014-10-19 01:03:36.000000000 +0200
+++ mpd-0.19.3/NEWS 2014-11-11 11:21:38.000000000 +0100
@@ -1,3 +1,38 @@
+ver 0.19.3 (2014/11/11)
+* protocol
+ - fix "(null)" result string to "list" when AlbumArtist is disabled
+* database
+ - upnp: fix breakage due to malformed URIs
+* input
+ - curl: another fix for redirected streams
+* decoder
+ - audiofile: fix crash while playing streams
+ - audiofile: fix bit rate calculation
+ - ffmpeg: support opus
+ - opus: fix bogus duration on streams
+ - opus: support chained streams
+ - opus: improved error logging
+* fix distorted audio with soxr resampler
+* fix build failure on Mac OS X with non-Apple compilers
+
+ver 0.19.2 (2014/11/02)
+* input
+ - curl: fix redirected streams
+* playlist
+ - don't allow empty playlist name
+ - m3u: don't ignore unterminated last line
+ - m3u: recognize the file suffix ".m3u8"
+* decoder
+ - ignore URI query string for plugin detection
+ - faad: remove workaround for ancient libfaad2 ABI bug
+ - ffmpeg: recognize MIME type audio/aacp
+ - mad: fix negative replay gain values
+* output
+ - fix memory leak after filter initialization error
+ - fall back to PCM if given DSD sample rate is not supported
+* fix assertion failure on unsupported PCM conversion
+* auto-disable plugins that require GLib when --disable-glib is used
+
ver 0.19.1 (2014/10/19)
* input
- mms: fix deadlock bug
@@ -85,6 +120,15 @@
* install systemd unit for socket activation
* Android port
+ver 0.18.17 (2014/11/02)
+* playlist
+ - don't allow empty playlist name
+ - m3u: recognize the file suffix ".m3u8"
+* decoder
+ - ignore URI query string for plugin detection
+ - faad: remove workaround for ancient libfaad2 ABI bug
+ - ffmpeg: recognize MIME type audio/aacp
+
ver 0.18.16 (2014/09/26)
* fix DSD breakage due to typo in configure.ac
diff -Nru mpd-0.19.1/src/db/Count.cxx mpd-0.19.3/src/db/Count.cxx
--- mpd-0.19.1/src/db/Count.cxx 2014-08-29 23:30:42.000000000 +0200
+++ mpd-0.19.3/src/db/Count.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -23,7 +23,7 @@
#include "Interface.hxx"
#include "client/Client.hxx"
#include "LightSong.hxx"
-#include "tag/Set.hxx"
+#include "tag/Tag.hxx"
#include <functional>
#include <map>
diff -Nru mpd-0.19.1/src/db/plugins/upnp/Directory.cxx mpd-0.19.3/src/db/plugins/upnp/Directory.cxx
--- mpd-0.19.1/src/db/plugins/upnp/Directory.cxx 2014-08-29 19:30:43.000000000 +0200
+++ mpd-0.19.3/src/db/plugins/upnp/Directory.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -129,6 +129,7 @@
state(NONE),
tag_type(TAG_NUM_OF_ITEM_TYPES)
{
+ m_tobj.clear();
}
protected:
diff -Nru mpd-0.19.1/src/decoder/DecoderThread.cxx mpd-0.19.3/src/decoder/DecoderThread.cxx
--- mpd-0.19.1/src/decoder/DecoderThread.cxx 2014-10-02 21:55:44.000000000 +0200
+++ mpd-0.19.3/src/decoder/DecoderThread.cxx 2014-11-01 13:15:50.000000000 +0100
@@ -237,7 +237,8 @@
decoder_run_stream_locked(Decoder &decoder, InputStream &is,
const char *uri, bool &tried_r)
{
- const char *const suffix = uri_get_suffix(uri);
+ UriSuffixBuffer suffix_buffer;
+ const char *const suffix = uri_get_suffix(uri, suffix_buffer);
using namespace std::placeholders;
const auto f = std::bind(decoder_run_stream_plugin,
diff -Nru mpd-0.19.1/src/decoder/plugins/AudiofileDecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/AudiofileDecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/AudiofileDecoderPlugin.cxx 2014-09-19 23:57:02.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/AudiofileDecoderPlugin.cxx 2014-11-10 08:59:42.000000000 +0100
@@ -209,7 +209,7 @@
const auto total_time = audiofile_get_duration(fh);
const uint16_t kbit_rate = (uint16_t)
- (is.GetSize() * uint64_t(8000) / total_time.ToMS());
+ (is.GetSize() * uint64_t(8) / total_time.ToMS());
const unsigned frame_size = (unsigned)
afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true);
diff -Nru mpd-0.19.1/src/decoder/plugins/FaadDecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/FaadDecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/FaadDecoderPlugin.cxx 2014-09-24 18:56:53.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/FaadDecoderPlugin.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -255,20 +255,12 @@
}
uint8_t channels;
- uint32_t sample_rate;
-#ifdef HAVE_FAAD_LONG
- /* neaacdec.h declares all arguments as "unsigned long", but
- internally expects uint32_t pointers. To avoid gcc
- warnings, use this workaround. */
- unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
-#else
- uint32_t *sample_rate_p = &sample_rate;
-#endif
+ unsigned long sample_rate;
long nbytes = NeAACDecInit(decoder,
/* deconst hack, libfaad requires this */
const_cast<unsigned char *>(data.data),
data.size,
- sample_rate_p, &channels);
+ &sample_rate, &channels);
if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream");
return false;
diff -Nru mpd-0.19.1/src/decoder/plugins/FfmpegDecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/FfmpegDecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/FfmpegDecoderPlugin.cxx 2014-09-11 19:24:55.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/FfmpegDecoderPlugin.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -657,7 +657,7 @@
"mj2", "mjpeg", "mjpg", "mka", "mkv", "mlp", "mm", "mmf", "mov", "mp+",
"mp1", "mp2", "mp3", "mp4", "mpc", "mpeg", "mpg", "mpga", "mpp", "mpu",
"mve", "mvi", "mxf", "nc", "nsv", "nut", "nuv", "oga", "ogm", "ogv",
- "ogx", "oma", "ogg", "omg", "psp", "pva", "qcp", "qt", "r3d", "ra",
+ "ogx", "oma", "ogg", "omg", "opus", "psp", "pva", "qcp", "qt", "r3d", "ra",
"ram", "rl2", "rm", "rmvb", "roq", "rpl", "rvc", "shn", "smk", "snd",
"sol", "son", "spx", "str", "swf", "tgi", "tgq", "tgv", "thp", "ts",
"tsp", "tta", "xa", "xvid", "uv", "uv2", "vb", "vid", "vob", "voc",
@@ -680,6 +680,7 @@
"audio/8svx",
"audio/16sv",
"audio/aac",
+ "audio/aacp",
"audio/ac3",
"audio/aiff"
"audio/amr",
@@ -690,6 +691,7 @@
"audio/mpeg",
"audio/musepack",
"audio/ogg",
+ "audio/opus",
"audio/qcelp",
"audio/vorbis",
"audio/vorbis+ogg",
diff -Nru mpd-0.19.1/src/decoder/plugins/MadDecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/MadDecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/MadDecoderPlugin.cxx 2014-09-24 22:42:53.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/MadDecoderPlugin.cxx 2014-10-31 08:47:38.000000000 +0100
@@ -657,7 +657,7 @@
unsigned name = mad_bit_read(ptr, 3); /* gain name */
unsigned orig = mad_bit_read(ptr, 3); /* gain originator */
unsigned sign = mad_bit_read(ptr, 1); /* sign bit */
- unsigned gain = mad_bit_read(ptr, 9); /* gain*10 */
+ int gain = mad_bit_read(ptr, 9); /* gain*10 */
if (gain && name == 1 && orig != 0) {
lame->track_gain = ((sign ? -gain : gain) / 10.0) + adj;
FormatDebug(mad_domain, "LAME track gain found: %f",
diff -Nru mpd-0.19.1/src/decoder/plugins/Mp4v2DecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/Mp4v2DecoderPlugin.cxx 2014-09-24 23:28:54.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/Mp4v2DecoderPlugin.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -39,15 +39,7 @@
mp4_get_aac_track(MP4FileHandle handle, NeAACDecHandle decoder,
AudioFormat &audio_format, Error &error)
{
- uint32_t sample_rate;
-#ifdef HAVE_FAAD_LONG
- /* neaacdec.h declares all arguments as "unsigned long", but
- internally expects uint32_t pointers. To avoid gcc
- warnings, use this workaround. */
- unsigned long *sample_rate_r = (unsigned long*)&sample_rate;
-#else
- uint32_t *sample_rate_r = sample_rate;
-#endif
+ unsigned long sample_rate;
const MP4TrackId tracks = MP4GetNumberOfTracks(handle);
@@ -80,7 +72,7 @@
uint8_t channels;
int32_t nbytes = NeAACDecInit(decoder, buff, buff_size,
- sample_rate_r, &channels);
+ &sample_rate, &channels);
free(buff);
diff -Nru mpd-0.19.1/src/decoder/plugins/OpusDecoderPlugin.cxx mpd-0.19.3/src/decoder/plugins/OpusDecoderPlugin.cxx
--- mpd-0.19.1/src/decoder/plugins/OpusDecoderPlugin.cxx 2014-08-29 23:30:42.000000000 +0200
+++ mpd-0.19.3/src/decoder/plugins/OpusDecoderPlugin.cxx 2014-11-11 11:20:18.000000000 +0100
@@ -40,6 +40,12 @@
static constexpr opus_int32 opus_sample_rate = 48000;
+/**
+ * Allocate an output buffer for 16 bit PCM samples big enough to hold
+ * a quarter second, larger than 120ms required by libopus.
+ */
+static constexpr unsigned opus_output_buffer_frames = opus_sample_rate / 4;
+
gcc_pure
static bool
IsOpusHead(const ogg_packet &packet)
@@ -70,10 +76,16 @@
OpusDecoder *opus_decoder;
opus_int16 *output_buffer;
- unsigned output_size;
+
+ /**
+ * If non-zero, then a previous Opus stream has been found
+ * already with this number of channels. If opus_decoder is
+ * nullptr, then its end-of-stream packet has been found
+ * already.
+ */
+ unsigned previous_channels;
bool os_initialized;
- bool found_opus;
int opus_serialno;
@@ -86,8 +98,9 @@
InputStream &_input_stream)
:decoder(_decoder), input_stream(_input_stream),
opus_decoder(nullptr),
- output_buffer(nullptr), output_size(0),
- os_initialized(false), found_opus(false) {}
+ output_buffer(nullptr),
+ previous_channels(0),
+ os_initialized(false) {}
~MPDOpusDecoder();
bool ReadFirstPage(OggSyncState &oy);
@@ -96,6 +109,7 @@
DecoderCommand HandlePackets();
DecoderCommand HandlePacket(const ogg_packet &packet);
DecoderCommand HandleBOS(const ogg_packet &packet);
+ DecoderCommand HandleEOS();
DecoderCommand HandleTags(const ogg_packet &packet);
DecoderCommand HandleAudio(const ogg_packet &packet);
@@ -159,12 +173,14 @@
MPDOpusDecoder::HandlePacket(const ogg_packet &packet)
{
if (packet.e_o_s)
- return DecoderCommand::STOP;
+ return HandleEOS();
if (packet.b_o_s)
return HandleBOS(packet);
- else if (!found_opus)
+ else if (opus_decoder == nullptr) {
+ LogDebug(opus_domain, "BOS packet expected");
return DecoderCommand::STOP;
+ }
if (IsOpusTags(packet))
return HandleTags(packet);
@@ -184,7 +200,7 @@
/* we do this for local files only, because seeking
around remote files is expensive and not worth the
troubl */
- return -1;
+ return false;
const auto old_offset = is.GetOffset();
@@ -225,19 +241,29 @@
{
assert(packet.b_o_s);
- if (found_opus || !IsOpusHead(packet))
+ if (opus_decoder != nullptr || !IsOpusHead(packet)) {
+ LogDebug(opus_domain, "BOS packet must be OpusHead");
return DecoderCommand::STOP;
+ }
unsigned channels;
if (!ScanOpusHeader(packet.packet, packet.bytes, channels) ||
- !audio_valid_channel_count(channels))
+ !audio_valid_channel_count(channels)) {
+ LogDebug(opus_domain, "Malformed BOS packet");
return DecoderCommand::STOP;
+ }
assert(opus_decoder == nullptr);
- assert(output_buffer == nullptr);
+ assert((previous_channels == 0) == (output_buffer == nullptr));
+
+ if (previous_channels != 0 && channels != previous_channels) {
+ FormatWarning(opus_domain,
+ "Next stream has different channels (%u -> %u)",
+ previous_channels, channels);
+ return DecoderCommand::STOP;
+ }
opus_serialno = os.serialno;
- found_opus = true;
/* TODO: parse attributes from the OpusHead (sample rate,
channels, ...) */
@@ -251,6 +277,13 @@
return DecoderCommand::STOP;
}
+ if (previous_channels != 0) {
+ /* decoder was already initialized by the previous
+ stream; skip the rest of this method */
+ LogDebug(opus_domain, "Found another stream");
+ return decoder_get_command(decoder);
+ }
+
eos_granulepos = LoadEOSGranulePos(input_stream, &decoder,
opus_serialno);
const auto duration = eos_granulepos >= 0
@@ -258,22 +291,37 @@
opus_sample_rate)
: SignedSongTime::Negative();
+ previous_channels = channels;
const AudioFormat audio_format(opus_sample_rate,
SampleFormat::S16, channels);
decoder_initialized(decoder, audio_format,
eos_granulepos > 0, duration);
frame_size = audio_format.GetFrameSize();
- /* allocate an output buffer for 16 bit PCM samples big enough
- to hold a quarter second, larger than 120ms required by
- libopus */
- output_size = audio_format.sample_rate / 4;
- output_buffer = new opus_int16[output_size * audio_format.channels];
+ output_buffer = new opus_int16[opus_output_buffer_frames
+ * audio_format.channels];
return decoder_get_command(decoder);
}
inline DecoderCommand
+MPDOpusDecoder::HandleEOS()
+{
+ if (eos_granulepos < 0 && previous_channels != 0) {
+ /* allow chaining of (unseekable) streams */
+ assert(opus_decoder != nullptr);
+ assert(output_buffer != nullptr);
+
+ opus_decoder_destroy(opus_decoder);
+ opus_decoder = nullptr;
+
+ return decoder_get_command(decoder);
+ }
+
+ return DecoderCommand::STOP;
+}
+
+inline DecoderCommand
MPDOpusDecoder::HandleTags(const ogg_packet &packet)
{
ReplayGainInfo rgi;
@@ -304,10 +352,11 @@
int nframes = opus_decode(opus_decoder,
(const unsigned char*)packet.packet,
packet.bytes,
- output_buffer, output_size,
+ output_buffer, opus_output_buffer_frames,
0);
if (nframes < 0) {
- LogError(opus_domain, opus_strerror(nframes));
+ FormatError(opus_domain, "libopus error: %s",
+ opus_strerror(nframes));
return DecoderCommand::STOP;
}
diff -Nru mpd-0.19.1/src/fs/Charset.cxx mpd-0.19.3/src/fs/Charset.cxx
--- mpd-0.19.1/src/fs/Charset.cxx 2014-02-23 22:03:40.000000000 +0100
+++ mpd-0.19.3/src/fs/Charset.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -34,6 +34,8 @@
#include <assert.h>
#include <string.h>
+#ifdef HAVE_GLIB
+
/**
* Maximal number of bytes required to represent path name in UTF-8
* (including nul-terminator).
@@ -44,7 +46,6 @@
*/
static constexpr size_t MPD_PATH_MAX_UTF8 = (MPD_PATH_MAX - 1) * 4 + 1;
-#ifdef HAVE_GLIB
static std::string fs_charset;
gcc_pure
diff -Nru mpd-0.19.1/src/input/AsyncInputStream.cxx mpd-0.19.3/src/input/AsyncInputStream.cxx
--- mpd-0.19.1/src/input/AsyncInputStream.cxx 2014-08-19 21:19:11.000000000 +0200
+++ mpd-0.19.3/src/input/AsyncInputStream.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -19,6 +19,7 @@
#include "config.h"
#include "AsyncInputStream.hxx"
+#include "Domain.hxx"
#include "tag/Tag.hxx"
#include "event/Call.hxx"
#include "thread/Cond.hxx"
@@ -113,8 +114,10 @@
/* no-op */
return true;
- if (!IsSeekable())
+ if (!IsSeekable()) {
+ error.Set(input_domain, "Not seekable");
return false;
+ }
/* check if we can fast-forward the buffer */
diff -Nru mpd-0.19.1/src/input/AsyncInputStream.hxx mpd-0.19.3/src/input/AsyncInputStream.hxx
--- mpd-0.19.1/src/input/AsyncInputStream.hxx 2014-09-02 21:36:20.000000000 +0200
+++ mpd-0.19.3/src/input/AsyncInputStream.hxx 2014-11-02 21:01:47.000000000 +0100
@@ -83,6 +83,10 @@
*/
void SetTag(Tag *_tag);
+ void ClearTag() {
+ SetTag(nullptr);
+ }
+
void Pause();
bool IsPaused() const {
diff -Nru mpd-0.19.1/src/input/Domain.cxx mpd-0.19.3/src/input/Domain.cxx
--- mpd-0.19.1/src/input/Domain.cxx 1970-01-01 01:00:00.000000000 +0100
+++ mpd-0.19.3/src/input/Domain.cxx 2014-11-07 18:42:57.000000000 +0100
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Domain.hxx"
+#include "util/Domain.hxx"
+
+const Domain input_domain("input");
diff -Nru mpd-0.19.1/src/input/Domain.hxx mpd-0.19.3/src/input/Domain.hxx
--- mpd-0.19.1/src/input/Domain.hxx 1970-01-01 01:00:00.000000000 +0100
+++ mpd-0.19.3/src/input/Domain.hxx 2014-11-07 18:42:57.000000000 +0100
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_INPUT_DOMAIN_HXX
+#define MPD_INPUT_DOMAIN_HXX
+
+class Domain;
+
+extern const Domain input_domain;
+
+#endif
diff -Nru mpd-0.19.1/src/input/InputStream.hxx mpd-0.19.3/src/input/InputStream.hxx
--- mpd-0.19.1/src/input/InputStream.hxx 2014-10-11 21:59:12.000000000 +0200
+++ mpd-0.19.3/src/input/InputStream.hxx 2014-11-02 21:01:47.000000000 +0100
@@ -200,6 +200,10 @@
return mime.empty() ? nullptr : mime.c_str();
}
+ void ClearMimeType() {
+ mime.clear();
+ }
+
gcc_nonnull_all
void SetMimeType(const char *_mime) {
assert(!ready);
diff -Nru mpd-0.19.1/src/input/Open.cxx mpd-0.19.3/src/input/Open.cxx
--- mpd-0.19.1/src/input/Open.cxx 2014-10-11 21:59:12.000000000 +0200
+++ mpd-0.19.3/src/input/Open.cxx 2014-11-07 18:42:57.000000000 +0100
@@ -22,14 +22,13 @@
#include "Registry.hxx"
#include "InputPlugin.hxx"
#include "LocalOpen.hxx"
+#include "Domain.hxx"
#include "plugins/RewindInputPlugin.hxx"
#include "fs/Traits.hxx"
#include "fs/Path.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
-static constexpr Domain input_domain("input");
-
InputStream *
InputStream::Open(const char *url,
Mutex &mutex, Cond &cond,
diff -Nru mpd-0.19.1/src/input/plugins/CurlInputPlugin.cxx mpd-0.19.3/src/input/plugins/CurlInputPlugin.cxx
--- mpd-0.19.1/src/input/plugins/CurlInputPlugin.cxx 2014-09-16 18:40:37.000000000 +0200
+++ mpd-0.19.3/src/input/plugins/CurlInputPlugin.cxx 2014-11-10 08:44:08.000000000 +0100
@@ -109,6 +109,13 @@
*/
void FreeEasyIndirect();
+ /**
+ * Called when a new response begins. This is used to discard
+ * headers from previous responses (for example authentication
+ * and redirects).
+ */
+ void ResponseBoundary();
+
void HeaderReceived(const char *name, std::string &&value);
size_t DataReceived(const void *ptr, size_t size);
@@ -598,6 +605,24 @@
}
inline void
+CurlInputStream::ResponseBoundary()
+{
+ /* undo all effects of HeaderReceived() because the previous
+ response was not applicable for this stream */
+
+ if (IsSeekPending())
+ /* don't update metadata while seeking */
+ return;
+
+ seekable = false;
+ size = UNKNOWN_SIZE;
+ ClearMimeType();
+ ClearTag();
+
+ // TODO: reset the IcyInputStream?
+}
+
+inline void
CurlInputStream::HeaderReceived(const char *name, std::string &&value)
{
if (IsSeekPending())
@@ -645,6 +670,11 @@
size *= nmemb;
const char *header = (const char *)ptr;
+ if (size > 5 && memcmp(header, "HTTP/", 5) == 0) {
+ c.ResponseBoundary();
+ return size;
+ }
+
const char *end = header + size;
char name[64];
@@ -720,10 +750,10 @@
input_curl_writefunction);
curl_easy_setopt(easy, CURLOPT_WRITEDATA, this);
curl_easy_setopt(easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
- curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(easy, CURLOPT_NETRC, 1);
- curl_easy_setopt(easy, CURLOPT_MAXREDIRS, 5);
- curl_easy_setopt(easy, CURLOPT_FAILONERROR, true);
+ curl_easy_setopt(easy, CURLOPT_FOLLOWLOCATION, 1l);
+ curl_easy_setopt(easy, CURLOPT_NETRC, 1l);
+ curl_easy_setopt(easy, CURLOPT_MAXREDIRS, 5l);
+ curl_easy_setopt(easy, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, error_buffer);
curl_easy_setopt(easy, CURLOPT_NOPROGRESS, 1l);
curl_easy_setopt(easy, CURLOPT_NOSIGNAL, 1l);
diff -Nru mpd-0.19.1/src/input/TextInputStream.cxx mpd-0.19.3/src/input/TextInputStream.cxx
--- mpd-0.19.1/src/input/TextInputStream.cxx 2014-10-19 00:49:40.000000000 +0200
+++ mpd-0.19.3/src/input/TextInputStream.cxx 2014-10-31 08:47:38.000000000 +0100
@@ -38,8 +38,8 @@
while (true) {
auto dest = buffer.Write();
if (dest.size < 2) {
- /* end of file (or line too long): terminate
- the current line */
+ /* line too long: terminate the current
+ line */
assert(!dest.IsEmpty());
dest[0] = 0;
@@ -66,7 +66,19 @@
if (line != nullptr)
return line;
- if (nbytes == 0)
- return nullptr;
+ if (nbytes == 0) {
+ /* end of file: see if there's an unterminated
+ line */
+
+ dest = buffer.Write();
+ assert(!dest.IsEmpty());
+ dest[0] = 0;
+
+ auto r = buffer.Read();
+ buffer.Clear();
+ return r.IsEmpty()
+ ? nullptr
+ : r.data;
+ }
}
}
diff -Nru mpd-0.19.1/src/lib/upnp/ContentDirectoryService.cxx mpd-0.19.3/src/lib/upnp/ContentDirectoryService.cxx
--- mpd-0.19.1/src/lib/upnp/ContentDirectoryService.cxx 2014-10-10 22:46:59.000000000 +0200
+++ mpd-0.19.3/src/lib/upnp/ContentDirectoryService.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -29,7 +29,7 @@
ContentDirectoryService::ContentDirectoryService(const UPnPDevice &device,
const UPnPService &service)
- :m_actionURL(uri_apply_base(device.URLBase, service.controlURL)),
+ :m_actionURL(uri_apply_base(service.controlURL, device.URLBase)),
m_serviceType(service.serviceType),
m_deviceId(device.UDN),
m_friendlyName(device.friendlyName),
diff -Nru mpd-0.19.1/src/lib/upnp/Discovery.cxx mpd-0.19.3/src/lib/upnp/Discovery.cxx
--- mpd-0.19.1/src/lib/upnp/Discovery.cxx 2014-01-26 15:58:26.000000000 +0100
+++ mpd-0.19.3/src/lib/upnp/Discovery.cxx 2014-11-02 11:04:03.000000000 +0100
@@ -26,6 +26,7 @@
#include <upnp/upnptools.h>
+#include <stdlib.h>
#include <string.h>
// The service type string we are looking for.
diff -Nru mpd-0.19.1/src/Main.cxx mpd-0.19.3/src/Main.cxx
--- mpd-0.19.1/src/Main.cxx 2014-10-10 19:45:56.000000000 +0200
+++ mpd-0.19.3/src/Main.cxx 2014-11-11 06:22:24.000000000 +0100
@@ -114,6 +114,10 @@
#include <ws2tcpip.h>
#endif
+#ifdef __BLOCKS__
+#include <dispatch/dispatch.h>
+#endif
+
#include <limits.h>
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
@@ -401,8 +405,6 @@
{
#ifdef WIN32
return win32_main(argc, argv);
-#elif __APPLE__
- return osx_main(argc, argv);
#else
return mpd_main(argc, argv);
#endif
@@ -410,6 +412,8 @@
#endif
+static int mpd_main_after_fork(struct options);
+
#ifdef ANDROID
static inline
#endif
@@ -513,6 +517,27 @@
daemonize_begin(options.daemon);
#endif
+#ifdef __BLOCKS__
+ /* Runs the OS X native event loop in the main thread, and runs
+ the rest of mpd_main on a new thread. This lets CoreAudio receive
+ route change notifications (e.g. plugging or unplugging headphones).
+ All hardware output on OS X ultimately uses CoreAudio internally.
+ This must be run after forking; if dispatch is called before forking,
+ the child process will have a broken internal dispatch state. */
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ exit(mpd_main_after_fork(options));
+ });
+ dispatch_main();
+ return EXIT_FAILURE; // unreachable, because dispatch_main never returns
+#else
+ return mpd_main_after_fork(options);
+#endif
+}
+
+static int mpd_main_after_fork(struct options options)
+{
+ Error error;
+
GlobalEvents::Initialize(*instance->event_loop);
GlobalEvents::Register(GlobalEvents::IDLE, idle_event_emitted);
#ifdef WIN32
diff -Nru mpd-0.19.1/src/Main.hxx mpd-0.19.3/src/Main.hxx
--- mpd-0.19.1/src/Main.hxx 2014-10-10 19:45:56.000000000 +0200
+++ mpd-0.19.3/src/Main.hxx 2014-10-31 15:03:46.000000000 +0100
@@ -75,15 +75,4 @@
#endif
-#ifdef __APPLE__
-
-/* Runs the OS X native event loop in the main thread, and runs
- * mpd_main on a new thread. This lets CoreAudio receive route
- * change notifications (e.g. plugging or unplugging headphones).
- * All hardware output on OS X ultimately uses CoreAudio internally.
- */
-int osx_main(int argc, char *argv[]);
-
-#endif
-
#endif
diff -Nru mpd-0.19.1/src/osx/OSXMain.cxx mpd-0.19.3/src/osx/OSXMain.cxx
--- mpd-0.19.1/src/osx/OSXMain.cxx 2014-10-10 19:45:56.000000000 +0200
+++ mpd-0.19.3/src/osx/OSXMain.cxx 1970-01-01 01:00:00.000000000 +0100
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
- * http://www.musicpd.org
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include "config.h"
-#include "Main.hxx"
-
-#ifdef __APPLE__
-
-#include <stdlib.h>
-#include <dispatch/dispatch.h>
-
-int osx_main(int argc, char *argv[])
-{
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- exit(mpd_main(argc, argv));
- });
- dispatch_main();
- return EXIT_FAILURE; // unreachable, because dispatch_main never returns
-}
-
-#endif
diff -Nru mpd-0.19.1/src/output/Internal.hxx mpd-0.19.3/src/output/Internal.hxx
--- mpd-0.19.1/src/output/Internal.hxx 2014-08-12 16:00:27.000000000 +0200
+++ mpd-0.19.3/src/output/Internal.hxx 2014-10-27 09:26:34.000000000 +0100
@@ -383,7 +383,12 @@
void Reopen();
AudioFormat OpenFilter(AudioFormat &format, Error &error_r);
+
+ /**
+ * Mutex must not be locked.
+ */
void CloseFilter();
+
void ReopenFilter();
/**
diff -Nru mpd-0.19.1/src/output/OutputThread.cxx mpd-0.19.3/src/output/OutputThread.cxx
--- mpd-0.19.1/src/output/OutputThread.cxx 2014-09-24 21:47:32.000000000 +0200
+++ mpd-0.19.3/src/output/OutputThread.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -22,6 +22,7 @@
#include "OutputAPI.hxx"
#include "Domain.hxx"
#include "pcm/PcmMix.hxx"
+#include "pcm/Domain.hxx"
#include "notify.hxx"
#include "filter/FilterInternal.hxx"
#include "filter/plugins/ConvertFilterPlugin.hxx"
@@ -165,6 +166,10 @@
out_audio_format.ApplyMask(config_audio_format);
mutex.unlock();
+
+ const AudioFormat retry_audio_format = out_audio_format;
+
+ retry_without_dsd:
success = ao_plugin_open(this, out_audio_format, error);
mutex.lock();
@@ -174,7 +179,10 @@
FormatError(error, "Failed to open \"%s\" [%s]",
name, plugin.name);
+ mutex.unlock();
CloseFilter();
+ mutex.lock();
+
fail_timer.Update();
return;
}
@@ -184,7 +192,36 @@
FormatError(error, "Failed to convert for \"%s\" [%s]",
name, plugin.name);
+ mutex.unlock();
+ ao_plugin_close(this);
+
+ if (error.IsDomain(pcm_domain) &&
+ out_audio_format.format == SampleFormat::DSD) {
+ /* if the audio output supports DSD, but not
+ the given sample rate, it asks MPD to
+ resample; resampling DSD however is not
+ implemented; our last resort is to give up
+ DSD and fall back to PCM */
+
+ // TODO: clean up this workaround
+
+ FormatError(output_domain, "Retrying without DSD");
+
+ out_audio_format = retry_audio_format;
+ out_audio_format.format = SampleFormat::FLOAT;
+
+ /* clear the Error to allow reusing it */
+ error.Clear();
+
+ /* sorry for the "goto" - this is a workaround
+ for the stable branch that should be as
+ unintrusive as possible */
+ goto retry_without_dsd;
+ }
+
CloseFilter();
+ mutex.lock();
+
fail_timer.Update();
return;
}
@@ -233,7 +270,10 @@
{
Error error;
+ mutex.unlock();
CloseFilter();
+ mutex.lock();
+
const AudioFormat filter_audio_format =
OpenFilter(in_audio_format, error);
if (!filter_audio_format.IsDefined() ||
diff -Nru mpd-0.19.1/src/output/plugins/RoarOutputPlugin.cxx mpd-0.19.3/src/output/plugins/RoarOutputPlugin.cxx
--- mpd-0.19.1/src/output/plugins/RoarOutputPlugin.cxx 2014-09-28 13:24:40.000000000 +0200
+++ mpd-0.19.3/src/output/plugins/RoarOutputPlugin.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -46,7 +46,7 @@
struct roar_connection con;
struct roar_audio_info info;
mutable Mutex mutex;
- volatile bool alive;
+ bool alive;
public:
RoarOutput()
diff -Nru mpd-0.19.1/src/pcm/ChannelsConverter.cxx mpd-0.19.3/src/pcm/ChannelsConverter.cxx
--- mpd-0.19.1/src/pcm/ChannelsConverter.cxx 2014-01-24 00:22:50.000000000 +0100
+++ mpd-0.19.3/src/pcm/ChannelsConverter.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -43,7 +43,7 @@
default:
error.Format(pcm_domain,
"PCM channel conversion for %s is not implemented",
- sample_format_to_string(format));
+ sample_format_to_string(_format));
return false;
}
diff -Nru mpd-0.19.1/src/pcm/FormatConverter.cxx mpd-0.19.3/src/pcm/FormatConverter.cxx
--- mpd-0.19.1/src/pcm/FormatConverter.cxx 2014-01-24 00:22:50.000000000 +0100
+++ mpd-0.19.3/src/pcm/FormatConverter.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -28,11 +28,31 @@
bool
PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
- gcc_unused Error &error)
+ Error &error)
{
assert(_src_format != SampleFormat::UNDEFINED);
assert(_dest_format != SampleFormat::UNDEFINED);
+ switch (_dest_format) {
+ case SampleFormat::UNDEFINED:
+ assert(false);
+ gcc_unreachable();
+
+ case SampleFormat::S8:
+ case SampleFormat::DSD:
+ error.Format(pcm_domain,
+ "PCM conversion from %s to %s is not implemented",
+ sample_format_to_string(_src_format),
+ sample_format_to_string(_dest_format));
+ return nullptr;
+
+ case SampleFormat::S16:
+ case SampleFormat::S24_P32:
+ case SampleFormat::S32:
+ case SampleFormat::FLOAT:
+ break;
+ }
+
src_format = _src_format;
dest_format = _dest_format;
return true;
@@ -48,20 +68,14 @@
}
ConstBuffer<void>
-PcmFormatConverter::Convert(ConstBuffer<void> src, Error &error)
+PcmFormatConverter::Convert(ConstBuffer<void> src, gcc_unused Error &error)
{
switch (dest_format) {
case SampleFormat::UNDEFINED:
- assert(false);
- gcc_unreachable();
-
case SampleFormat::S8:
case SampleFormat::DSD:
- error.Format(pcm_domain,
- "PCM conversion from %s to %s is not implemented",
- sample_format_to_string(src_format),
- sample_format_to_string(dest_format));
- return nullptr;
+ assert(false);
+ gcc_unreachable();
case SampleFormat::S16:
return pcm_convert_to_16(buffer, dither,
diff -Nru mpd-0.19.1/src/pcm/PcmConvert.cxx mpd-0.19.3/src/pcm/PcmConvert.cxx
--- mpd-0.19.1/src/pcm/PcmConvert.cxx 2014-09-26 12:17:58.000000000 +0200
+++ mpd-0.19.3/src/pcm/PcmConvert.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -51,7 +51,7 @@
}
bool
-PcmConvert::Open(AudioFormat _src_format, AudioFormat _dest_format,
+PcmConvert::Open(const AudioFormat _src_format, const AudioFormat _dest_format,
Error &error)
{
assert(!src_format.IsValid());
@@ -59,36 +59,34 @@
assert(_src_format.IsValid());
assert(_dest_format.IsValid());
- src_format = _src_format;
- dest_format = _dest_format;
-
- AudioFormat format = src_format;
+ AudioFormat format = _src_format;
if (format.format == SampleFormat::DSD)
format.format = SampleFormat::FLOAT;
- enable_resampler = format.sample_rate != dest_format.sample_rate;
+ enable_resampler = format.sample_rate != _dest_format.sample_rate;
if (enable_resampler) {
- if (!resampler.Open(format, dest_format.sample_rate, error))
+ if (!resampler.Open(format, _dest_format.sample_rate, error))
return false;
format.format = resampler.GetOutputSampleFormat();
- format.sample_rate = dest_format.sample_rate;
+ format.sample_rate = _dest_format.sample_rate;
}
- enable_format = format.format != dest_format.format;
+ enable_format = format.format != _dest_format.format;
if (enable_format &&
- !format_converter.Open(format.format, dest_format.format, error)) {
+ !format_converter.Open(format.format, _dest_format.format,
+ error)) {
if (enable_resampler)
resampler.Close();
return false;
}
- format.format = dest_format.format;
+ format.format = _dest_format.format;
- enable_channels = format.channels != dest_format.channels;
+ enable_channels = format.channels != _dest_format.channels;
if (enable_channels &&
!channels_converter.Open(format.format, format.channels,
- dest_format.channels, error)) {
+ _dest_format.channels, error)) {
if (enable_format)
format_converter.Close();
if (enable_resampler)
@@ -96,6 +94,9 @@
return false;
}
+ src_format = _src_format;
+ dest_format = _dest_format;
+
return true;
}
diff -Nru mpd-0.19.1/src/pcm/SoxrResampler.cxx mpd-0.19.3/src/pcm/SoxrResampler.cxx
--- mpd-0.19.1/src/pcm/SoxrResampler.cxx 2014-08-16 08:24:55.000000000 +0200
+++ mpd-0.19.3/src/pcm/SoxrResampler.cxx 2014-11-10 23:00:14.000000000 +0100
@@ -147,7 +147,8 @@
const size_t n_frames = src.size / frame_size;
- const size_t o_frames = size_t(n_frames * ratio + 0.5);
+ /* always round up: worst case output buffer size */
+ const size_t o_frames = size_t(n_frames * ratio) + 1;
float *output_buffer = (float *)buffer.Get(o_frames * frame_size);
diff -Nru mpd-0.19.1/src/playlist/PlaylistRegistry.cxx mpd-0.19.3/src/playlist/PlaylistRegistry.cxx
--- mpd-0.19.1/src/playlist/PlaylistRegistry.cxx 2014-05-12 18:59:46.000000000 +0200
+++ mpd-0.19.3/src/playlist/PlaylistRegistry.cxx 2014-11-01 13:18:48.000000000 +0100
@@ -139,12 +139,12 @@
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
const bool *tried)
{
- const char *suffix;
SongEnumerator *playlist = nullptr;
assert(uri != nullptr);
- suffix = uri_get_suffix(uri);
+ UriSuffixBuffer suffix_buffer;
+ const char *const suffix = uri_get_suffix(uri, suffix_buffer);
if (suffix == nullptr)
return nullptr;
@@ -257,7 +257,10 @@
return playlist;
}
- const char *suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr;
+ UriSuffixBuffer suffix_buffer;
+ const char *suffix = uri != nullptr
+ ? uri_get_suffix(uri, suffix_buffer)
+ : nullptr;
if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix);
if (playlist != nullptr)
diff -Nru mpd-0.19.1/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx mpd-0.19.3/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
--- mpd-0.19.1/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx 2014-10-19 00:37:35.000000000 +0200
+++ mpd-0.19.3/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -130,6 +130,7 @@
static const char *const extm3u_suffixes[] = {
"m3u",
+ "m3u8",
nullptr
};
diff -Nru mpd-0.19.1/src/playlist/plugins/M3uPlaylistPlugin.cxx mpd-0.19.3/src/playlist/plugins/M3uPlaylistPlugin.cxx
--- mpd-0.19.1/src/playlist/plugins/M3uPlaylistPlugin.cxx 2014-08-07 16:53:20.000000000 +0200
+++ mpd-0.19.3/src/playlist/plugins/M3uPlaylistPlugin.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -60,6 +60,7 @@
static const char *const m3u_suffixes[] = {
"m3u",
+ "m3u8",
nullptr
};
diff -Nru mpd-0.19.1/src/PlaylistFile.cxx mpd-0.19.3/src/PlaylistFile.cxx
--- mpd-0.19.1/src/PlaylistFile.cxx 2014-08-07 19:35:50.000000000 +0200
+++ mpd-0.19.3/src/PlaylistFile.cxx 2014-10-31 14:58:22.000000000 +0100
@@ -64,6 +64,10 @@
bool
spl_valid_name(const char *name_utf8)
{
+ if (*name_utf8 == 0)
+ /* empty name not allowed */
+ return false;
+
/*
* Not supporting '/' was done out of laziness, and we should
* really strive to support it in the future.
diff -Nru mpd-0.19.1/src/tag/Set.cxx mpd-0.19.3/src/tag/Set.cxx
--- mpd-0.19.1/src/tag/Set.cxx 2014-07-12 18:45:35.000000000 +0200
+++ mpd-0.19.3/src/tag/Set.cxx 2014-11-10 08:37:05.000000000 +0100
@@ -19,6 +19,7 @@
#include "Set.hxx"
#include "TagBuilder.hxx"
+#include "TagSettings.h"
#include <assert.h>
@@ -109,6 +110,7 @@
if (!CheckUnique(type, tag, type, group_mask) &&
(type != TAG_ALBUM_ARTIST ||
+ ignore_tag_items[TAG_ALBUM_ARTIST] ||
/* fall back to "Artist" if no "AlbumArtist" was found */
!CheckUnique(type, tag, TAG_ARTIST, group_mask)))
InsertUnique(tag, type, nullptr, group_mask);
diff -Nru mpd-0.19.1/src/TagStream.cxx mpd-0.19.3/src/TagStream.cxx
--- mpd-0.19.1/src/TagStream.cxx 2014-05-11 17:03:06.000000000 +0200
+++ mpd-0.19.3/src/TagStream.cxx 2014-11-01 13:15:55.000000000 +0100
@@ -46,7 +46,8 @@
{
assert(is.IsReady());
- const char *const suffix = uri_get_suffix(is.GetURI());
+ UriSuffixBuffer suffix_buffer;
+ const char *const suffix = uri_get_suffix(is.GetURI(), suffix_buffer);
const char *const mime = is.GetMimeType();
if (suffix == nullptr && mime == nullptr)
diff -Nru mpd-0.19.1/src/util/UriUtil.cxx mpd-0.19.3/src/util/UriUtil.cxx
--- mpd-0.19.1/src/util/UriUtil.cxx 2014-10-10 22:43:40.000000000 +0200
+++ mpd-0.19.3/src/util/UriUtil.cxx 2014-11-01 12:51:30.000000000 +0100
@@ -54,6 +54,23 @@
return suffix;
}
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
+{
+ const char *suffix = uri_get_suffix(uri);
+ if (suffix == nullptr)
+ return nullptr;
+
+ const char *q = strchr(suffix, '?');
+ if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
+ memcpy(buffer.data, suffix, q - suffix);
+ buffer.data[q - suffix] = 0;
+ suffix = buffer.data;
+ }
+
+ return suffix;
+}
+
static const char *
verify_uri_segment(const char *p)
{
diff -Nru mpd-0.19.1/src/util/UriUtil.hxx mpd-0.19.3/src/util/UriUtil.hxx
--- mpd-0.19.1/src/util/UriUtil.hxx 2014-10-10 22:43:40.000000000 +0200
+++ mpd-0.19.3/src/util/UriUtil.hxx 2014-11-01 13:41:16.000000000 +0100
@@ -42,6 +42,17 @@
const char *
uri_get_suffix(const char *uri);
+struct UriSuffixBuffer {
+ char data[8];
+};
+
+/**
+ * Returns the file name suffix, ignoring the query string.
+ */
+gcc_pure
+const char *
+uri_get_suffix(const char *uri, UriSuffixBuffer &buffer);
+
/**
* Returns true if this is a safe "local" URI:
*
diff -Nru mpd-0.19.1/test/DumpDatabase.cxx mpd-0.19.3/test/DumpDatabase.cxx
--- mpd-0.19.1/test/DumpDatabase.cxx 2014-02-23 19:55:27.000000000 +0100
+++ mpd-0.19.3/test/DumpDatabase.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -33,7 +33,9 @@
#include "event/Loop.hxx"
#include "util/Error.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <iostream>
using std::cout;
@@ -107,9 +109,11 @@
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(nullptr);
#endif
+#endif
/* initialize MPD */
diff -Nru mpd-0.19.1/test/FakeDecoderAPI.cxx mpd-0.19.3/test/FakeDecoderAPI.cxx
--- mpd-0.19.1/test/FakeDecoderAPI.cxx 2014-08-29 23:30:42.000000000 +0200
+++ mpd-0.19.3/test/FakeDecoderAPI.cxx 2014-11-10 08:52:27.000000000 +0100
@@ -132,6 +132,12 @@
const void *data, size_t datalen,
gcc_unused uint16_t kbit_rate)
{
+ static uint16_t prev_kbit_rate;
+ if (kbit_rate != prev_kbit_rate) {
+ prev_kbit_rate = kbit_rate;
+ fprintf(stderr, "%u kbit/s\n", kbit_rate);
+ }
+
gcc_unused ssize_t nbytes = write(1, data, datalen);
return DecoderCommand::NONE;
}
diff -Nru mpd-0.19.1/test/read_mixer.cxx mpd-0.19.3/test/read_mixer.cxx
--- mpd-0.19.1/test/read_mixer.cxx 2014-02-19 21:59:25.000000000 +0100
+++ mpd-0.19.3/test/read_mixer.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -28,7 +28,9 @@
#include "util/Error.hxx"
#include "Log.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <assert.h>
#include <string.h>
@@ -50,9 +52,11 @@
return EXIT_FAILURE;
}
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
EventLoop event_loop;
diff -Nru mpd-0.19.1/test/test_archive.cxx mpd-0.19.3/test/test_archive.cxx
--- mpd-0.19.1/test/test_archive.cxx 2014-01-24 09:49:05.000000000 +0100
+++ mpd-0.19.3/test/test_archive.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -7,8 +7,6 @@
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
-#include <glib.h>
-
#include <string.h>
#include <stdlib.h>
@@ -29,22 +27,22 @@
char *path = strdup("");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup(".");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("config.h");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("src/foo/bar");
CPPUNIT_ASSERT_EQUAL(false,
archive_lookup(path, &archive, &inpath, &suffix));
- g_free(path);
+ free(path);
path = strdup("Makefile/foo/bar");
CPPUNIT_ASSERT_EQUAL(true,
@@ -53,7 +51,7 @@
CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "Makefile"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr, suffix);
- g_free(path);
+ free(path);
path = strdup("config.h/foo/bar");
CPPUNIT_ASSERT_EQUAL(true,
@@ -62,7 +60,7 @@
CPPUNIT_ASSERT_EQUAL(0, strcmp(archive, "config.h"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(inpath, "foo/bar"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(suffix, "h"));
- g_free(path);
+ free(path);
}
CPPUNIT_TEST_SUITE_REGISTRATION(ArchiveLookupTest);
diff -Nru mpd-0.19.1/test/test_util.cxx mpd-0.19.3/test/test_util.cxx
--- mpd-0.19.1/test/test_util.cxx 2014-10-10 22:40:13.000000000 +0200
+++ mpd-0.19.3/test/test_util.cxx 2014-11-01 13:14:50.000000000 +0100
@@ -34,6 +34,25 @@
uri_get_suffix(".jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/.jpg"));
+
+ /* the first overload does not eliminate the query
+ string */
+ CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
+ "jpg?query_string"));
+
+ /* ... but the second one does */
+ UriSuffixBuffer buffer;
+ CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
+ buffer),
+ "jpg"));
+
+ /* repeat some of the above tests with the second overload */
+ CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+ uri_get_suffix("/foo/bar", buffer));
+ CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
+ uri_get_suffix("/foo.jpg/bar", buffer));
+ CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
+ "jpg"));
}
void TestRemoveAuth() {
diff -Nru mpd-0.19.1/test/visit_archive.cxx mpd-0.19.3/test/visit_archive.cxx
--- mpd-0.19.1/test/visit_archive.cxx 2014-10-07 20:09:31.000000000 +0200
+++ mpd-0.19.3/test/visit_archive.cxx 2014-10-27 09:26:34.000000000 +0100
@@ -30,7 +30,9 @@
#include "fs/Path.hxx"
#include "util/Error.hxx"
+#ifdef HAVE_GLIB
#include <glib.h>
+#endif
#include <unistd.h>
#include <stdlib.h>
@@ -57,9 +59,11 @@
/* initialize GLib */
+#ifdef HAVE_GLIB
#if !GLIB_CHECK_VERSION(2,32,0)
g_thread_init(NULL);
#endif
+#endif
/* initialize MPD */
Reply to: