diff --git a/AUTHORS b/AUTHORS index 14aa053fa..7625fcdda 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,3 +31,8 @@ The following people have contributed code to MPD: Jean-Francois Dockes Yue Wang Matthew Leon Grinshpun + Dimitris Papastamos + Florian Schlichting + François Revol + Jacob Vosmaer + Thomas Guillem diff --git a/NEWS b/NEWS index c8d400113..9dcde8cfc 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,8 @@ ver 0.21 (not yet released) ver 0.20.19 (not yet released) * protocol - validate absolute seek time, reject negative values +* input + - mms: fix lockup bug and a crash bug * macOS: fix crash bug ver 0.20.18 (2018/02/24) diff --git a/configure.ac b/configure.ac index 325eaa77e..17effba43 100644 --- a/configure.ac +++ b/configure.ac @@ -465,7 +465,7 @@ dnl --------------------------------------------------------------------------- dnl Mandatory Libraries dnl --------------------------------------------------------------------------- -AX_BOOST_BASE([1.46],, [AC_MSG_ERROR([Boost not found])]) +AX_BOOST_BASE([1.54],, [AC_MSG_ERROR([Boost not found])]) AC_ARG_ENABLE(icu, AS_HELP_STRING([--enable-icu], diff --git a/doc/user.xml b/doc/user.xml index 8ae71f51a..f63ed2a0a 100644 --- a/doc/user.xml +++ b/doc/user.xml @@ -79,7 +79,10 @@ If you need to tweak the configuration, you can create a file - called mpd.conf on the data partition. + called mpd.conf on the data partition + (the directory which is returned by Android's getExternalStorageDirectory() + API function). @@ -111,7 +114,7 @@ cd mpd-version - Boost 1.46 + Boost 1.54 diff --git a/python/build/libs.py b/python/build/libs.py index 18b4cbbaf..1c99a37cb 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -334,8 +334,8 @@ ffmpeg = FfmpegProject( ) curl = AutotoolsProject( - 'http://curl.haxx.se/download/curl-7.58.0.tar.xz', - '6a813875243609eb75f37fa72044e4ad618b55ec15a4eafdac2df6a7e800e3e3', + 'http://curl.haxx.se/download/curl-7.59.0.tar.xz', + 'e44eaabdf916407585bf5c7939ff1161e6242b6b015d3f2f5b758b2a330461fc', 'lib/libcurl.a', [ '--disable-shared', '--enable-static', diff --git a/src/input/ThreadInputStream.cxx b/src/input/ThreadInputStream.cxx index bfcf43394..f33f8dbd7 100644 --- a/src/input/ThreadInputStream.cxx +++ b/src/input/ThreadInputStream.cxx @@ -37,8 +37,12 @@ ThreadInputStream::ThreadInputStream(const char *_plugin, allocation.ForkCow(false); } -ThreadInputStream::~ThreadInputStream() noexcept +void +ThreadInputStream::Stop() noexcept { + if (!thread.IsDefined()) + return; + { const std::lock_guard lock(mutex); close = true; @@ -69,7 +73,7 @@ ThreadInputStream::ThreadFunc() noexcept Open(); } catch (...) { postponed_exception = std::current_exception(); - cond.broadcast(); + SetReady(); return; } diff --git a/src/input/ThreadInputStream.hxx b/src/input/ThreadInputStream.hxx index c3ab0f653..4883dae24 100644 --- a/src/input/ThreadInputStream.hxx +++ b/src/input/ThreadInputStream.hxx @@ -29,6 +29,7 @@ #include +#include #include /** @@ -39,6 +40,11 @@ * manages the thread and the buffer. * * This works only for "streams": unknown length, no seeking, no tags. + * + * The implementation must call Stop() before its destruction + * completes. This cannot be done in ~ThreadInputStream() because at + * this point, the class has been morphed back to #ThreadInputStream + * and the still-running thread will crash due to pure method call. */ class ThreadInputStream : public InputStream { const char *const plugin; @@ -73,7 +79,12 @@ public: const char *_uri, Mutex &_mutex, Cond &_cond, size_t _buffer_size) noexcept; - virtual ~ThreadInputStream() noexcept; +#ifndef NDEBUG + ~ThreadInputStream() override { + /* Stop() must have been called already */ + assert(!thread.IsDefined()); + } +#endif /** * Initialize the object and start the thread. @@ -87,6 +98,12 @@ public: size_t Read(void *ptr, size_t size) override final; protected: + /** + * Stop the thread and free the buffer. This must be called + * before destruction of this object completes. + */ + void Stop() noexcept; + void SetMimeType(const char *_mime) noexcept { assert(thread.IsInside()); diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx index 022245fd0..de35e2f15 100644 --- a/src/input/plugins/MmsInputPlugin.cxx +++ b/src/input/plugins/MmsInputPlugin.cxx @@ -39,6 +39,10 @@ public: MMS_BUFFER_SIZE) { } + ~MmsInputStream() noexcept override { + Stop(); + } + protected: virtual void Open() override; virtual size_t ThreadRead(void *ptr, size_t size) override; diff --git a/src/pcm/PcmDop.cxx b/src/pcm/PcmDop.cxx index f4f1e6c8d..e8e5fad14 100644 --- a/src/pcm/PcmDop.cxx +++ b/src/pcm/PcmDop.cxx @@ -46,19 +46,20 @@ pcm_dsd_to_dop(PcmBuffer &buffer, unsigned channels, assert(audio_valid_channel_count(channels)); assert(_src.size % channels == 0); - const unsigned num_src_samples = _src.size; - const unsigned num_src_frames = num_src_samples / channels; + const size_t num_src_samples = _src.size; + const size_t num_src_frames = num_src_samples / channels; - /* this rounds down and discards the last odd frame; not + /* this rounds down and discards up to 3 odd frames; not elegant, but good enough for now */ - const unsigned num_frames = num_src_frames / 2; - const unsigned num_samples = num_frames * channels; + const size_t num_dop_quads = num_src_frames / 4; + const size_t num_frames = num_dop_quads * 2; + const size_t num_samples = num_frames * channels; uint32_t *const dest0 = (uint32_t *)buffer.GetT(num_samples), *dest = dest0; auto src = _src.data; - for (unsigned i = num_frames / 2; i > 0; --i) { + for (size_t i = num_dop_quads; i > 0; --i) { for (unsigned c = channels; c > 0; --c) { /* each 24 bit sample has 16 DSD sample bits plus the magic 0x05 marker */