Commit 0309db33 authored by Florian Schlichting's avatar Florian Schlichting

New upstream version 0.20.19

parent 3dc04775
...@@ -31,3 +31,8 @@ The following people have contributed code to MPD: ...@@ -31,3 +31,8 @@ The following people have contributed code to MPD:
Jean-Francois Dockes <jf@dockes.org> Jean-Francois Dockes <jf@dockes.org>
Yue Wang <yuleopen@gmail.com> Yue Wang <yuleopen@gmail.com>
Matthew Leon Grinshpun <ml@matthewleon.com> Matthew Leon Grinshpun <ml@matthewleon.com>
Dimitris Papastamos <sin@2f30.org>
Florian Schlichting <fsfs@debian.org>
François Revol <revol@free.fr>
Jacob Vosmaer <contact@jacobvosmaer.nl>
Thomas Guillem <thomas@gllm.fr>
...@@ -15615,8 +15615,8 @@ maintainer-clean-generic: ...@@ -15615,8 +15615,8 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild." @echo "it deletes files that may require special tools to rebuild."
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
@ENABLE_DOCUMENTATION_FALSE@install-data-local: @ENABLE_DOCUMENTATION_FALSE@install-data-local:
@ANDROID_FALSE@@ENABLE_DOCUMENTATION_FALSE@@ENABLE_HAIKU_FALSE@clean-local:
@ENABLE_DOCUMENTATION_FALSE@uninstall-local: @ENABLE_DOCUMENTATION_FALSE@uninstall-local:
@ANDROID_FALSE@@ENABLE_DOCUMENTATION_FALSE@@ENABLE_HAIKU_FALSE@clean-local:
clean: clean-am clean: clean-am
clean-am: clean-binPROGRAMS clean-generic clean-local \ clean-am: clean-binPROGRAMS clean-generic clean-local \
ver 0.20.19 (2018/04/26)
* protocol
- validate absolute seek time, reject negative values
* database
- proxy: fix "search already in progress" errors
- proxy: implement "list ... group"
* input
- mms: fix lockup bug and a crash bug
* decoder
- ffmpeg: fix av_register_all() deprecation warning (FFmpeg 4.0)
* player
- fix spurious "Not seekable" error when switching radio streams
* macOS: fix crash bug
ver 0.20.18 (2018/02/24) ver 0.20.18 (2018/02/24)
* input * input
- curl: allow authentication methods other than "Basic" - curl: allow authentication methods other than "Basic"
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd" package="org.musicpd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="17" android:versionCode="18"
android:versionName="0.20.18"> android:versionName="0.20.19">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/>
......
...@@ -3,13 +3,14 @@ ...@@ -3,13 +3,14 @@
import os, os.path import os, os.path
import sys, subprocess import sys, subprocess
if len(sys.argv) < 3: if len(sys.argv) < 4:
print("Usage: build.py SDK_PATH NDK_PATH [configure_args...]", file=sys.stderr) print("Usage: build.py SDK_PATH NDK_PATH ABI [configure_args...]", file=sys.stderr)
sys.exit(1) sys.exit(1)
sdk_path = sys.argv[1] sdk_path = sys.argv[1]
ndk_path = sys.argv[2] ndk_path = sys.argv[2]
configure_args = sys.argv[3:] android_abi = sys.argv[3]
configure_args = sys.argv[4:]
if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')): if not os.path.isfile(os.path.join(sdk_path, 'tools', 'android')):
print("SDK not found in", ndk_path, file=sys.stderr) print("SDK not found in", ndk_path, file=sys.stderr)
...@@ -19,8 +20,27 @@ if not os.path.isdir(ndk_path): ...@@ -19,8 +20,27 @@ if not os.path.isdir(ndk_path):
print("NDK not found in", ndk_path, file=sys.stderr) print("NDK not found in", ndk_path, file=sys.stderr)
sys.exit(1) sys.exit(1)
android_abis = {
'armeabi-v7a': {
'arch': 'arm-linux-androideabi',
'ndk_arch': 'arm',
'toolchain_arch': 'arm-linux-androideabi',
'llvm_triple': 'armv7-none-linux-androideabi',
'cflags': '-march=armv7-a -mfpu=vfp -mfloat-abi=softfp',
},
'x86': {
'arch': 'i686-linux-android',
'ndk_arch': 'x86',
'toolchain_arch': 'x86',
'llvm_triple': 'i686-none-linux-android',
'cflags': '-march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
},
}
# select the NDK target # select the NDK target
arch = 'arm-linux-androideabi' abi_info = android_abis[android_abi]
arch = abi_info['arch']
# the path to the MPD sources # the path to the MPD sources
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..')) mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
...@@ -44,8 +64,7 @@ class AndroidNdkToolchain: ...@@ -44,8 +64,7 @@ class AndroidNdkToolchain:
self.src_path = src_path self.src_path = src_path
self.build_path = build_path self.build_path = build_path
self.ndk_arch = 'arm' ndk_arch = abi_info['ndk_arch']
android_abi = 'armeabi-v7a'
ndk_platform = 'android-14' ndk_platform = 'android-14'
# select the NDK compiler # select the NDK compiler
...@@ -53,7 +72,7 @@ class AndroidNdkToolchain: ...@@ -53,7 +72,7 @@ class AndroidNdkToolchain:
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform) ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
sysroot = os.path.join(ndk_path, 'sysroot') sysroot = os.path.join(ndk_path, 'sysroot')
target_root = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch) target_root = os.path.join(ndk_platform_path, 'arch-' + ndk_arch)
install_prefix = os.path.join(arch_path, 'root') install_prefix = os.path.join(arch_path, 'root')
...@@ -61,13 +80,13 @@ class AndroidNdkToolchain: ...@@ -61,13 +80,13 @@ class AndroidNdkToolchain:
self.install_prefix = install_prefix self.install_prefix = install_prefix
self.sysroot = sysroot self.sysroot = sysroot
toolchain_path = os.path.join(ndk_path, 'toolchains', arch + '-' + gcc_version, 'prebuilt', build_arch) toolchain_path = os.path.join(ndk_path, 'toolchains', abi_info['toolchain_arch'] + '-' + gcc_version, 'prebuilt', build_arch)
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch) llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
llvm_triple = 'armv7-none-linux-androideabi' llvm_triple = abi_info['llvm_triple']
common_flags = '-Os -g' common_flags = '-Os -g'
common_flags += ' -fPIC' common_flags += ' -fPIC'
common_flags += ' -march=armv7-a -mfpu=vfp -mfloat-abi=softfp' common_flags += ' ' + abi_info['cflags']
toolchain_bin = os.path.join(toolchain_path, 'bin') toolchain_bin = os.path.join(toolchain_path, 'bin')
llvm_bin = os.path.join(llvm_path, 'bin') llvm_bin = os.path.join(llvm_path, 'bin')
...@@ -95,7 +114,7 @@ class AndroidNdkToolchain: ...@@ -95,7 +114,7 @@ class AndroidNdkToolchain:
' ' + common_flags ' ' + common_flags
self.libs = '' self.libs = ''
self.is_arm = self.ndk_arch == 'arm' self.is_arm = ndk_arch == 'arm'
self.is_armv7 = self.is_arm and 'armv7' in self.cflags self.is_armv7 = self.is_arm and 'armv7' in self.cflags
self.is_windows = False self.is_windows = False
......
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mpd 0.20.18. # Generated by GNU Autoconf 2.69 for mpd 0.20.19.
# #
# Report bugs to <musicpd-dev-team@lists.sourceforge.net>. # Report bugs to <musicpd-dev-team@lists.sourceforge.net>.
# #
...@@ -580,8 +580,8 @@ MAKEFLAGS= ...@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='mpd' PACKAGE_NAME='mpd'
PACKAGE_TARNAME='mpd' PACKAGE_TARNAME='mpd'
PACKAGE_VERSION='0.20.18' PACKAGE_VERSION='0.20.19'
PACKAGE_STRING='mpd 0.20.18' PACKAGE_STRING='mpd 0.20.19'
PACKAGE_BUGREPORT='musicpd-dev-team@lists.sourceforge.net' PACKAGE_BUGREPORT='musicpd-dev-team@lists.sourceforge.net'
PACKAGE_URL='' PACKAGE_URL=''
...@@ -1785,7 +1785,7 @@ if test "$ac_init_help" = "long"; then ...@@ -1785,7 +1785,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures mpd 0.20.18 to adapt to many kinds of systems. \`configure' configures mpd 0.20.19 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
...@@ -1856,7 +1856,7 @@ fi ...@@ -1856,7 +1856,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of mpd 0.20.18:";; short | recursive ) echo "Configuration of mpd 0.20.19:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
...@@ -2209,7 +2209,7 @@ fi ...@@ -2209,7 +2209,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
mpd configure 0.20.18 mpd configure 0.20.19
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
...@@ -2616,7 +2616,7 @@ cat >config.log <<_ACEOF ...@@ -2616,7 +2616,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by mpd $as_me 0.20.18, which was It was created by mpd $as_me 0.20.19, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
...@@ -2967,7 +2967,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ...@@ -2967,7 +2967,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=20 VERSION_MINOR=20
VERSION_REVISION=18 VERSION_REVISION=19
VERSION_EXTRA=0 VERSION_EXTRA=0
...@@ -3486,7 +3486,7 @@ fi ...@@ -3486,7 +3486,7 @@ fi
# Define the identity of the package. # Define the identity of the package.
PACKAGE='mpd' PACKAGE='mpd'
VERSION='0.20.18' VERSION='0.20.19'
cat >>confdefs.h <<_ACEOF cat >>confdefs.h <<_ACEOF
...@@ -9216,7 +9216,7 @@ fi ...@@ -9216,7 +9216,7 @@ fi
if test "x$want_boost" = "xyes"; then if test "x$want_boost" = "xyes"; then
boost_lib_version_req=1.46 boost_lib_version_req=1.54
boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([0-9]*\.[0-9]*\)'` boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([0-9]*\.[0-9]*\)'`
boost_lib_version_req_major=`expr $boost_lib_version_req : '\([0-9]*\)'` boost_lib_version_req_major=`expr $boost_lib_version_req : '\([0-9]*\)'`
boost_lib_version_req_minor=`expr $boost_lib_version_req : '[0-9]*\.\([0-9]*\)'` boost_lib_version_req_minor=`expr $boost_lib_version_req : '[0-9]*\.\([0-9]*\)'`
...@@ -21779,7 +21779,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ...@@ -21779,7 +21779,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by mpd $as_me 0.20.18, which was This file was extended by mpd $as_me 0.20.19, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
...@@ -21845,7 +21845,7 @@ _ACEOF ...@@ -21845,7 +21845,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
mpd config.status 0.20.18 mpd config.status 0.20.19
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"
......
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(mpd, 0.20.18, musicpd-dev-team@lists.sourceforge.net) AC_INIT(mpd, 0.20.19, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=20 VERSION_MINOR=20
VERSION_REVISION=18 VERSION_REVISION=19
VERSION_EXTRA=0 VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx]) AC_CONFIG_SRCDIR([src/Main.cxx])
...@@ -454,7 +454,7 @@ dnl --------------------------------------------------------------------------- ...@@ -454,7 +454,7 @@ dnl ---------------------------------------------------------------------------
dnl Mandatory Libraries dnl Mandatory Libraries
dnl --------------------------------------------------------------------------- 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, AC_ARG_ENABLE(icu,
AS_HELP_STRING([--enable-icu], AS_HELP_STRING([--enable-icu],
......
...@@ -38,7 +38,7 @@ PROJECT_NAME = MPD ...@@ -38,7 +38,7 @@ PROJECT_NAME = MPD
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 0.20.18 PROJECT_NUMBER = 0.20.19
# Using the PROJECT_BRIEF tag one can provide an optional one line description # Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a # for a project that appears at the top of each page and should give viewer a
......
...@@ -79,7 +79,10 @@ ...@@ -79,7 +79,10 @@
<para> <para>
If you need to tweak the configuration, you can create a file If you need to tweak the configuration, you can create a file
called <filename>mpd.conf</filename> on the data partition. called <filename>mpd.conf</filename> on the data partition
(the directory which is returned by Android's <ulink
url="https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()">getExternalStorageDirectory()</ulink>
API function).
</para> </para>
</section> </section>
...@@ -111,7 +114,7 @@ cd mpd-version</programlisting> ...@@ -111,7 +114,7 @@ cd mpd-version</programlisting>
<listitem> <listitem>
<para> <para>
<ulink url="http://www.boost.org/">Boost 1.46</ulink> <ulink url="http://www.boost.org/">Boost 1.54</ulink>
</para> </para>
</listitem> </listitem>
...@@ -265,6 +268,59 @@ apt-get install g++ \ ...@@ -265,6 +268,59 @@ apt-get install g++ \
script. script.
</para> </para>
</section> </section>
<section id="android_build">
<title>Compiling for Android</title>
<para>
MPD can be compiled as an Android app. It can be installed
easily with <link linkend="install_android">Google
Play</link>, but if you want to build it from source, follow
this section.
</para>
<para>
You need:
</para>
<itemizedlist>
<listitem>
<para>
Android SDK
</para>
</listitem>
<listitem>
<para>
<ulink
url="https://developer.android.com/ndk/downloads/index.html">Android
NDK</ulink>
</para>
</listitem>
</itemizedlist>
<para>
Just like with the native build, unpack the
<application>MPD</application> source tarball and change
into the directory. Then, instead of
<command>./configure</command>, type:
</para>
<programlisting>./android/build.py SDK_PATH NDK_PATH ABI
make android/build/mpd-debug.apk</programlisting>
<para>
<varname>SDK_PATH</varname> is the absolute path where you
installed the Android SDK; <varname>NDK_PATH</varname> is
the Android NDK installation path; <varname>ABI</varname> is
the Android ABI to be built, e.g. "armeabi-v7a".
</para>
<para>
This downloads various library sources, and then configures
and builds <application>MPD</application>.
</para>
</section>
</section> </section>
<section id="systemd_socket"> <section id="systemd_socket">
......
...@@ -17,12 +17,17 @@ libogg = AutotoolsProject( ...@@ -17,12 +17,17 @@ libogg = AutotoolsProject(
) )
libvorbis = AutotoolsProject( libvorbis = AutotoolsProject(
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz', 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.xz',
'28cb28097c07a735d6af56e598e1c90f', 'af00bb5a784e7c9e69f56823de4637c350643deedaf333d0fa86ecdba6fcb415',
'lib/libvorbis.a', 'lib/libvorbis.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
], ],
edits={
# this option is not understood by clang
'configure': lambda data: data.replace('-mno-ieee-fp', ' '),
}
) )
opus = AutotoolsProject( opus = AutotoolsProject(
...@@ -100,8 +105,8 @@ liblame = AutotoolsProject( ...@@ -100,8 +105,8 @@ liblame = AutotoolsProject(
) )
ffmpeg = FfmpegProject( ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.4.2.tar.xz', 'http://ffmpeg.org/releases/ffmpeg-4.0.tar.xz',
'2b92e9578ef8b3e49eeab229e69305f5f4cbc1fdaa22e927fc7fca18acccd740', 'ed945daf40b124e77a685893cc025d086f638bc703183460aff49508edb3a43f',
'lib/libavcodec.a', 'lib/libavcodec.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
...@@ -329,8 +334,8 @@ ffmpeg = FfmpegProject( ...@@ -329,8 +334,8 @@ ffmpeg = FfmpegProject(
) )
curl = AutotoolsProject( curl = AutotoolsProject(
'http://curl.haxx.se/download/curl-7.58.0.tar.xz', 'http://curl.haxx.se/download/curl-7.59.0.tar.xz',
'6a813875243609eb75f37fa72044e4ad618b55ec15a4eafdac2df6a7e800e3e3', 'e44eaabdf916407585bf5c7939ff1161e6242b6b015d3f2f5b758b2a330461fc',
'lib/libcurl.a', 'lib/libcurl.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
......
...@@ -107,10 +107,6 @@ ...@@ -107,10 +107,6 @@
#include <locale.h> #include <locale.h>
#endif #endif
#ifdef __BLOCKS__
#include <dispatch/dispatch.h>
#endif
#include <limits.h> #include <limits.h>
static constexpr size_t KILOBYTE = 1024; static constexpr size_t KILOBYTE = 1024;
...@@ -483,21 +479,8 @@ try { ...@@ -483,21 +479,8 @@ try {
daemonize_begin(options.daemon); daemonize_begin(options.daemon);
#endif #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(config));
});
dispatch_main();
return EXIT_FAILURE; // unreachable, because dispatch_main never returns
#else
return mpd_main_after_fork(config); return mpd_main_after_fork(config);
#endif
} catch (const std::exception &e) { } catch (const std::exception &e) {
LogError(e); LogError(e);
return EXIT_FAILURE; return EXIT_FAILURE;
......
...@@ -325,6 +325,34 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection) ...@@ -325,6 +325,34 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection)
return true; return true;
} }
static bool
SendGroupMask(mpd_connection *connection, tag_mask_t mask)
{
#if LIBMPDCLIENT_CHECK_VERSION(2,12,0)
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) {
if ((mask & (tag_mask_t(1) << i)) == 0)
continue;
const auto tag = Convert(TagType(i));
if (tag == MPD_TAG_COUNT)
throw std::runtime_error("Unsupported tag");
if (!mpd_search_add_group_tag(connection, tag))
return false;
}
return true;
#else
(void)connection;
(void)mask;
if (mask != 0)
throw std::runtime_error("Grouping requires libmpdclient 2.12");
return true;
#endif
}
ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener, ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener,
const ConfigBlock &block) const ConfigBlock &block)
:Database(proxy_db_plugin), :Database(proxy_db_plugin),
...@@ -682,7 +710,7 @@ static void ...@@ -682,7 +710,7 @@ static void
SearchSongs(struct mpd_connection *connection, SearchSongs(struct mpd_connection *connection,
const DatabaseSelection &selection, const DatabaseSelection &selection,
VisitSong visit_song) VisitSong visit_song)
{ try {
assert(selection.recursive); assert(selection.recursive);
assert(visit_song); assert(visit_song);
...@@ -709,6 +737,11 @@ SearchSongs(struct mpd_connection *connection, ...@@ -709,6 +737,11 @@ SearchSongs(struct mpd_connection *connection,
if (!mpd_response_finish(connection)) if (!mpd_response_finish(connection))
ThrowError(connection); ThrowError(connection);
} catch (...) {
if (connection != nullptr)
mpd_search_cancel(connection);
throw;
} }
/** /**
...@@ -756,9 +789,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection, ...@@ -756,9 +789,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
void void
ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
TagType tag_type, TagType tag_type,
gcc_unused tag_mask_t group_mask, tag_mask_t group_mask,
VisitTag visit_tag) const VisitTag visit_tag) const
{ try {
// TODO: eliminate the const_cast // TODO: eliminate the const_cast
const_cast<ProxyDatabase *>(this)->EnsureConnected(); const_cast<ProxyDatabase *>(this)->EnsureConnected();
...@@ -767,32 +800,47 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ...@@ -767,32 +800,47 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
throw std::runtime_error("Unsupported tag"); throw std::runtime_error("Unsupported tag");
if (!mpd_search_db_tags(connection, tag_type2) || if (!mpd_search_db_tags(connection, tag_type2) ||
!SendConstraints(connection, selection)) !SendConstraints(connection, selection) ||
!SendGroupMask(connection, group_mask))
ThrowError(connection); ThrowError(connection);
// TODO: use group_mask
if (!mpd_search_commit(connection)) if (!mpd_search_commit(connection))
ThrowError(connection); ThrowError(connection);
while (auto *pair = mpd_recv_pair_tag(connection, tag_type2)) { TagBuilder builder;
while (auto *pair = mpd_recv_pair(connection)) {
AtScopeExit(this, pair) { AtScopeExit(this, pair) {
mpd_return_pair(connection, pair); mpd_return_pair(connection, pair);
}; };
TagBuilder tag; const auto current_type = tag_name_parse_i(pair->name);
tag.AddItem(tag_type, pair->value); if (current_type == TAG_NUM_OF_ITEM_TYPES)
continue;
if (tag.IsEmpty()) if (current_type == tag_type && !builder.IsEmpty()) {
try {
visit_tag(builder.Commit());
} catch (...) {
mpd_response_finish(connection);
throw;
}
}
builder.AddItem(current_type, pair->value);
if (!builder.HasType(current_type))
/* if no tag item has been added, then the /* if no tag item has been added, then the
given value was not acceptable given value was not acceptable
(e.g. empty); forcefully insert an empty (e.g. empty); forcefully insert an empty
tag in this case, as the caller expects the tag in this case, as the caller expects the
given tag type to be present */ given tag type to be present */
tag.AddEmptyItem(tag_type); builder.AddEmptyItem(current_type);
}
if (!builder.IsEmpty()) {
try { try {
visit_tag(tag.Commit()); visit_tag(builder.Commit());
} catch (...) { } catch (...) {
mpd_response_finish(connection); mpd_response_finish(connection);
throw; throw;
...@@ -801,6 +849,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ...@@ -801,6 +849,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
if (!mpd_response_finish(connection)) if (!mpd_response_finish(connection))
ThrowError(connection); ThrowError(connection);
} catch (...) {
if (connection != nullptr)
mpd_search_cancel(connection);
throw;
} }
DatabaseStats DatabaseStats
......
...@@ -308,9 +308,14 @@ struct DecoderControl { ...@@ -308,9 +308,14 @@ struct DecoderControl {
bool IsCurrentSong(const DetachedSong &_song) const noexcept; bool IsCurrentSong(const DetachedSong &_song) const noexcept;
gcc_pure gcc_pure
bool LockIsCurrentSong(const DetachedSong &_song) const noexcept { bool IsSeekableCurrentSong(const DetachedSong &_song) const