summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--android/AndroidManifest.xml6
-rwxr-xr-xandroid/build.py6
-rw-r--r--doc/user.xml21
-rw-r--r--python/build/libs.py4
-rw-r--r--python/build/project.py11
-rw-r--r--python/build/quilt.py9
-rw-r--r--src/SongSave.cxx3
-rw-r--r--src/db/update/Service.cxx3
-rw-r--r--src/filter/plugins/ConvertFilterPlugin.cxx3
-rw-r--r--src/input/plugins/FileInputPlugin.cxx3
-rw-r--r--src/lib/curl/patches/no_netrc.patch20
-rw-r--r--src/lib/curl/patches/only_lib.patch15
-rw-r--r--src/lib/curl/patches/series2
-rw-r--r--src/mixer/plugins/volume_mapping.c7
-rw-r--r--src/pcm/Order.cxx2
-rw-r--r--src/protocol/ArgParser.cxx3
-rw-r--r--src/queue/PlaylistState.cxx7
-rw-r--r--src/tag/ReplayGain.cxx9
-rw-r--r--src/thread/Util.cxx26
-rw-r--r--src/util/NumberParser.hxx5
21 files changed, 150 insertions, 24 deletions
diff --git a/NEWS b/NEWS
index 45d2a107f..01d477197 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,15 @@ ver 0.21 (not yet released)
- sndio: new mixer plugin
* require GCC 5.0
+ver 0.20.17 (2018/02/11)
+* output
+ - alsa: fix crash bug with 8 channels
+* mixer
+ - alsa: fix rounding error at volume 0
+* fix real-time and idle scheduling with Musl
+* Android
+ - fix compatibility with Android 4.0
+
ver 0.20.16 (2018/02/03)
* output
- pulse: fix crash during auto-detection
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 16a75f5e1..713c136bf 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -2,10 +2,10 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
- android:versionCode="15"
- android:versionName="0.20.16">
+ android:versionCode="16"
+ android:versionName="0.20.17">
- <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/>
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
diff --git a/android/build.py b/android/build.py
index 0b001e7da..3e2e71dcc 100755
--- a/android/build.py
+++ b/android/build.py
@@ -46,7 +46,7 @@ class AndroidNdkToolchain:
self.ndk_arch = 'arm'
android_abi = 'armeabi-v7a'
- ndk_platform = 'android-21'
+ ndk_platform = 'android-14'
# select the NDK compiler
gcc_version = '4.9'
@@ -67,7 +67,7 @@ class AndroidNdkToolchain:
common_flags = '-Os -g'
common_flags += ' -fPIC'
- common_flags += ' -march=armv7-a -mfloat-abi=softfp'
+ common_flags += ' -march=armv7-a -mfpu=vfp -mfloat-abi=softfp'
toolchain_bin = os.path.join(toolchain_path, 'bin')
llvm_bin = os.path.join(llvm_path, 'bin')
@@ -87,7 +87,7 @@ class AndroidNdkToolchain:
self.cppflags = '--sysroot=' + sysroot + \
' -isystem ' + os.path.join(install_prefix, 'include') + \
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
- ' -D__ANDROID_API__=21'
+ ' -D__ANDROID_API__=14'
self.ldflags = '--sysroot=' + sysroot + \
' -L' + os.path.join(install_prefix, 'lib') + \
' -L' + os.path.join(target_root, 'usr', 'lib') + \
diff --git a/doc/user.xml b/doc/user.xml
index 43e7c6d35..bbe8f6cdb 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -66,6 +66,23 @@
</para>
</section>
+ <section id="install_android">
+ <title>Installing on Android</title>
+
+ <para>
+ An experimental Android build is available on <ulink
+ url="https://play.google.com/store/apps/details?id=org.musicpd">Google
+ Play</ulink>. After installing and launching it, MPD will
+ scan the music in your <filename>Music</filename> directory
+ and you can control it as usual with a MPD client.
+ </para>
+
+ <para>
+ If you need to tweak the configuration, you can create a file
+ called <filename>mpd.conf</filename> on the data partition.
+ </para>
+ </section>
+
<section id="install_source">
<title>Compiling from source</title>
@@ -323,7 +340,9 @@ systemctl start mpd.socket</programlisting>
<application>MPD</application> as a user daemon (and not as a
system daemon), the configuration is read from
<filename>$XDG_CONFIG_HOME/mpd/mpd.conf</filename> (usually
- <filename>~/.config/mpd/mpd.conf</filename>).
+ <filename>~/.config/mpd/mpd.conf</filename>). On Android,
+ <filename>mpd.conf</filename> will be loaded from the
+ top-level directory of the data partition.
</para>
<para>
diff --git a/python/build/libs.py b/python/build/libs.py
index a46902a19..7d93799d8 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -1,4 +1,6 @@
import re
+from os.path import abspath
+
from build.project import Project
from build.zlib import ZlibProject
from build.autotools import AutotoolsProject
@@ -358,6 +360,8 @@ curl = AutotoolsProject(
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
],
+
+ patches='src/lib/curl/patches',
)
boost = BoostProject(
diff --git a/python/build/project.py b/python/build/project.py
index 087ca3d07..b78c89238 100644
--- a/python/build/project.py
+++ b/python/build/project.py
@@ -3,10 +3,12 @@ import re
from build.download import download_and_verify
from build.tar import untar
+from build.quilt import push_all
class Project:
def __init__(self, url, md5, installed, name=None, version=None,
base=None,
+ patches=None,
edits=None,
use_cxx=False):
if base is None:
@@ -18,7 +20,7 @@ class Project:
self.base = base
if name is None or version is None:
- m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?)$', self.base)
+ m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?[\d.]*)$', self.base)
if name is None: name = m.group(1)
if version is None: version = m.group(2)
@@ -29,6 +31,10 @@ class Project:
self.md5 = md5
self.installed = installed
+ if patches is not None:
+ srcdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+ patches = os.path.join(srcdir, patches)
+ self.patches = patches
self.edits = edits
self.use_cxx = use_cxx
@@ -51,6 +57,9 @@ class Project:
parent_path = toolchain.build_path
path = untar(self.download(toolchain), parent_path, self.base)
+ if self.patches is not None:
+ push_all(toolchain, path, self.patches)
+
if self.edits is not None:
for filename, function in self.edits.items():
with open(os.path.join(path, filename), 'r+t') as f:
diff --git a/python/build/quilt.py b/python/build/quilt.py
new file mode 100644
index 000000000..876453d2b
--- /dev/null
+++ b/python/build/quilt.py
@@ -0,0 +1,9 @@
+import subprocess
+
+def run_quilt(toolchain, cwd, patches_path, *args):
+ env = dict(toolchain.env)
+ env['QUILT_PATCHES'] = patches_path
+ subprocess.check_call(['quilt'] + list(args), cwd=cwd, env=env)
+
+def push_all(toolchain, src_path, patches_path):
+ run_quilt(toolchain, src_path, patches_path, 'push', '-a')
diff --git a/src/SongSave.cxx b/src/SongSave.cxx
index ab80c5c75..c3593d823 100644
--- a/src/SongSave.cxx
+++ b/src/SongSave.cxx
@@ -30,6 +30,7 @@
#include "util/ChronoUtil.hxx"
#include "util/StringStrip.hxx"
#include "util/RuntimeError.hxx"
+#include "util/NumberParser.hxx"
#include <string.h>
#include <stdlib.h>
@@ -98,7 +99,7 @@ song_load(TextFile &file, const char *uri)
if ((type = tag_name_parse(line)) != TAG_NUM_OF_ITEM_TYPES) {
tag.AddItem(type, value);
} else if (strcmp(line, "Time") == 0) {
- tag.SetDuration(SignedSongTime::FromS(atof(value)));
+ tag.SetDuration(SignedSongTime::FromS(ParseDouble(value)));
} else if (strcmp(line, "Playlist") == 0) {
tag.SetHasPlaylist(strcmp(value, "yes") == 0);
} else if (strcmp(line, SONG_MTIME) == 0) {
diff --git a/src/db/update/Service.cxx b/src/db/update/Service.cxx
index ded404424..d115fb5d9 100644
--- a/src/db/update/Service.cxx
+++ b/src/db/update/Service.cxx
@@ -29,6 +29,7 @@
#include "Idle.hxx"
#include "Log.hxx"
#include "thread/Thread.hxx"
+#include "thread/Name.hxx"
#include "thread/Util.hxx"
#ifndef NDEBUG
@@ -111,6 +112,8 @@ UpdateService::Task()
{
assert(walk != nullptr);
+ SetThreadName("update");
+
if (!next.path_utf8.empty())
FormatDebug(update_domain, "starting: %s",
next.path_utf8.c_str());
diff --git a/src/filter/plugins/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx
index 77c82eea9..eaa5fc4a3 100644
--- a/src/filter/plugins/ConvertFilterPlugin.cxx
+++ b/src/filter/plugins/ConvertFilterPlugin.cxx
@@ -51,7 +51,8 @@ public:
void Set(const AudioFormat &_out_audio_format);
void Reset() noexcept override {
- state.Reset();
+ if (IsActive())
+ state.Reset();
}
ConstBuffer<void> FilterPCM(ConstBuffer<void> src) override;
diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx
index 9e0398916..cc8e62413 100644
--- a/src/input/plugins/FileInputPlugin.cxx
+++ b/src/input/plugins/FileInputPlugin.cxx
@@ -65,10 +65,13 @@ OpenFileInputStream(Path path,
throw FormatRuntimeError("Not a regular file: %s",
path.c_str());
+#if !defined(__BIONIC__) || __ANDROID_API__ >= 21
+ /* posix_fadvise() requires Android API 21 */
#ifdef POSIX_FADV_SEQUENTIAL
posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(),
POSIX_FADV_SEQUENTIAL);
#endif
+#endif
return std::make_unique<FileInputStream>(path.ToUTF8().c_str(),
std::move(reader), info.GetSize(),
diff --git a/src/lib/curl/patches/no_netrc.patch b/src/lib/curl/patches/no_netrc.patch
new file mode 100644
index 000000000..22557d162
--- /dev/null
+++ b/src/lib/curl/patches/no_netrc.patch
@@ -0,0 +1,20 @@
+Index: curl-7.58.0/lib/url.c
+===================================================================
+--- curl-7.58.0.orig/lib/url.c
++++ curl-7.58.0/lib/url.c
+@@ -3503,6 +3503,7 @@ static CURLcode override_login(struct Cu
+ }
+
+ conn->bits.netrc = FALSE;
++#ifndef __BIONIC__
+ if(data->set.use_netrc != CURL_NETRC_IGNORED) {
+ int ret = Curl_parsenetrc(conn->host.name,
+ userp, passwdp,
+@@ -3524,6 +3525,7 @@ static CURLcode override_login(struct Cu
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+ }
+ }
++#endif
+
+ return CURLE_OK;
+ }
diff --git a/src/lib/curl/patches/only_lib.patch b/src/lib/curl/patches/only_lib.patch
new file mode 100644
index 000000000..2bc374983
--- /dev/null
+++ b/src/lib/curl/patches/only_lib.patch
@@ -0,0 +1,15 @@
+Index: curl-7.58.0/Makefile.in
+===================================================================
+--- curl-7.58.0.orig/Makefile.in
++++ curl-7.58.0/Makefile.in
+@@ -641,8 +641,8 @@ CLEANFILES = $(VC6_LIBDSP) $(VC6_SRCDSP)
+ $(VC14_LIBVCXPROJ) $(VC14_SRCVCXPROJ) $(VC15_LIBVCXPROJ) $(VC15_SRCVCXPROJ)
+
+ bin_SCRIPTS = curl-config
+-SUBDIRS = lib src
+-DIST_SUBDIRS = $(SUBDIRS) tests packages scripts include docs
++SUBDIRS = lib
++DIST_SUBDIRS = $(SUBDIRS) include
+ pkgconfigdir = $(libdir)/pkgconfig
+ pkgconfig_DATA = libcurl.pc
+ LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \
diff --git a/src/lib/curl/patches/series b/src/lib/curl/patches/series
new file mode 100644
index 000000000..f9bd7bfe3
--- /dev/null
+++ b/src/lib/curl/patches/series
@@ -0,0 +1,2 @@
+only_lib.patch
+no_netrc.patch
diff --git a/src/mixer/plugins/volume_mapping.c b/src/mixer/plugins/volume_mapping.c
index 4e559cf54..2078d346d 100644
--- a/src/mixer/plugins/volume_mapping.c
+++ b/src/mixer/plugins/volume_mapping.c
@@ -139,6 +139,13 @@ static int set_normalized_volume(snd_mixer_elem_t *elem,
return set_raw[ctl_dir](elem, value);
}
+ /* two special cases to avoid rounding errors at 0% and
+ 100% */
+ if (volume <= 0)
+ return set_dB[ctl_dir](elem, min, dir);
+ else if (volume >= 100)
+ return set_dB[ctl_dir](elem, max, dir);
+
if (use_linear_dB_scale(min, max)) {
value = lrint_dir(volume * (max - min), dir) + min;
return set_dB[ctl_dir](elem, value, dir);
diff --git a/src/pcm/Order.cxx b/src/pcm/Order.cxx
index 8f246bdce..3a1a412a8 100644
--- a/src/pcm/Order.cxx
+++ b/src/pcm/Order.cxx
@@ -88,7 +88,7 @@ static inline ConstBuffer<V>
ToAlsaChannelOrder71(PcmBuffer &buffer, ConstBuffer<V> src) noexcept
{
auto dest = buffer.GetT<V>(src.size);
- ToAlsaChannelOrder71(dest, src.data, src.size / 6);
+ ToAlsaChannelOrder71(dest, src.data, src.size / 8);
return { dest, src.size };
}
diff --git a/src/protocol/ArgParser.cxx b/src/protocol/ArgParser.cxx
index 185c57863..47fdfa405 100644
--- a/src/protocol/ArgParser.cxx
+++ b/src/protocol/ArgParser.cxx
@@ -21,6 +21,7 @@
#include "ArgParser.hxx"
#include "Ack.hxx"
#include "Chrono.hxx"
+#include "util/NumberParser.hxx"
#include <stdlib.h>
@@ -151,7 +152,7 @@ float
ParseCommandArgFloat(const char *s)
{
char *endptr;
- auto value = strtof(s, &endptr);
+ auto value = ParseFloat(s, &endptr);
if (endptr == s || *endptr != 0)
throw FormatProtocolError(ACK_ERROR_ARG,
"Float expected: %s", s);
diff --git a/src/queue/PlaylistState.cxx b/src/queue/PlaylistState.cxx
index d08610efc..614f01c19 100644
--- a/src/queue/PlaylistState.cxx
+++ b/src/queue/PlaylistState.cxx
@@ -35,6 +35,7 @@
#include "util/CharUtil.hxx"
#include "util/StringAPI.hxx"
#include "util/StringCompare.hxx"
+#include "util/NumberParser.hxx"
#include "Log.hxx"
#include <string.h>
@@ -148,7 +149,7 @@ playlist_state_restore(const char *line, TextFile &file,
while ((line = file.ReadLine()) != nullptr) {
const char *p;
if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_TIME))) {
- seek_time = SongTime::FromS(atof(p));
+ seek_time = SongTime::FromS(ParseDouble(p));
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_REPEAT))) {
playlist.SetRepeat(pc, StringIsEqual(p, "1"));
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_SINGLE))) {
@@ -158,12 +159,12 @@ playlist_state_restore(const char *line, TextFile &file,
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_CROSSFADE))) {
pc.SetCrossFade(atoi(p));
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_MIXRAMPDB))) {
- pc.SetMixRampDb(atof(p));
+ pc.SetMixRampDb(ParseFloat(p));
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_MIXRAMPDELAY))) {
/* this check discards "nan" which was used
prior to MPD 0.18 */
if (IsDigitASCII(*p))
- pc.SetMixRampDelay(atof(p));
+ pc.SetMixRampDelay(ParseFloat(p));
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_RANDOM))) {
random_mode = StringIsEqual(p, "1");
} else if ((p = StringAfterPrefix(line, PLAYLIST_STATE_FILE_CURRENT))) {
diff --git a/src/tag/ReplayGain.cxx b/src/tag/ReplayGain.cxx
index 10f2f8a32..ccdcf3fc8 100644
--- a/src/tag/ReplayGain.cxx
+++ b/src/tag/ReplayGain.cxx
@@ -22,6 +22,7 @@
#include "VorbisComment.hxx"
#include "ReplayGainInfo.hxx"
#include "util/ASCII.hxx"
+#include "util/NumberParser.hxx"
#include <assert.h>
#include <stdlib.h>
@@ -33,16 +34,16 @@ ParseReplayGainTagTemplate(ReplayGainInfo &info, const T t)
const char *value;
if ((value = t["replaygain_track_gain"]) != nullptr) {
- info.track.gain = atof(value);
+ info.track.gain = ParseFloat(value);
return true;
} else if ((value = t["replaygain_album_gain"]) != nullptr) {
- info.album.gain = atof(value);
+ info.album.gain = ParseFloat(value);
return true;
} else if ((value = t["replaygain_track_peak"]) != nullptr) {
- info.track.peak = atof(value);
+ info.track.peak = ParseFloat(value);
return true;
} else if ((value = t["replaygain_album_peak"]) != nullptr) {
- info.album.peak = atof(value);
+ info.album.peak = ParseFloat(value);
return true;
} else
return false;
diff --git a/src/thread/Util.cxx b/src/thread/Util.cxx
index d50d507e1..5b61b62be 100644
--- a/src/thread/Util.cxx
+++ b/src/thread/Util.cxx
@@ -38,10 +38,12 @@
#include <windows.h>
#endif
-#if defined(__linux__) && !defined(ANDROID)
+#ifdef __linux__
+
+#ifndef ANDROID
static int
-ioprio_set(int which, int who, int ioprio) noexcept
+linux_ioprio_set(int which, int who, int ioprio) noexcept
{
return syscall(__NR_ioprio_set, which, who, ioprio);
}
@@ -55,7 +57,21 @@ ioprio_set_idle() noexcept
static constexpr int _IOPRIO_IDLE =
(_IOPRIO_CLASS_IDLE << _IOPRIO_CLASS_SHIFT) | 7;
- ioprio_set(_IOPRIO_WHO_PROCESS, 0, _IOPRIO_IDLE);
+ linux_ioprio_set(_IOPRIO_WHO_PROCESS, 0, _IOPRIO_IDLE);
+}
+
+#endif /* !ANDROID */
+
+/**
+ * Wrapper for the "sched_setscheduler" system call. We don't use the
+ * one from the C library because Musl has an intentionally broken
+ * implementation.
+ */
+static int
+linux_sched_setscheduler(pid_t pid, int sched,
+ const struct sched_param *param) noexcept
+{
+ return syscall(__NR_sched_setscheduler, pid, sched, param);
}
#endif
@@ -66,7 +82,7 @@ SetThreadIdlePriority() noexcept
#ifdef __linux__
#ifdef SCHED_IDLE
static struct sched_param sched_param;
- sched_setscheduler(0, SCHED_IDLE, &sched_param);
+ linux_sched_setscheduler(0, SCHED_IDLE, &sched_param);
#endif
#ifndef ANDROID
@@ -92,7 +108,7 @@ SetThreadRealtime()
policy |= SCHED_RESET_ON_FORK;
#endif
- if (sched_setscheduler(0, policy, &sched_param) < 0)
+ if (linux_sched_setscheduler(0, policy, &sched_param) < 0)
throw MakeErrno("sched_setscheduler failed");
#endif // __linux__
};
diff --git a/src/util/NumberParser.hxx b/src/util/NumberParser.hxx
index 47e9aacbd..67d42affa 100644
--- a/src/util/NumberParser.hxx
+++ b/src/util/NumberParser.hxx
@@ -78,7 +78,12 @@ ParseDouble(const char *p, char **endptr=nullptr)
static inline float
ParseFloat(const char *p, char **endptr=nullptr)
{
+#if defined(__BIONIC__) && __ANDROID_API__ < 21
+ /* strtof() requires API level 21 */
return (float)ParseDouble(p, endptr);
+#else
+ return strtof(p, endptr);
+#endif
}
#endif