From bc5a53574c64eb51d2cbf31b26f4607e566eeaab Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 25 Oct 2014 20:42:50 +0200 Subject: [PATCH 01/28] decoder/faad: remove workaround for ancient libfaad2 ABI bug Many years ago, FAAD had a serious ABI bug: the NeAACDecInit() prototype in its header declared the "samplerate" parameter to be "unsigned long *", but internally, the function assumed it was "uint32_t *" instead. On 32 bit machines, that was no difference, but on 64 bit, this left one portion of the return value uninitialized; and worse, on big-endian, the wrong word was filled. This bug had to be worked around in MPD (commit 9c4e97a6). A few months later, the bug was fixed in the FAAD CVS in commit 1.117 on file libfaad/decoder.c; the commit message was: "Use public headers internally to prevent duplicate declarations" The commit message was too brief at best; the problem was not duplicate declarations, but a prototype mismatch. No mention of the bug fix in the ChangeLog. The MPD project never learned about this bug fix, and so MPD would always pass a "uin32_t *" dressed up as a "unsigned long *". Nearly 6 years later, it's about time to fix this second ABI problem. Let's kill the workaround! --- NEWS | 1 + m4/faad.m4 | 31 +--------------------- src/decoder/plugins/FaadDecoderPlugin.cxx | 12 ++------- src/decoder/plugins/Mp4v2DecoderPlugin.cxx | 12 ++------- 4 files changed, 6 insertions(+), 50 deletions(-) diff --git a/NEWS b/NEWS index e1497a0ed..2a6c5c439 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.19.2 (not yet released) * decoder + - faad: remove workaround for ancient libfaad2 ABI bug - ffmpeg: recognize MIME type audio/aacp * output - fix memory leak after filter initialization error diff --git a/m4/faad.m4 b/m4/faad.m4 index 5ca520e79..9dcb1ccab 100644 --- a/m4/faad.m4 +++ b/m4/faad.m4 @@ -62,36 +62,7 @@ int main() { 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 -#include -#include - -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 --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx index 793ab1011..add23aaa4 100644 --- a/src/decoder/plugins/FaadDecoderPlugin.cxx +++ b/src/decoder/plugins/FaadDecoderPlugin.cxx @@ -255,20 +255,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer &buffer, } 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(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 --git a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx index bf97763c5..34bccd243 100644 --- a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx +++ b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx @@ -39,15 +39,7 @@ static MP4TrackId 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 @@ mp4_get_aac_track(MP4FileHandle handle, NeAACDecHandle decoder, uint8_t channels; int32_t nbytes = NeAACDecInit(decoder, buff, buff_size, - sample_rate_r, &channels); + &sample_rate, &channels); free(buff); From d7f024c51047222dda4224c56865d66c8f384c76 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 25 Oct 2014 21:25:49 +0200 Subject: [PATCH 02/28] OutputThread: fall back to PCM if given DSD sample rate is not supported Works around the "PCM conversion from f to dsd is not implemented" error message that prevents DSD playback. --- NEWS | 1 + src/output/OutputThread.cxx | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/NEWS b/NEWS index 2a6c5c439..658ca8c5f 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.19.2 (not yet released) - ffmpeg: recognize MIME type audio/aacp * 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 diff --git a/src/output/OutputThread.cxx b/src/output/OutputThread.cxx index 54664bb65..2ec0670c1 100644 --- a/src/output/OutputThread.cxx +++ b/src/output/OutputThread.cxx @@ -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 @@ AudioOutput::Open() 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(); @@ -189,6 +194,31 @@ AudioOutput::Open() 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(); From 394e3be482ed492e5d90222dab828c2448fbccce Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 26 Oct 2014 08:14:16 +0100 Subject: [PATCH 03/28] playlist/m3u: recognize the file suffix ".m3u8" --- NEWS | 2 ++ src/playlist/plugins/ExtM3uPlaylistPlugin.cxx | 1 + src/playlist/plugins/M3uPlaylistPlugin.cxx | 1 + 3 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 658ca8c5f..6b2282a20 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.19.2 (not yet released) +* playlist + - m3u: recognize the file suffix ".m3u8" * decoder - faad: remove workaround for ancient libfaad2 ABI bug - ffmpeg: recognize MIME type audio/aacp diff --git a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx index fdd4357ca..93316ca6c 100644 --- a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx +++ b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx @@ -130,6 +130,7 @@ ExtM3uPlaylist::NextSong() static const char *const extm3u_suffixes[] = { "m3u", + "m3u8", nullptr }; diff --git a/src/playlist/plugins/M3uPlaylistPlugin.cxx b/src/playlist/plugins/M3uPlaylistPlugin.cxx index a4125bc70..0428d291a 100644 --- a/src/playlist/plugins/M3uPlaylistPlugin.cxx +++ b/src/playlist/plugins/M3uPlaylistPlugin.cxx @@ -60,6 +60,7 @@ M3uPlaylist::NextSong() static const char *const m3u_suffixes[] = { "m3u", + "m3u8", nullptr }; From 217d88f21f11236478dd41c37b67bef5b0a06497 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 28 Oct 2014 22:10:47 +0100 Subject: [PATCH 04/28] TextInputStream: don't ignore unterminated last line --- NEWS | 1 + src/input/TextInputStream.cxx | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 6b2282a20..5541db7f2 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.19.2 (not yet released) * playlist + - m3u: don't ignore unterminated last line - m3u: recognize the file suffix ".m3u8" * decoder - faad: remove workaround for ancient libfaad2 ABI bug diff --git a/src/input/TextInputStream.cxx b/src/input/TextInputStream.cxx index b79f64bdc..5a8dcc065 100644 --- a/src/input/TextInputStream.cxx +++ b/src/input/TextInputStream.cxx @@ -38,8 +38,8 @@ TextInputStream::ReadLine() 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 @@ TextInputStream::ReadLine() 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; + } } } From 54c591bd9d9657065fb1c338eefe416840c78d3e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 28 Oct 2014 22:22:30 +0100 Subject: [PATCH 05/28] decoder/mad: fix negative replay gain values Negating an unsigned integer does not work. --- NEWS | 1 + src/decoder/plugins/MadDecoderPlugin.cxx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 5541db7f2..66862543b 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,7 @@ ver 0.19.2 (not yet released) * decoder - 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 diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx index 41efb593d..de6c9b127 100644 --- a/src/decoder/plugins/MadDecoderPlugin.cxx +++ b/src/decoder/plugins/MadDecoderPlugin.cxx @@ -657,7 +657,7 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) 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", From 7350144ab36879ec92fdad3f4d3919913e660799 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 31 Oct 2014 14:59:27 +0100 Subject: [PATCH 06/28] PlaylistFile: don't allow empty playlist name --- NEWS | 1 + src/PlaylistFile.cxx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 66862543b..64490ac36 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.19.2 (not yet released) * playlist + - don't allow empty playlist name - m3u: don't ignore unterminated last line - m3u: recognize the file suffix ".m3u8" * decoder diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx index f0aa2d2d7..ab269378a 100644 --- a/src/PlaylistFile.cxx +++ b/src/PlaylistFile.cxx @@ -64,6 +64,10 @@ spl_global_init(void) 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. From 6ad1e4d99aba346440e984a232a312ea49561e7d Mon Sep 17 00:00:00 2001 From: NanoTech Date: Sun, 12 Oct 2014 16:23:33 -0600 Subject: [PATCH 07/28] Revert "Main: run the OS X native event loop" This reverts commit f0be48ff90503d9ffa5b295fd4454eec753950ee (except for the NEWS entry). If libdispatch (GCD) is used before forking, it can't safely be used again after forking. --- Makefile.am | 1 - src/Main.cxx | 2 -- src/Main.hxx | 11 ----------- src/osx/OSXMain.cxx | 37 ------------------------------------- 4 files changed, 51 deletions(-) delete mode 100644 src/osx/OSXMain.cxx diff --git a/Makefile.am b/Makefile.am index c105b9945..dac3e1772 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,7 +130,6 @@ libmpd_a_SOURCES = \ 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 \ diff --git a/src/Main.cxx b/src/Main.cxx index d17590e44..417e055d6 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -401,8 +401,6 @@ int main(int argc, char *argv[]) { #ifdef WIN32 return win32_main(argc, argv); -#elif __APPLE__ - return osx_main(argc, argv); #else return mpd_main(argc, argv); #endif diff --git a/src/Main.hxx b/src/Main.hxx index dae7a5043..7e3fecd0b 100644 --- a/src/Main.hxx +++ b/src/Main.hxx @@ -75,15 +75,4 @@ win32_app_stopping(void); #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 --git a/src/osx/OSXMain.cxx b/src/osx/OSXMain.cxx deleted file mode 100644 index 1ac9aec23..000000000 --- a/src/osx/OSXMain.cxx +++ /dev/null @@ -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 -#include - -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 From d42c0f1dc5063d50a62817b63a1c2a4507c46071 Mon Sep 17 00:00:00 2001 From: NanoTech Date: Sun, 12 Oct 2014 16:29:43 -0600 Subject: [PATCH 08/28] Main: run the OS X native event loop after forking --- src/Main.cxx | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Main.cxx b/src/Main.cxx index 417e055d6..2719c05e0 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -114,6 +114,10 @@ #include #endif +#ifdef __APPLE__ +#include +#endif + #include static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096; @@ -408,6 +412,8 @@ int main(int argc, char *argv[]) #endif +static int mpd_main_after_fork(struct options); + #ifdef ANDROID static inline #endif @@ -511,6 +517,27 @@ int mpd_main(int argc, char *argv[]) daemonize_begin(options.daemon); #endif +#ifdef __APPLE__ + /* 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 From eab32f2e5d8114d08e392001f0004284267bebd5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 12:45:47 +0100 Subject: [PATCH 09/28] util/UriUtil: add uri_get_suffix() overload that ignores query string --- src/util/UriUtil.cxx | 17 +++++++++++++++++ src/util/UriUtil.hxx | 11 +++++++++++ test/test_util.cxx | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx index fdca47c00..62977e91b 100644 --- a/src/util/UriUtil.cxx +++ b/src/util/UriUtil.cxx @@ -54,6 +54,23 @@ uri_get_suffix(const char *uri) 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 --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx index c2cc97a63..d478d5b92 100644 --- a/src/util/UriUtil.hxx +++ b/src/util/UriUtil.hxx @@ -42,6 +42,17 @@ gcc_pure 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 --git a/test/test_util.cxx b/test/test_util.cxx index aaadec68f..3e79aeca0 100644 --- a/test/test_util.cxx +++ b/test/test_util.cxx @@ -34,6 +34,25 @@ public: 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() { From 7d5442e1039869d659533eafcf15d8157bf4c465 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 13:20:39 +0100 Subject: [PATCH 10/28] Decoder, Playlist: ignore URI query string for plugin detection Use the new uri_get_suffix() overload that removes the query string. --- NEWS | 1 + src/TagStream.cxx | 3 ++- src/decoder/DecoderThread.cxx | 3 ++- src/playlist/PlaylistRegistry.cxx | 9 ++++++--- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 64490ac36..4982e98ad 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ ver 0.19.2 (not yet released) - 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 diff --git a/src/TagStream.cxx b/src/TagStream.cxx index 639763373..6201028f6 100644 --- a/src/TagStream.cxx +++ b/src/TagStream.cxx @@ -46,7 +46,8 @@ tag_stream_scan(InputStream &is, const tag_handler &handler, void *ctx) { 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 --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx index a39cfa6e9..dd5518b98 100644 --- a/src/decoder/DecoderThread.cxx +++ b/src/decoder/DecoderThread.cxx @@ -237,7 +237,8 @@ static bool 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 --git a/src/playlist/PlaylistRegistry.cxx b/src/playlist/PlaylistRegistry.cxx index bc5932de3..4e9ef890e 100644 --- a/src/playlist/PlaylistRegistry.cxx +++ b/src/playlist/PlaylistRegistry.cxx @@ -139,12 +139,12 @@ static SongEnumerator * 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 @@ playlist_list_open_stream(InputStream &is, const char *uri) 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) From a8770aa606a1d83f252d150530db667bc7614da9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 14:09:30 +0100 Subject: [PATCH 11/28] input/curl: fix curl_easy_setopt() parameter types --- src/input/plugins/CurlInputPlugin.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 617805e2c..42575a3fa 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -720,9 +720,9 @@ CurlInputStream::InitEasy(Error &error) 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_FOLLOWLOCATION, 1l); + curl_easy_setopt(easy, CURLOPT_NETRC, 1l); + curl_easy_setopt(easy, CURLOPT_MAXREDIRS, 5l); curl_easy_setopt(easy, CURLOPT_FAILONERROR, true); curl_easy_setopt(easy, CURLOPT_ERRORBUFFER, error_buffer); curl_easy_setopt(easy, CURLOPT_NOPROGRESS, 1l); From 054323c2bc8ec5f1e417f85e3293f2a91d8425d8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 11:04:13 +0100 Subject: [PATCH 12/28] lib/upnp/Discovery: add missing stdlib.h include --- src/lib/upnp/Discovery.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/upnp/Discovery.cxx b/src/lib/upnp/Discovery.cxx index 9ea78c624..1539e1512 100644 --- a/src/lib/upnp/Discovery.cxx +++ b/src/lib/upnp/Discovery.cxx @@ -26,6 +26,7 @@ #include +#include #include // The service type string we are looking for. From 432ce9b1de0f89e0f714d182980d5a562024faa5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 11:41:40 +0100 Subject: [PATCH 13/28] configure.ac: prepare for 0.18.17 --- NEWS | 2 ++ configure.ac | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 2e8c2dcdb..bea9b2ebb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,5 @@ +ver 0.18.17 (not yet released) + ver 0.18.16 (2014/09/26) * fix DSD breakage due to typo in configure.ac diff --git a/configure.ac b/configure.ac index 3d6b8526c..d6526e883 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ AC_PREREQ(2.60) -AC_INIT(mpd, 0.18.16, mpd-devel@musicpd.org) +AC_INIT(mpd, 0.18.17, mpd-devel@musicpd.org) VERSION_MAJOR=0 VERSION_MINOR=18 -VERSION_REVISION=0 +VERSION_REVISION=17 VERSION_EXTRA=0 AC_CONFIG_SRCDIR([src/Main.cxx]) From c37f7abb79b6c9f30a77ea605b18674acc5ffff2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 10 Oct 2014 22:06:48 +0200 Subject: [PATCH 14/28] TagString: use g_strndup() for unterminated string Fixes buffer overflow bug. --- src/tag/TagString.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tag/TagString.cxx b/src/tag/TagString.cxx index 3e8d8c1b0..9ab095249 100644 --- a/src/tag/TagString.cxx +++ b/src/tag/TagString.cxx @@ -33,7 +33,7 @@ patch_utf8(const char *src, size_t length, const gchar *end) { /* duplicate the string, and replace invalid bytes in that buffer */ - char *dest = g_strdup(src); + char *dest = g_strndup(src, length); do { dest[end - src] = '?'; From c50a0cf7bf96a3eb2d49e5416dfe88dc86a589ef Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 23 Oct 2014 23:29:56 +0200 Subject: [PATCH 15/28] output/roar: remove unnecessary "volatile" keyword A mutex acts as a memory barrier, and thus "volatile" is not necessary. --- src/output/RoarOutputPlugin.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output/RoarOutputPlugin.cxx b/src/output/RoarOutputPlugin.cxx index 895a165d1..20d69f3f9 100644 --- a/src/output/RoarOutputPlugin.cxx +++ b/src/output/RoarOutputPlugin.cxx @@ -46,7 +46,7 @@ class RoarOutput { struct roar_connection con; struct roar_audio_info info; mutable Mutex mutex; - volatile bool alive; + bool alive; public: RoarOutput() From 94c240a0264b7ce1693fc341778ac19ac3a535b9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 25 Oct 2014 00:19:01 +0200 Subject: [PATCH 16/28] configure.ac: show DSD in result --- configure.ac | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.ac b/configure.ac index d6526e883..05a4f5050 100644 --- a/configure.ac +++ b/configure.ac @@ -1523,6 +1523,7 @@ results(un,[UNIX Domain Sockets]) 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]) From bccd4ef2f72f723b7abb1d7f6d004a70cad735aa Mon Sep 17 00:00:00 2001 From: Steven OBrien Date: Sun, 9 Feb 2014 15:47:45 +0000 Subject: [PATCH 17/28] decoder/ffmpeg: recognize MIME type audio/aacp --- NEWS | 2 ++ src/decoder/FfmpegDecoderPlugin.cxx | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index bea9b2ebb..0706e447c 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.18.17 (not yet released) +* decoder + - ffmpeg: recognize MIME type audio/aacp ver 0.18.16 (2014/09/26) * fix DSD breakage due to typo in configure.ac diff --git a/src/decoder/FfmpegDecoderPlugin.cxx b/src/decoder/FfmpegDecoderPlugin.cxx index 9cd26c4fa..104129ad9 100644 --- a/src/decoder/FfmpegDecoderPlugin.cxx +++ b/src/decoder/FfmpegDecoderPlugin.cxx @@ -643,6 +643,7 @@ static const char *const ffmpeg_mime_types[] = { "audio/8svx", "audio/16sv", "audio/aac", + "audio/aacp", "audio/ac3", "audio/aiff" "audio/amr", From f6b2899dd2f2b7985da0cf3734a7276ea54e23a2 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 25 Oct 2014 20:42:50 +0200 Subject: [PATCH 18/28] decoder/faad: remove workaround for ancient libfaad2 ABI bug Many years ago, FAAD had a serious ABI bug: the NeAACDecInit() prototype in its header declared the "samplerate" parameter to be "unsigned long *", but internally, the function assumed it was "uint32_t *" instead. On 32 bit machines, that was no difference, but on 64 bit, this left one portion of the return value uninitialized; and worse, on big-endian, the wrong word was filled. This bug had to be worked around in MPD (commit 9c4e97a6). A few months later, the bug was fixed in the FAAD CVS in commit 1.117 on file libfaad/decoder.c; the commit message was: "Use public headers internally to prevent duplicate declarations" The commit message was too brief at best; the problem was not duplicate declarations, but a prototype mismatch. No mention of the bug fix in the ChangeLog. The MPD project never learned about this bug fix, and so MPD would always pass a "uin32_t *" dressed up as a "unsigned long *". Nearly 6 years later, it's about time to fix this second ABI problem. Let's kill the workaround! --- NEWS | 1 + m4/faad.m4 | 31 +------------------------------ src/decoder/FaadDecoderPlugin.cxx | 12 ++---------- 3 files changed, 4 insertions(+), 40 deletions(-) diff --git a/NEWS b/NEWS index 0706e447c..f27bd8c4f 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.18.17 (not yet released) * decoder + - faad: remove workaround for ancient libfaad2 ABI bug - ffmpeg: recognize MIME type audio/aacp ver 0.18.16 (2014/09/26) diff --git a/m4/faad.m4 b/m4/faad.m4 index 5ca520e79..9dcb1ccab 100644 --- a/m4/faad.m4 +++ b/m4/faad.m4 @@ -62,36 +62,7 @@ int main() { 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 -#include -#include - -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 --git a/src/decoder/FaadDecoderPlugin.cxx b/src/decoder/FaadDecoderPlugin.cxx index b446ac5be..ae1181b4c 100644 --- a/src/decoder/FaadDecoderPlugin.cxx +++ b/src/decoder/FaadDecoderPlugin.cxx @@ -277,20 +277,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer, } 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(data), length, - sample_rate_p, &channels); + &sample_rate, &channels); if (nbytes < 0) { error.Set(faad_decoder_domain, "Not an AAC stream"); return false; From c882568ccd5271a3f2c9d97a9a718706f9e71a65 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 26 Oct 2014 08:14:16 +0100 Subject: [PATCH 19/28] playlist/m3u: recognize the file suffix ".m3u8" --- NEWS | 2 ++ src/playlist/ExtM3uPlaylistPlugin.cxx | 3 ++- src/playlist/M3uPlaylistPlugin.cxx | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index f27bd8c4f..439f39c4e 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.18.17 (not yet released) +* playlist + - m3u: recognize the file suffix ".m3u8" * decoder - faad: remove workaround for ancient libfaad2 ABI bug - ffmpeg: recognize MIME type audio/aacp diff --git a/src/playlist/ExtM3uPlaylistPlugin.cxx b/src/playlist/ExtM3uPlaylistPlugin.cxx index 8d260fec7..5ef010bda 100644 --- a/src/playlist/ExtM3uPlaylistPlugin.cxx +++ b/src/playlist/ExtM3uPlaylistPlugin.cxx @@ -135,7 +135,8 @@ ExtM3uPlaylist::NextSong() static const char *const extm3u_suffixes[] = { "m3u", - NULL + "m3u8", + nullptr }; static const char *const extm3u_mime_types[] = { diff --git a/src/playlist/M3uPlaylistPlugin.cxx b/src/playlist/M3uPlaylistPlugin.cxx index 3f99bdfdf..8b6adc2b6 100644 --- a/src/playlist/M3uPlaylistPlugin.cxx +++ b/src/playlist/M3uPlaylistPlugin.cxx @@ -61,6 +61,7 @@ M3uPlaylist::NextSong() static const char *const m3u_suffixes[] = { "m3u", + "m3u8", nullptr }; From 6ad336743d861a03df3079058fdc18eee07a3014 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 31 Oct 2014 14:59:27 +0100 Subject: [PATCH 20/28] PlaylistFile: don't allow empty playlist name --- NEWS | 1 + src/PlaylistFile.cxx | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 439f39c4e..509627858 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ ver 0.18.17 (not yet released) * playlist + - don't allow empty playlist name - m3u: recognize the file suffix ".m3u8" * decoder - faad: remove workaround for ancient libfaad2 ABI bug diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx index e7dae6258..e5285ad04 100644 --- a/src/PlaylistFile.cxx +++ b/src/PlaylistFile.cxx @@ -69,6 +69,10 @@ spl_global_init(void) 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. From 674091424e715fddd8fbfe8146f351da5bf84974 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 12:45:47 +0100 Subject: [PATCH 21/28] util/UriUtil: add uri_get_suffix() overload that ignores query string --- src/util/UriUtil.cxx | 17 +++++++++++++++++ src/util/UriUtil.hxx | 11 +++++++++++ test/test_util.cxx | 19 +++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx index 2609db2cf..1783fbca5 100644 --- a/src/util/UriUtil.cxx +++ b/src/util/UriUtil.cxx @@ -44,6 +44,23 @@ uri_get_suffix(const char *uri) 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 --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx index 78d0a6bff..1c6bce3ff 100644 --- a/src/util/UriUtil.hxx +++ b/src/util/UriUtil.hxx @@ -35,6 +35,17 @@ gcc_pure 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 --git a/test/test_util.cxx b/test/test_util.cxx index a472391a3..91e87957f 100644 --- a/test/test_util.cxx +++ b/test/test_util.cxx @@ -33,6 +33,25 @@ public: 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() { From 32b5654a6e7738211e6aa18ab8089cc6328aa1fa Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 13:20:39 +0100 Subject: [PATCH 22/28] Decoder, Playlist: ignore URI query string for plugin detection Use the new uri_get_suffix() overload that removes the query string. --- NEWS | 1 + src/DecoderThread.cxx | 3 ++- src/PlaylistRegistry.cxx | 11 ++++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 509627858..1cebfd2db 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.18.17 (not yet released) - 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 diff --git a/src/DecoderThread.cxx b/src/DecoderThread.cxx index cf21534f0..7ee36faca 100644 --- a/src/DecoderThread.cxx +++ b/src/DecoderThread.cxx @@ -212,7 +212,8 @@ static bool 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 --git a/src/PlaylistRegistry.cxx b/src/PlaylistRegistry.cxx index 9afbe349d..f81978322 100644 --- a/src/PlaylistRegistry.cxx +++ b/src/PlaylistRegistry.cxx @@ -164,12 +164,12 @@ static SongEnumerator * 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; @@ -273,8 +273,6 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix) SongEnumerator * playlist_list_open_stream(InputStream &is, const char *uri) { - const char *suffix; - is.LockWaitReady(); const char *const mime = is.GetMimeType(); @@ -284,7 +282,10 @@ playlist_list_open_stream(InputStream &is, const char *uri) return playlist; } - 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) From ec3191f50279c432ffef7449133db1d4c433120c Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sat, 1 Nov 2014 14:09:30 +0100 Subject: [PATCH 23/28] input/curl: fix curl_easy_setopt() parameter types --- src/input/CurlInputPlugin.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/input/CurlInputPlugin.cxx b/src/input/CurlInputPlugin.cxx index b78545951..031ebfea6 100644 --- a/src/input/CurlInputPlugin.cxx +++ b/src/input/CurlInputPlugin.cxx @@ -983,10 +983,10 @@ input_curl_easy_init(struct input_curl *c, Error &error) input_curl_writefunction); curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c); curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases); - curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1); - curl_easy_setopt(c->easy, CURLOPT_NETRC, 1); - curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5); - curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true); + curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1l); + curl_easy_setopt(c->easy, CURLOPT_NETRC, 1l); + curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5l); + curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, 1l); 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); From 05c63af7c473de374406d76e146d73245de10a2b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 12:59:16 +0100 Subject: [PATCH 24/28] InputStream: add method ClearMimeType() --- src/input/InputStream.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx index 15c350103..81b903ba2 100644 --- a/src/input/InputStream.hxx +++ b/src/input/InputStream.hxx @@ -200,6 +200,10 @@ public: return mime.empty() ? nullptr : mime.c_str(); } + void ClearMimeType() { + mime.clear(); + } + gcc_nonnull_all void SetMimeType(const char *_mime) { assert(!ready); From a2eb14f3b379c966b259825c91c154f475f13eb6 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 13:00:25 +0100 Subject: [PATCH 25/28] AsyncInputStream: add method ClearTag() --- src/input/AsyncInputStream.hxx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/input/AsyncInputStream.hxx b/src/input/AsyncInputStream.hxx index 7935f1a17..d1f0c3b9d 100644 --- a/src/input/AsyncInputStream.hxx +++ b/src/input/AsyncInputStream.hxx @@ -83,6 +83,10 @@ protected: */ void SetTag(Tag *_tag); + void ClearTag() { + SetTag(nullptr); + } + void Pause(); bool IsPaused() const { From 56f763a4a83f6410b1bd9e1f8b41240df535ebc9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 12:59:45 +0100 Subject: [PATCH 26/28] input/curl: forget Content-Length (and more) after redirect Fixes playback of redirected streams. --- NEWS | 2 ++ src/input/plugins/CurlInputPlugin.cxx | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/NEWS b/NEWS index 2f04931e6..a9fabed98 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.19.2 (not yet released) +* input + - curl: fix redirected streams * playlist - don't allow empty playlist name - m3u: don't ignore unterminated last line diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 0028158a3..1e1a46108 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -109,6 +109,13 @@ struct CurlInputStream final : public AsyncInputStream { */ 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); @@ -597,6 +604,20 @@ CurlInputStream::~CurlInputStream() FreeEasyIndirect(); } +inline void +CurlInputStream::ResponseBoundary() +{ + /* undo all effects of HeaderReceived() because the previous + response was not applicable for this stream */ + + seekable = false; + size = UNKNOWN_SIZE; + ClearMimeType(); + ClearTag(); + + // TODO: reset the IcyInputStream? +} + inline void CurlInputStream::HeaderReceived(const char *name, std::string &&value) { @@ -645,6 +666,11 @@ input_curl_headerfunction(void *ptr, size_t size, size_t nmemb, void *stream) 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]; From 38a0d15190a8ff45749dd7f048812ace35b9be7d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 13:06:20 +0100 Subject: [PATCH 27/28] release v0.18.17 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1cebfd2db..9be75c42e 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.18.17 (not yet released) +ver 0.18.17 (2014/11/02) * playlist - don't allow empty playlist name - m3u: recognize the file suffix ".m3u8" From 6a7f6cdacd81877276563c42fdeacad3a8deface Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Sun, 2 Nov 2014 13:46:32 +0100 Subject: [PATCH 28/28] release v0.19.2 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 823f3dd6d..e8e84ff7e 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.19.2 (not yet released) +ver 0.19.2 (2014/11/02) * input - curl: fix redirected streams * playlist