From 1dc71f383ac9f6a259b3e78199236e4ba8fb8f40 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 7 Apr 2021 10:14:58 +0200 Subject: [PATCH 01/18] python/build/boost.py: touch boost/version.hpp to avoid reinstalling all the time --- python/build/boost.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/build/boost.py b/python/build/boost.py index 26cdfae4f..8d33ba775 100644 --- a/python/build/boost.py +++ b/python/build/boost.py @@ -21,3 +21,8 @@ class BoostProject(Project): dest = os.path.join(includedir, 'boost') shutil.rmtree(dest, ignore_errors=True) shutil.copytree(os.path.join(src, 'boost'), dest) + + # touch the boost/version.hpp file to ensure it's newer than + # the downloaded Boost tarball, to avoid reinstalling Boost on + # every run + os.utime(os.path.join(toolchain.install_prefix, self.installed)) From 650a30d7940fd395bc664558ead883a6ada918a7 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 15 Apr 2021 16:13:27 +0200 Subject: [PATCH 02/18] Revert "tag/Pool: use strncmp() without strlen() to compare strings" This reverts commit 1532983fb5755305a86fc37d2f35a7757d2bd66f. This optimization was bad because now all strings match if they are a prefix of another string, and this caused collisions in the tag string pool, corrupting the database. --- NEWS | 2 ++ src/tag/Pool.cxx | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 738904249..f72f15838 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ ver 0.22.7 (not yet released) - gme: support RSN files * storage - curl: don't use glibc extension +* database + - simple: fix database corruption bug * output - httpd: send header "Access-Control-Allow-Origin: *" - wasapi: add algorithm for finding usable audio format diff --git a/src/tag/Pool.cxx b/src/tag/Pool.cxx index e977c6784..e5a6d57f2 100644 --- a/src/tag/Pool.cxx +++ b/src/tag/Pool.cxx @@ -114,10 +114,7 @@ tag_pool_get_item(TagType type, StringView value) noexcept auto slot_p = tag_value_slot_p(type, value); for (auto slot = *slot_p; slot != nullptr; slot = slot->next) { if (slot->item.type == type && - /* strncmp() only works if there are no null - bytes, which FixTagString() has already ensured - at this point */ - strncmp(value.data, slot->item.value, value.size) == 0 && + value.Equals(slot->item.value) && slot->ref < TagPoolSlot::MAX_REF) { assert(slot->ref > 0); ++slot->ref; From b885f358a51d1ea6b126372a3d122b26c19dbe46 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 26 Apr 2021 21:33:51 +0200 Subject: [PATCH 03/18] output/control: add missing nullptr checks Fixes crash when pausing the default partition after an output was moved to another partition. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1147 --- NEWS | 1 + src/output/Control.cxx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index f72f15838..a9a846f70 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ ver 0.22.7 (not yet released) * database - simple: fix database corruption bug * output + - fix crash when pausing with multiple partitions - httpd: send header "Access-Control-Allow-Origin: *" - wasapi: add algorithm for finding usable audio format - wasapi: use default device only if none was configured diff --git a/src/output/Control.cxx b/src/output/Control.cxx index 6141710e4..625c6ff37 100644 --- a/src/output/Control.cxx +++ b/src/output/Control.cxx @@ -118,7 +118,7 @@ AudioOutputControl::GetLogName() const noexcept { assert(!IsDummy()); - return output->GetLogName(); + return output ? output->GetLogName() : name.c_str(); } Mixer * @@ -364,7 +364,7 @@ AudioOutputControl::LockPlay() noexcept void AudioOutputControl::LockPauseAsync() noexcept { - if (output->mixer != nullptr && !output->SupportsPause()) + if (output && output->mixer != nullptr && !output->SupportsPause()) /* the device has no pause mode: close the mixer, unless its "global" flag is set (checked by mixer_auto_close()) */ From 0f02bbc2fe4fa5e359dd3da7bb6fe9e87e96a98b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 7 Apr 2021 17:29:58 +0200 Subject: [PATCH 04/18] output/jack: enable on Windows This enables the JACK output plugin on Windows, but doesn't link against libjack64.dll, instead loads the DLL at runtime with LoadLibrary(). This kludge avoids the extremely fragile JACK shared memory protocol by using the system's libjack64.dll, without requiring the same DLL at build time. --- NEWS | 1 + doc/plugins.rst | 4 + python/build/jack.py | 47 ++++++ python/build/libs.py | 7 + src/lib/jack/Dynamic.hxx | 182 ++++++++++++++++++++++++ src/output/plugins/JackOutputPlugin.cxx | 8 ++ win32/build.py | 1 + 7 files changed, 250 insertions(+) create mode 100644 python/build/jack.py create mode 100644 src/lib/jack/Dynamic.hxx diff --git a/NEWS b/NEWS index a9a846f70..74e975f31 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ ver 0.22.7 (not yet released) - simple: fix database corruption bug * output - fix crash when pausing with multiple partitions + - jack: enable on Windows - httpd: send header "Access-Control-Allow-Origin: *" - wasapi: add algorithm for finding usable audio format - wasapi: use default device only if none was configured diff --git a/doc/plugins.rst b/doc/plugins.rst index 71b9ad004..3a4cf4b1a 100644 --- a/doc/plugins.rst +++ b/doc/plugins.rst @@ -910,6 +910,10 @@ jack The jack plugin connects to a `JACK server `_. +On Windows, this plugin loads :file:`libjack64.dll` at runtime. This +means you need to `download and install the JACK windows build +`_. + .. list-table:: :widths: 20 80 :header-rows: 1 diff --git a/python/build/jack.py b/python/build/jack.py new file mode 100644 index 000000000..6e71e7f1d --- /dev/null +++ b/python/build/jack.py @@ -0,0 +1,47 @@ +import os, shutil +import re + +from .project import Project + +# This class installs just the public headers and a fake pkg-config +# file which defines the macro "DYNAMIC_JACK". This tells MPD's JACK +# output plugin to load the libjack64.dll dynamically using +# LoadLibrary(). This kludge avoids the runtime DLL dependency for +# users who don't use JACK, but still allows using the system JACK +# client library. +# +# The problem with JACK is that it uses an extremely fragile shared +# memory protocol to communicate with the daemon. One needs to use +# daemon and client library from the same build. That's why we don't +# build libjack statically here; it would probably not be compatible +# with the user's JACK daemon. + +class JackProject(Project): + def __init__(self, url, md5, installed, + **kwargs): + m = re.match(r'.*/v([\d.]+)\.tar\.gz$', url) + self.version = m.group(1) + Project.__init__(self, url, md5, installed, + name='jack2', version=self.version, + base='jack2-' + self.version, + **kwargs) + + def build(self, toolchain): + src = self.unpack(toolchain) + + includes = ['jack.h', 'ringbuffer.h', 'systemdeps.h', 'transport.h', 'types.h', 'weakmacros.h'] + includedir = os.path.join(toolchain.install_prefix, 'include', 'jack') + os.makedirs(includedir, exist_ok=True) + + for i in includes: + shutil.copyfile(os.path.join(src, 'common', 'jack', i), + os.path.join(includedir, i)) + + with open(os.path.join(toolchain.install_prefix, 'lib', 'pkgconfig', 'jack.pc'), 'w') as f: + print("prefix=" + toolchain.install_prefix, file=f) + print("", file=f) + print("Name: jack", file=f) + print("Description: dummy", file=f) + print("Version: " + self.version, file=f) + print("Libs: ", file=f) + print("Cflags: -DDYNAMIC_JACK", file=f) diff --git a/python/build/libs.py b/python/build/libs.py index e5277856c..aa64db05c 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -9,6 +9,7 @@ from build.autotools import AutotoolsProject from build.ffmpeg import FfmpegProject from build.openssl import OpenSSLProject from build.boost import BoostProject +from build.jack import JackProject libmpdclient = MesonProject( 'https://www.musicpd.org/download/libmpdclient/2/libmpdclient-2.19.tar.xz', @@ -443,6 +444,12 @@ libnfs = AutotoolsProject( autoreconf=True, ) +jack = JackProject( + 'https://github.com/jackaudio/jack2/archive/v1.9.17.tar.gz', + '38f674bbc57852a8eb3d9faa1f96a0912d26f7d5df14c11005ad499c8ae352f2', + 'lib/pkgconfig/jack.pc', +) + boost = BoostProject( 'https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.bz2', '953db31e016db7bb207f11432bef7df100516eeb746843fa0486a222e3fd49cb', diff --git a/src/lib/jack/Dynamic.hxx b/src/lib/jack/Dynamic.hxx new file mode 100644 index 000000000..92d4d72c9 --- /dev/null +++ b/src/lib/jack/Dynamic.hxx @@ -0,0 +1,182 @@ +/* + * Copyright 2003-2021 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 "system/Error.hxx" + +/* sorry for this horrible piece of code - there's no elegant way to + load DLLs at runtime */ + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +using jack_set_error_function_t = std::add_pointer_t; +static jack_set_error_function_t _jack_set_error_function; + +using jack_set_info_function_t = std::add_pointer_t; +static jack_set_info_function_t _jack_set_info_function; + +using jack_client_open_t = std::add_pointer_t; +static jack_client_open_t _jack_client_open; + +using jack_client_close_t = std::add_pointer_t; +static jack_client_close_t _jack_client_close; + +using jack_connect_t = std::add_pointer_t; +static jack_connect_t _jack_connect; + +using jack_activate_t = std::add_pointer_t; +static jack_activate_t _jack_activate; + +using jack_deactivate_t = std::add_pointer_t; +static jack_deactivate_t _jack_deactivate; + +using jack_get_sample_rate_t = std::add_pointer_t; +static jack_get_sample_rate_t _jack_get_sample_rate; + +using jack_set_process_callback_t = std::add_pointer_t; +static jack_set_process_callback_t _jack_set_process_callback; + +using jack_on_info_shutdown_t = std::add_pointer_t; +static jack_on_info_shutdown_t _jack_on_info_shutdown; + +using jack_free_t = std::add_pointer_t; +static jack_free_t _jack_free; + +using jack_get_ports_t = std::add_pointer_t; +static jack_get_ports_t _jack_get_ports; + +using jack_port_register_t = std::add_pointer_t; +static jack_port_register_t _jack_port_register; + +using jack_port_name_t = std::add_pointer_t; +static jack_port_name_t _jack_port_name; + +using jack_port_get_buffer_t = std::add_pointer_t; +static jack_port_get_buffer_t _jack_port_get_buffer; + +using jack_ringbuffer_create_t = std::add_pointer_t; +static jack_ringbuffer_create_t _jack_ringbuffer_create; + +using jack_ringbuffer_free_t = std::add_pointer_t; +static jack_ringbuffer_free_t _jack_ringbuffer_free; + +using jack_ringbuffer_get_write_vector_t = std::add_pointer_t; +static jack_ringbuffer_get_write_vector_t _jack_ringbuffer_get_write_vector; + +using jack_ringbuffer_write_advance_t = std::add_pointer_t; +static jack_ringbuffer_write_advance_t _jack_ringbuffer_write_advance; + +using jack_ringbuffer_read_space_t = std::add_pointer_t; +static jack_ringbuffer_read_space_t _jack_ringbuffer_read_space; + +using jack_ringbuffer_read_t = std::add_pointer_t; +static jack_ringbuffer_read_t _jack_ringbuffer_read; + +using jack_ringbuffer_read_advance_t = std::add_pointer_t; +static jack_ringbuffer_read_advance_t _jack_ringbuffer_read_advance; + +using jack_ringbuffer_reset_t = std::add_pointer_t; +static jack_ringbuffer_reset_t _jack_ringbuffer_reset; + +template +static void +GetFunction(HMODULE h, const char *name, T &result) +{ + auto f = GetProcAddress(h, name); + if (f == nullptr) + throw FormatRuntimeError("No such libjack function: %s", name); + + result = reinterpret_cast(f); +} + +static void +LoadJackLibrary() +{ +#ifdef _WIN64 +#define LIBJACK "libjack64" +#else +#define LIBJACK "libjack" +#endif + + auto libjack = LoadLibraryA(LIBJACK); + if (!libjack) + throw FormatLastError("Failed to load " LIBJACK ".dll"); + + GetFunction(libjack, "jack_set_error_function", _jack_set_error_function); + GetFunction(libjack, "jack_set_info_function", _jack_set_info_function); + + GetFunction(libjack, "jack_client_open", _jack_client_open); + GetFunction(libjack, "jack_client_close", _jack_client_close); + GetFunction(libjack, "jack_connect", _jack_connect); + GetFunction(libjack, "jack_activate", _jack_activate); + GetFunction(libjack, "jack_deactivate", _jack_deactivate); + GetFunction(libjack, "jack_free", _jack_free); + + GetFunction(libjack, "jack_get_sample_rate", _jack_get_sample_rate); + GetFunction(libjack, "jack_set_process_callback", _jack_set_process_callback); + GetFunction(libjack, "jack_on_info_shutdown", _jack_on_info_shutdown); + + GetFunction(libjack, "jack_get_ports", _jack_get_ports); + GetFunction(libjack, "jack_port_register", _jack_port_register); + GetFunction(libjack, "jack_port_name", _jack_port_name); + GetFunction(libjack, "jack_port_get_buffer", _jack_port_get_buffer); + + GetFunction(libjack, "jack_ringbuffer_create", _jack_ringbuffer_create); + GetFunction(libjack, "jack_ringbuffer_free", _jack_ringbuffer_free); + GetFunction(libjack, "jack_ringbuffer_get_write_vector", _jack_ringbuffer_get_write_vector); + GetFunction(libjack, "jack_ringbuffer_write_advance", _jack_ringbuffer_write_advance); + GetFunction(libjack, "jack_ringbuffer_read_space", _jack_ringbuffer_read_space); + GetFunction(libjack, "jack_ringbuffer_read", _jack_ringbuffer_read); + GetFunction(libjack, "jack_ringbuffer_read_advance", _jack_ringbuffer_read_advance); + GetFunction(libjack, "jack_ringbuffer_reset", _jack_ringbuffer_reset); +} + +#define jack_set_error_function _jack_set_error_function +#define jack_set_info_function _jack_set_info_function + +#define jack_client_open _jack_client_open +#define jack_client_close _jack_client_close +#define jack_connect _jack_connect +#define jack_activate _jack_activate +#define jack_deactivate _jack_deactivate +#define jack_free _jack_free + +#define jack_get_sample_rate _jack_get_sample_rate +#define jack_set_process_callback _jack_set_process_callback +#define jack_on_info_shutdown _jack_on_info_shutdown + +#define jack_get_ports _jack_get_ports +#define jack_port_register _jack_port_register +#define jack_port_name _jack_port_name +#define jack_port_get_buffer _jack_port_get_buffer + +#define jack_ringbuffer_create _jack_ringbuffer_create +#define jack_ringbuffer_free _jack_ringbuffer_free +#define jack_ringbuffer_get_write_vector _jack_ringbuffer_get_write_vector +#define jack_ringbuffer_write_advance _jack_ringbuffer_write_advance +#define jack_ringbuffer_read_space _jack_ringbuffer_read_space +#define jack_ringbuffer_read _jack_ringbuffer_read +#define jack_ringbuffer_read_advance _jack_ringbuffer_read_advance +#define jack_ringbuffer_reset _jack_ringbuffer_reset + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx index 5f58f93f1..b0cb910d6 100644 --- a/src/output/plugins/JackOutputPlugin.cxx +++ b/src/output/plugins/JackOutputPlugin.cxx @@ -44,6 +44,10 @@ static constexpr unsigned MAX_PORTS = 16; static constexpr size_t jack_sample_size = sizeof(jack_default_audio_sample_t); +#ifdef DYNAMIC_JACK +#include "lib/jack/Dynamic.hxx" +#endif // _WIN32 + class JackOutput final : public AudioOutput { /** * libjack options passed to jack_client_open(). @@ -463,6 +467,10 @@ JackOutput::Disable() noexcept static AudioOutput * mpd_jack_init(EventLoop &, const ConfigBlock &block) { +#ifdef DYNAMIC_JACK + LoadJackLibrary(); +#endif + jack_set_error_function(mpd_jack_error); #ifdef HAVE_JACK_SET_INFO_FUNCTION diff --git a/win32/build.py b/win32/build.py index 8aa87e288..9f3011831 100755 --- a/win32/build.py +++ b/win32/build.py @@ -108,6 +108,7 @@ thirdparty_libs = [ curl, libexpat, libnfs, + jack, boost, ] From c1429500b24af7f3e89f48637f54d4e29daec108 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 26 Apr 2021 22:21:12 +0200 Subject: [PATCH 05/18] test/test_pcm_format: work around -Wdouble-promotion --- test/test_pcm_format.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pcm_format.cxx b/test/test_pcm_format.cxx index 1c448294f..e28faa7cb 100644 --- a/test/test_pcm_format.cxx +++ b/test/test_pcm_format.cxx @@ -79,8 +79,8 @@ TEST(PcmTest, FormatFloat16) EXPECT_EQ(N, f.size); for (size_t i = 0; i != f.size; ++i) { - EXPECT_GE(f[i], -1.); - EXPECT_LE(f[i], 1.); + EXPECT_GE(f[i], -1.f); + EXPECT_LE(f[i], 1.f); } PcmDither dither; From a71b76bb3c6b1a08a90370ae67e8b93bc53dfd47 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 26 Apr 2021 23:25:36 +0200 Subject: [PATCH 06/18] test/test_pcm_format: another workaround for -Wdouble-promotion --- test/test_pcm_format.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_pcm_format.cxx b/test/test_pcm_format.cxx index e28faa7cb..4ecd19270 100644 --- a/test/test_pcm_format.cxx +++ b/test/test_pcm_format.cxx @@ -125,8 +125,8 @@ TEST(PcmTest, FormatFloat32) EXPECT_EQ(N, f.size); for (size_t i = 0; i != f.size; ++i) { - EXPECT_GE(f[i], -1.); - EXPECT_LE(f[i], 1.); + EXPECT_GE(f[i], -1.f); + EXPECT_LE(f[i], 1.f); } auto d = pcm_convert_to_32(buffer2, From d6bf6e161ab4212cfce7178e9e0b181f13490e8a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 27 Apr 2021 15:48:18 +0200 Subject: [PATCH 07/18] .travis.yml: remove obsolete comment --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f6b7419f8..ce0adf046 100644 --- a/.travis.yml +++ b/.travis.yml @@ -134,8 +134,6 @@ before_install: - eval "${MATRIX_EVAL}" install: - # C++14 - # Work around "Target /usr/local/lib/libgtest.a is a symlink # belonging to nss. You can unlink it" during gtest install - test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss From 5452428d6986d55d271689e5903bf0fe0da33261 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 27 Apr 2021 15:57:22 +0200 Subject: [PATCH 08/18] .travis.yml: switch to ppa:ricotz/toolchain for ninja 1.8 on Ubuntu Trusty The old "ppa:mstipicevic/ninja-build-1-7-2" just provides ninja 1.7 which is too old and breaks the build. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ce0adf046..55c0a6f75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -75,7 +75,7 @@ jobs: sources: - ubuntu-toolchain-r-test - sourceline: 'ppa:mhier/libboost-latest' - - sourceline: 'ppa:mstipicevic/ninja-build-1-7-2' + - sourceline: 'ppa:ricotz/toolchain' - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) packages: - g++-8 From 3c1988b68f0c0e4b82dac40f69f71e5b07a84c2d Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 27 Apr 2021 16:08:36 +0200 Subject: [PATCH 09/18] .travis.yml: switch from Ubuntu Bionic to Ubuntu Focal (20.04) --- .travis.yml | 51 +++++++++------------------------------------------ 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55c0a6f75..56b78b425 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,70 +2,37 @@ language: cpp jobs: include: - # Ubuntu Bionic (18.04) with GCC 7 + # Ubuntu Focal (20.04) with GCC 9.3 - os: linux - dist: bionic + dist: focal addons: apt: - sources: - - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) packages: + - meson - libgtest-dev - libboost-dev - - python3.6 - - python3-urllib3 - - ninja-build - before_install: - - wget https://bootstrap.pypa.io/get-pip.py - - /usr/bin/python3.6 get-pip.py --user --no-cache-dir - install: - - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir - env: - - MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH" - # Ubuntu Bionic (18.04) with GCC 7 on big-endian + # Ubuntu Focal (20.04) with GCC 9.3 on big-endian - os: linux arch: s390x - dist: bionic + dist: focal addons: apt: - sources: - - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) packages: + - meson - libgtest-dev - libboost-dev - - python3.6 - - python3-urllib3 - - ninja-build - before_install: - - wget https://bootstrap.pypa.io/get-pip.py - - /usr/bin/python3.6 get-pip.py --user --no-cache-dir - install: - - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir - env: - - MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH" - # Ubuntu Bionic (18.04) with GCC 7 on ARM64 + # Ubuntu Focal (20.04) with GCC 9.3 on ARM64 - os: linux arch: arm64 - dist: bionic + dist: focal addons: apt: - sources: - - sourceline: 'ppa:deadsnakes/ppa' # for Python 3.7 (required by Meson) packages: + - meson - libgtest-dev - libboost-dev - - python3.6 - - python3-urllib3 - - ninja-build - before_install: - - wget https://bootstrap.pypa.io/get-pip.py - - /usr/bin/python3.6 get-pip.py --user --no-cache-dir - install: - - /usr/bin/python3.6 $HOME/.local/bin/pip install --user meson --no-cache-dir - env: - - MATRIX_EVAL="export PATH=\$HOME/.local/bin:\$PATH" # Ubuntu Trusty (16.04) with GCC 8 - os: linux From 018858ec975702d3fce20b9e6c48545b7f846a92 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 27 Apr 2021 15:47:23 +0200 Subject: [PATCH 10/18] .travis.yml: install standard Homebrew GTest formula --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56b78b425..6aec3a788 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,6 +67,7 @@ jobs: packages: - ccache - meson + - googletest - icu4c - ffmpeg - libnfs @@ -101,11 +102,6 @@ before_install: - eval "${MATRIX_EVAL}" install: - # Work around "Target /usr/local/lib/libgtest.a is a symlink - # belonging to nss. You can unlink it" during gtest install - - test "$TRAVIS_OS_NAME" != "osx" || brew unlink nss - - - test "$TRAVIS_OS_NAME" != "osx" || brew install https://gist.githubusercontent.com/Kronuz/96ac10fbd8472eb1e7566d740c4034f8/raw/gtest.rb before_script: - ccache -s From 8c51440057a52436322f7ba538d88b18f73490c8 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 28 Apr 2021 09:15:06 +0200 Subject: [PATCH 11/18] test/test_mixramp: workaround for -Wdouble-promotion --- test/test_mixramp.cxx | 16 ++++++++-------- test/test_pcm_volume.cxx | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/test_mixramp.cxx b/test/test_mixramp.cxx index ca010f246..6f32fec04 100644 --- a/test/test_mixramp.cxx +++ b/test/test_mixramp.cxx @@ -13,25 +13,25 @@ TEST(MixRamp, Interpolate) const char *input = "1.0 0.00;3.0 0.10;6.0 2.50;"; char *foo = strdup(input); - EXPECT_NEAR(double(0), + EXPECT_NEAR(0., mixramp_interpolate(foo, 0).count(), 0.05); free(foo); foo = strdup(input); - EXPECT_NEAR(float(0), + EXPECT_NEAR(0., mixramp_interpolate(foo, 1).count(), 0.005); free(foo); foo = strdup(input); - EXPECT_NEAR(float(0.1), + EXPECT_NEAR(0.1, mixramp_interpolate(foo, 3).count(), 0.005); free(foo); foo = strdup(input); - EXPECT_NEAR(float(2.5), + EXPECT_NEAR(2.5, mixramp_interpolate(foo, 6).count(), 0.01); free(foo); @@ -41,25 +41,25 @@ TEST(MixRamp, Interpolate) free(foo); foo = strdup(input); - EXPECT_NEAR(float(0.05), + EXPECT_NEAR(0.05, mixramp_interpolate(foo, 2).count(), 0.05); free(foo); foo = strdup(input); - EXPECT_NEAR(float(1.3), + EXPECT_NEAR(1.3, mixramp_interpolate(foo, 4.5).count(), 0.05); free(foo); foo = strdup(input); - EXPECT_NEAR(float(0.9), + EXPECT_NEAR(0.9, mixramp_interpolate(foo, 4).count(), 0.05); free(foo); foo = strdup(input); - EXPECT_NEAR(float(1.7), + EXPECT_NEAR(1.7, mixramp_interpolate(foo, 5).count(), 0.05); free(foo); diff --git a/test/test_pcm_volume.cxx b/test/test_pcm_volume.cxx index f8b3fec59..11ea75303 100644 --- a/test/test_pcm_volume.cxx +++ b/test/test_pcm_volume.cxx @@ -154,7 +154,7 @@ TEST(PcmTest, VolumeFloat) const auto _dest = ConstBuffer::FromVoid(dest); for (unsigned i = 0; i < N; ++i) - EXPECT_NEAR(_src[i] / 2, _dest[i], 1); + EXPECT_NEAR((double)_src[i] / 2., (double)_dest[i], 1.); pv.Close(); } From bfed47b82dff70f65fbd8fff3d38ede682810338 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 27 Apr 2021 17:19:19 +0200 Subject: [PATCH 12/18] .travis.yml: switch the OSX build to xcode11.6 The clang/libc++ version in xcode10.3 does not support C++17 properly and cannot build MPD. --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6aec3a788..40c7afcca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,7 +61,7 @@ jobs: - MATRIX_EVAL="export CC='ccache gcc-8' CXX='ccache g++-8' LDFLAGS=-fuse-ld=gold PATH=\$HOME/.local/bin:\$PATH" - os: osx - osx_image: xcode10.3 + osx_image: xcode11.6 addons: homebrew: packages: @@ -85,7 +85,6 @@ jobs: - faad2 - wavpack - libmpdclient - update: true env: - MATRIX_EVAL="export PATH=/usr/local/opt/ccache/libexec:$PATH HOMEBREW_NO_ANALYTICS=1" From 514ed33a029bd5c361b00b18b5a568544c5795d8 Mon Sep 17 00:00:00 2001 From: skidoo23 Date: Mon, 3 May 2021 18:20:22 +0200 Subject: [PATCH 13/18] python/build: update Boost URL and version --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index aa64db05c..3c78bebc2 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -451,7 +451,7 @@ jack = JackProject( ) boost = BoostProject( - 'https://dl.bintray.com/boostorg/release/1.75.0/source/boost_1_75_0.tar.bz2', - '953db31e016db7bb207f11432bef7df100516eeb746843fa0486a222e3fd49cb', + 'https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.bz2', + 'f0397ba6e982c4450f27bf32a2a83292aba035b827a5623a14636ea583318c41', 'include/boost/version.hpp', ) From 1215818572b6062c4ec709ba818954d49fbd9311 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 May 2021 18:32:20 +0200 Subject: [PATCH 14/18] doc/meson.build: remove "upload" target Since we migrated to readthedocs.io, we don't need this target anymore. And Meson 0.58.0 apparently has a change breaking this target. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1161 --- doc/meson.build | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/doc/meson.build b/doc/meson.build index a67686483..af09b19fd 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -22,20 +22,6 @@ if get_option('html_manual') install: true, install_dir: join_paths(get_option('datadir'), 'doc', meson.project_name()), ) - - custom_target( - 'upload', - input: sphinx_output, - output: 'upload', - build_always_stale: true, - command: [ - 'rsync', '-vpruz', '--delete', meson.current_build_dir() + '/', - 'www.musicpd.org:/var/www/mpd/doc/', - '--chmod=Dug+rwx,Do+rx,Fug+rw,Fo+r', - '--include=html', '--include=html/**', - '--exclude=*', - ], - ) endif if get_option('manpages') From 6f51d910eeef161b9e1a09406cf7e219341d8161 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 May 2021 18:37:38 +0200 Subject: [PATCH 15/18] python/build/libs.py: update CURL to 7.76.1 --- python/build/libs.py | 4 ++-- src/lib/curl/patches/no_netrc.patch | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index 3c78bebc2..56e3a29c4 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -385,8 +385,8 @@ openssl = OpenSSLProject( ) curl = AutotoolsProject( - 'http://curl.haxx.se/download/curl-7.74.0.tar.xz', - '999d5f2c403cf6e25d58319fdd596611e455dd195208746bc6e6d197a77e878b', + 'https://curl.se/download/curl-7.76.1.tar.xz', + '64bb5288c39f0840c07d077e30d9052e1cbb9fa6c2dc52523824cc859e679145', 'lib/libcurl.a', [ '--disable-shared', '--enable-static', diff --git a/src/lib/curl/patches/no_netrc.patch b/src/lib/curl/patches/no_netrc.patch index 9746f1435..c825ea36a 100644 --- a/src/lib/curl/patches/no_netrc.patch +++ b/src/lib/curl/patches/no_netrc.patch @@ -1,19 +1,20 @@ -diff -ur curl-7.63.0.orig/lib/url.c curl-7.63.0/lib/url.c ---- curl-7.63.0.orig/lib/url.c 2019-01-21 10:15:51.368019445 +0100 -+++ curl-7.63.0/lib/url.c 2019-01-21 10:19:16.307523984 +0100 -@@ -3057,6 +3057,7 @@ +Index: curl-7.71.1/lib/url.c +=================================================================== +--- curl-7.71.1.orig/lib/url.c ++++ curl-7.71.1/lib/url.c +@@ -2871,6 +2871,7 @@ } conn->bits.netrc = FALSE; +#ifndef __BIONIC__ - if(data->set.use_netrc != CURL_NETRC_IGNORED && - (!*userp || !**userp || !*passwdp || !**passwdp)) { + if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) { bool netrc_user_changed = FALSE; -@@ -3090,6 +3091,7 @@ - } + bool netrc_passwd_changed = FALSE; +@@ -2895,6 +2896,7 @@ + conn->bits.user_passwd = TRUE; /* enable user+password */ } } +#endif /* for updated strings, we update them in the URL */ - if(user_changed) { + if(*userp) { From 365b798f330aa5dd7680844bd94980943801f926 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 May 2021 18:39:25 +0200 Subject: [PATCH 16/18] python/build/libs.py: update FFmpeg to 4.4 --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index 56e3a29c4..a4e3a8f1b 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -150,8 +150,8 @@ gme = CmakeProject( ) ffmpeg = FfmpegProject( - 'http://ffmpeg.org/releases/ffmpeg-4.3.1.tar.xz', - 'ad009240d46e307b4e03a213a0f49c11b650e445b1f8be0dda2a9212b34d2ffb', + 'http://ffmpeg.org/releases/ffmpeg-4.4.tar.xz', + '06b10a183ce5371f915c6bb15b7b1fffbe046e8275099c96affc29e17645d909', 'lib/libavcodec.a', [ '--disable-shared', '--enable-static', From 7c09e44ad46b65765a0d63627ea203fca68825ff Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 May 2021 18:39:46 +0200 Subject: [PATCH 17/18] python/build/libs.py: update OpenSSL to 3.0.0-alpha16 --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index a4e3a8f1b..d3e50ab09 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -379,8 +379,8 @@ ffmpeg = FfmpegProject( ) openssl = OpenSSLProject( - 'https://www.openssl.org/source/openssl-3.0.0-alpha10.tar.gz', - 'b1699acf2148db31f12edf5ebfdf12a92bfd3f0e60538d169710408a3cd3b138', + 'https://www.openssl.org/source/openssl-3.0.0-alpha16.tar.gz', + '08ce8244b59d75f40f91170dfcb012bf25309cdcb1fef9502e39d694f883d1d1', 'include/openssl/ossl_typ.h', ) From 638dfc398184ff0d71c2a81c8c3eb99f649ac307 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 17 May 2021 19:24:12 +0200 Subject: [PATCH 18/18] {input,storage}/curl: set CURLOPT_HTTPAUTH=CURLAUTH_BASIC With the default value CURLAUTH_ANY, libcurl needs to probe for authentication methods first, and only the second request will have an Authorization header. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1155 --- NEWS | 2 ++ src/input/plugins/CurlInputPlugin.cxx | 4 ++++ src/storage/plugins/CurlStorage.cxx | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 74e975f31..b0f393f57 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ ver 0.22.7 (not yet released) * protocol - don't use glibc extension to parse time stamps +* input + - curl: send user/password in the first request, save one roundtrip * decoder - ffmpeg: fix build problem with FFmpeg 3.4 - gme: support RSN files diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 86647f550..b3b6a9652 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -421,6 +421,10 @@ CurlInputStream::InitEasy() request->SetOption(CURLOPT_MAXREDIRS, 5L); request->SetOption(CURLOPT_FAILONERROR, 1L); + /* this option eliminates the probe request when + username/password are specified */ + request->SetOption(CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + if (proxy != nullptr) request->SetOption(CURLOPT_PROXY, proxy); diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx index 731f7e7b9..80c4dcdf3 100644 --- a/src/storage/plugins/CurlStorage.cxx +++ b/src/storage/plugins/CurlStorage.cxx @@ -262,6 +262,10 @@ public: request.SetOption(CURLOPT_FOLLOWLOCATION, 1L); request.SetOption(CURLOPT_MAXREDIRS, 1L); + /* this option eliminates the probe request when + username/password are specified */ + request.SetOption(CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + request_headers.Append(StringFormat<40>("depth: %u", depth)); request_headers.Append("content-type: text/xml");