aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS16
-rw-r--r--configure.ac8
-rw-r--r--src/DatabaseGlue.cxx6
-rw-r--r--src/DatabasePlugin.hxx9
-rw-r--r--src/DatabaseSimple.hxx16
-rw-r--r--src/Mapper.cxx4
-rw-r--r--src/Mapper.hxx3
-rw-r--r--src/Stats.cxx62
-rw-r--r--src/Stats.hxx20
-rw-r--r--src/archive/Iso9660ArchivePlugin.cxx6
-rw-r--r--src/db/ProxyDatabasePlugin.cxx10
-rw-r--r--src/db/SimpleDatabasePlugin.hxx11
-rw-r--r--src/decoder/DsdiffDecoderPlugin.cxx5
-rw-r--r--src/decoder/DsfDecoderPlugin.cxx4
-rw-r--r--src/decoder/OggFind.cxx2
-rw-r--r--src/input/CurlInputPlugin.cxx32
-rw-r--r--src/pcm/PcmResample.cxx23
-rw-r--r--src/pcm/PcmResample.hxx8
-rw-r--r--src/pcm/PcmResampleInternal.hxx9
-rw-r--r--src/pcm/PcmResampleLibsamplerate.cxx25
-rw-r--r--src/pcm/PcmUtils.hxx12
-rw-r--r--src/system/ByteOrder.hxx20
-rw-r--r--src/system/fd_util.h5
23 files changed, 224 insertions, 92 deletions
diff --git a/NEWS b/NEWS
index 86ab1a2a0..9301f1dcc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,19 @@
+ver 0.18.5 (2013/11/23)
+* configuration
+ - fix crash when db_file is configured without music_directory
+ - fix crash on "stats" without db_file/music_directory
+* database
+ - proxy: auto-reload statistics
+ - proxy: provide "db_update" in "stats" response
+* input
+ - curl: work around stream resume bug (fixed in libcurl 7.32.0)
+* decoder
+ - fluidsynth: auto-detect by default
+* clip 24 bit data from libsamplerate
+* fix ia64, mipsel and other little-endian architectures
+* fix build failures due to missing includes
+* fix build failure with static libmpdclient
+
ver 0.18.4 (2013/11/13)
* decoder
- dsdiff: fix byte order bug
diff --git a/configure.ac b/configure.ac
index df3a92810..e2f2eba7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -874,10 +874,12 @@ AM_CONDITIONAL(HAVE_FLAC, test x$enable_flac = xyes)
enable_flac_encoder=$enable_flac
dnl -------------------------------- FluidSynth -------------------------------
+
+MPD_AUTO_PKG(fluidsynth, FLUIDSYNTH, [fluidsynth >= 1.1],
+ [fluidsynth decoder], [fluidsynth not found])
+
if test x$enable_fluidsynth = xyes; then
- PKG_CHECK_MODULES(FLUIDSYNTH, [fluidsynth >= 1.1],
- AC_DEFINE(ENABLE_FLUIDSYNTH, 1, [Define for fluidsynth support]),
- enable_fluidsynth=no)
+ AC_DEFINE(ENABLE_FLUIDSYNTH, 1, [Define for fluidsynth support])
fi
AM_CONDITIONAL(ENABLE_FLUIDSYNTH, test x$enable_fluidsynth = xyes)
diff --git a/src/DatabaseGlue.cxx b/src/DatabaseGlue.cxx
index e84503713..013a3e329 100644
--- a/src/DatabaseGlue.cxx
+++ b/src/DatabaseGlue.cxx
@@ -148,12 +148,12 @@ DatabaseGlobalOpen(Error &error)
return true;
}
-time_t
-db_get_mtime(void)
+bool
+db_exists()
{
assert(db != nullptr);
assert(db_is_open);
assert(db_is_simple());
- return ((SimpleDatabase *)db)->GetLastModified();
+ return ((SimpleDatabase *)db)->GetUpdateStamp() > 0;
}
diff --git a/src/DatabasePlugin.hxx b/src/DatabasePlugin.hxx
index 629dff329..ccf899389 100644
--- a/src/DatabasePlugin.hxx
+++ b/src/DatabasePlugin.hxx
@@ -30,6 +30,8 @@
#include "tag/TagType.h"
#include "Compiler.h"
+#include <time.h>
+
struct config_param;
struct DatabaseSelection;
struct db_visitor;
@@ -132,6 +134,13 @@ public:
virtual bool GetStats(const DatabaseSelection &selection,
DatabaseStats &stats,
Error &error) const = 0;
+
+ /**
+ * Returns the time stamp of the last database update.
+ * Returns 0 if that is not not known/available.
+ */
+ gcc_pure
+ virtual time_t GetUpdateStamp() const = 0;
};
struct DatabasePlugin {
diff --git a/src/DatabaseSimple.hxx b/src/DatabaseSimple.hxx
index 124d78a30..6d52ac0b3 100644
--- a/src/DatabaseSimple.hxx
+++ b/src/DatabaseSimple.hxx
@@ -63,24 +63,12 @@ bool
db_save(Error &error);
/**
- * May only be used if db_is_simple() returns true.
- */
-gcc_pure
-time_t
-db_get_mtime(void);
-
-/**
* Returns true if there is a valid database file on the disk.
*
* May only be used if db_is_simple() returns true.
*/
gcc_pure
-static inline bool
-db_exists(void)
-{
- /* mtime is set only if the database file was loaded or saved
- successfully */
- return db_get_mtime() > 0;
-}
+bool
+db_exists();
#endif
diff --git a/src/Mapper.cxx b/src/Mapper.cxx
index 08597732a..cbe45daa0 100644
--- a/src/Mapper.cxx
+++ b/src/Mapper.cxx
@@ -133,7 +133,9 @@ void mapper_finish(void)
const char *
mapper_get_music_directory_utf8(void)
{
- return music_dir_utf8.c_str();
+ return music_dir_utf8.empty()
+ ? nullptr
+ : music_dir_utf8.c_str();
}
const AllocatedPath &
diff --git a/src/Mapper.hxx b/src/Mapper.hxx
index be69a7110..947fd2822 100644
--- a/src/Mapper.hxx
+++ b/src/Mapper.hxx
@@ -41,7 +41,8 @@ mapper_init(AllocatedPath &&music_dir, AllocatedPath &&playlist_dir);
void mapper_finish(void);
/**
- * Return the absolute path of the music directory encoded in UTF-8.
+ * Return the absolute path of the music directory encoded in UTF-8 or
+ * nullptr if no music directory was configured.
*/
gcc_const
const char *
diff --git a/src/Stats.cxx b/src/Stats.cxx
index 88f76928f..f224bdf49 100644
--- a/src/Stats.cxx
+++ b/src/Stats.cxx
@@ -30,59 +30,75 @@
#include <glib.h>
-struct stats stats;
+static GTimer *uptime;
+static DatabaseStats stats;
void stats_global_init(void)
{
- stats.timer = g_timer_new();
+ uptime = g_timer_new();
}
void stats_global_finish(void)
{
- g_timer_destroy(stats.timer);
+ g_timer_destroy(uptime);
}
void stats_update(void)
{
+ assert(GetDatabase() != nullptr);
+
Error error;
DatabaseStats stats2;
const DatabaseSelection selection("", true);
if (GetDatabase()->GetStats(selection, stats2, error)) {
- stats.song_count = stats2.song_count;
- stats.song_duration = stats2.total_duration;
- stats.artist_count = stats2.artist_count;
- stats.album_count = stats2.album_count;
+ stats = stats2;
} else {
LogError(error);
- stats.song_count = 0;
- stats.song_duration = 0;
- stats.artist_count = 0;
- stats.album_count = 0;
+ stats.Clear();
}
}
-void
-stats_print(Client &client)
+static void
+db_stats_print(Client &client)
{
+ assert(GetDatabase() != nullptr);
+
+ if (!db_is_simple())
+ /* reload statistics if we're using the "proxy"
+ database plugin */
+ /* TODO: move this into the "proxy" database plugin as
+ an "idle" handler */
+ stats_update();
+
client_printf(client,
"artists: %u\n"
"albums: %u\n"
- "songs: %i\n"
- "uptime: %li\n"
- "playtime: %li\n"
- "db_playtime: %li\n",
+ "songs: %u\n"
+ "db_playtime: %lu\n",
stats.artist_count,
stats.album_count,
stats.song_count,
- (long)g_timer_elapsed(stats.timer, NULL),
- (long)(client.player_control.GetTotalPlayTime() + 0.5),
- stats.song_duration);
+ stats.total_duration);
- if (db_is_simple())
+ const time_t update_stamp = GetDatabase()->GetUpdateStamp();
+ if (update_stamp > 0)
client_printf(client,
- "db_update: %li\n",
- (long)db_get_mtime());
+ "db_update: %lu\n",
+ (unsigned long)update_stamp);
+}
+
+void
+stats_print(Client &client)
+{
+ client_printf(client,
+ "uptime: %lu\n"
+ "playtime: %lu\n",
+ (unsigned long)g_timer_elapsed(uptime, NULL),
+ (unsigned long)(client.player_control.GetTotalPlayTime() + 0.5));
+
+ if (GetDatabase() != nullptr)
+ db_stats_print(client);
}
diff --git a/src/Stats.hxx b/src/Stats.hxx
index 1b141355c..dd131ce19 100644
--- a/src/Stats.hxx
+++ b/src/Stats.hxx
@@ -21,26 +21,6 @@
#define MPD_STATS_HXX
class Client;
-typedef struct _GTimer GTimer;
-
-struct stats {
- GTimer *timer;
-
- /** number of song files in the music directory */
- unsigned song_count;
-
- /** sum of all song durations in the music directory (in
- seconds) */
- unsigned long song_duration;
-
- /** number of distinct artist names in the music directory */
- unsigned artist_count;
-
- /** number of distinct album names in the music directory */
- unsigned album_count;
-};
-
-extern struct stats stats;
void stats_global_init(void);
diff --git a/src/archive/Iso9660ArchivePlugin.cxx b/src/archive/Iso9660ArchivePlugin.cxx
index 8233d03f7..ad21d4a3d 100644
--- a/src/archive/Iso9660ArchivePlugin.cxx
+++ b/src/archive/Iso9660ArchivePlugin.cxx
@@ -190,18 +190,16 @@ iso9660_input_read(InputStream *is, void *ptr, size_t size,
Error &error)
{
Iso9660InputStream *iis = (Iso9660InputStream *)is;
- int toread, readed = 0;
+ int readed = 0;
int no_blocks, cur_block;
size_t left_bytes = iis->statbuf->size - is->offset;
size = (size * ISO_BLOCKSIZE) / ISO_BLOCKSIZE;
if (left_bytes < size) {
- toread = left_bytes;
no_blocks = CEILING(left_bytes,ISO_BLOCKSIZE);
} else {
- toread = size;
- no_blocks = toread / ISO_BLOCKSIZE;
+ no_blocks = size / ISO_BLOCKSIZE;
}
if (no_blocks > 0) {
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
index fc99242ee..00b5d445f 100644
--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -46,6 +46,9 @@ class ProxyDatabase : public Database {
struct mpd_connection *connection;
Directory *root;
+ /* this is mutable because GetStats() must be "const" */
+ mutable time_t update_stamp;
+
public:
static Database *Create(const config_param &param,
Error &error);
@@ -71,6 +74,10 @@ public:
DatabaseStats &stats,
Error &error) const override;
+ virtual time_t GetUpdateStamp() const override {
+ return update_stamp;
+ }
+
private:
bool Configure(const config_param &param, Error &error);
@@ -237,6 +244,7 @@ ProxyDatabase::Open(Error &error)
return false;
root = Directory::NewRoot();
+ update_stamp = 0;
return true;
}
@@ -631,6 +639,8 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
if (stats2 == nullptr)
return CheckError(connection, error);
+ update_stamp = (time_t)mpd_stats_get_db_update_time(stats2);
+
stats.song_count = mpd_stats_get_number_of_songs(stats2);
stats.total_duration = mpd_stats_get_db_play_time(stats2);
stats.artist_count = mpd_stats_get_number_of_artists(stats2);
diff --git a/src/db/SimpleDatabasePlugin.hxx b/src/db/SimpleDatabasePlugin.hxx
index 24e150a97..dfe981dd8 100644
--- a/src/db/SimpleDatabasePlugin.hxx
+++ b/src/db/SimpleDatabasePlugin.hxx
@@ -26,8 +26,6 @@
#include <cassert>
-#include <time.h>
-
struct Directory;
class SimpleDatabase : public Database {
@@ -55,11 +53,6 @@ public:
bool Save(Error &error);
- gcc_pure
- time_t GetLastModified() const {
- return mtime;
- }
-
static Database *Create(const config_param &param,
Error &error);
@@ -85,6 +78,10 @@ public:
DatabaseStats &stats,
Error &error) const override;
+ virtual time_t GetUpdateStamp() const override {
+ return mtime;
+ }
+
protected:
bool Configure(const config_param &param, Error &error);
diff --git a/src/decoder/DsdiffDecoderPlugin.cxx b/src/decoder/DsdiffDecoderPlugin.cxx
index 347f5b586..a3c0149b9 100644
--- a/src/decoder/DsdiffDecoderPlugin.cxx
+++ b/src/decoder/DsdiffDecoderPlugin.cxx
@@ -294,7 +294,6 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
if (!dsdiff_read_chunk_header(decoder, is, chunk_header))
return false;
}
- chunk_size = 0;
}
/* done processing chunk headers, process tags if any */
@@ -385,10 +384,10 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is,
while (chunk_size > 0) {
/* see how much aligned data from the remaining chunk
fits into the local buffer */
- unsigned now_frames = buffer_frames;
size_t now_size = buffer_size;
if (chunk_size < (uint64_t)now_size) {
- now_frames = (unsigned)chunk_size / frame_size;
+ unsigned now_frames =
+ (unsigned)chunk_size / frame_size;
now_size = now_frames * frame_size;
}
diff --git a/src/decoder/DsfDecoderPlugin.cxx b/src/decoder/DsfDecoderPlugin.cxx
index 0507f5047..5ef94e647 100644
--- a/src/decoder/DsfDecoderPlugin.cxx
+++ b/src/decoder/DsfDecoderPlugin.cxx
@@ -240,10 +240,10 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
while (chunk_size > 0) {
/* see how much aligned data from the remaining chunk
fits into the local buffer */
- unsigned now_frames = buffer_frames;
size_t now_size = buffer_size;
if (chunk_size < (uint64_t)now_size) {
- now_frames = (unsigned)chunk_size / frame_size;
+ unsigned now_frames =
+ (unsigned)chunk_size / frame_size;
now_size = now_frames * frame_size;
}
diff --git a/src/decoder/OggFind.cxx b/src/decoder/OggFind.cxx
index 821f75ca8..65c7fa3ce 100644
--- a/src/decoder/OggFind.cxx
+++ b/src/decoder/OggFind.cxx
@@ -22,6 +22,8 @@
#include "OggSyncState.hxx"
#include "util/Error.hxx"
+#include <stdio.h>
+
bool
OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet)
{
diff --git a/src/input/CurlInputPlugin.cxx b/src/input/CurlInputPlugin.cxx
index 841db6ceb..b78545951 100644
--- a/src/input/CurlInputPlugin.cxx
+++ b/src/input/CurlInputPlugin.cxx
@@ -273,12 +273,27 @@ public:
SocketAction(CURL_SOCKET_TIMEOUT, 0);
}
+ /**
+ * This is a kludge to allow pausing/resuming a stream with
+ * libcurl < 7.32.0. Read the curl_easy_pause manpage for
+ * more information.
+ */
+ void ResumeSockets() {
+ int running_handles;
+ curl_multi_socket_all(multi, &running_handles);
+ }
+
private:
static int TimerFunction(CURLM *multi, long timeout_ms, void *userp);
virtual void OnTimeout() override;
};
+/**
+ * libcurl version number encoded in a 24 bit integer.
+ */
+static unsigned curl_version_num;
+
/** libcurl should accept "ICY 200 OK" */
static struct curl_slist *http_200_aliases;
@@ -330,6 +345,13 @@ input_curl_resume(struct input_curl *c)
if (c->paused) {
c->paused = false;
curl_easy_pause(c->easy, CURLPAUSE_CONT);
+
+ if (curl_version_num < 0x072000)
+ /* libcurl older than 7.32.0 does not update
+ its sockets after curl_easy_pause(); force
+ libcurl to do it now */
+ curl_multi->ResumeSockets();
+
curl_multi->InvalidateSockets();
}
}
@@ -586,6 +608,16 @@ input_curl_init(const config_param &param, Error &error)
return false;
}
+ const auto version_info = curl_version_info(CURLVERSION_FIRST);
+ if (version_info != nullptr) {
+ FormatDebug(curl_domain, "version %s", version_info->version);
+ if (version_info->features & CURL_VERSION_SSL)
+ FormatDebug(curl_domain, "with %s",
+ version_info->ssl_version);
+
+ curl_version_num = version_info->version_num;
+ }
+
http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");
proxy = param.GetBlockValue("proxy");
diff --git a/src/pcm/PcmResample.cxx b/src/pcm/PcmResample.cxx
index 318181e15..b30e01407 100644
--- a/src/pcm/PcmResample.cxx
+++ b/src/pcm/PcmResample.cxx
@@ -148,3 +148,26 @@ PcmResampler::Resample32(unsigned channels, unsigned src_rate,
src_rate, src_buffer, src_size,
dest_rate, dest_size_r);
}
+
+const int32_t *
+PcmResampler::Resample24(unsigned channels, unsigned src_rate,
+ const int32_t *src_buffer, size_t src_size,
+ unsigned dest_rate, size_t *dest_size_r,
+ Error &error_r)
+{
+#ifdef HAVE_LIBSAMPLERATE
+ if (pcm_resample_lsr_enabled())
+ return pcm_resample_lsr_24(this, channels,
+ src_rate, src_buffer, src_size,
+ dest_rate, dest_size_r,
+ error_r);
+#else
+ (void)error_r;
+#endif
+
+ /* reuse the 32 bit code - the resampler code doesn't care if
+ the upper 8 bits are actually used */
+ return pcm_resample_fallback_32(buffer, channels,
+ src_rate, src_buffer, src_size,
+ dest_rate, dest_size_r);
+}
diff --git a/src/pcm/PcmResample.hxx b/src/pcm/PcmResample.hxx
index 8a740744a..e839d6ecd 100644
--- a/src/pcm/PcmResample.hxx
+++ b/src/pcm/PcmResample.hxx
@@ -124,13 +124,7 @@ struct PcmResampler {
const int32_t *Resample24(unsigned channels, unsigned src_rate,
const int32_t *src_buffer, size_t src_size,
unsigned dest_rate, size_t *dest_size_r,
- Error &error_r)
- {
- /* reuse the 32 bit code - the resampler code doesn't care if
- the upper 8 bits are actually used */
- return Resample32(channels, src_rate, src_buffer, src_size,
- dest_rate, dest_size_r, error_r);
- }
+ Error &error_r);
};
bool
diff --git a/src/pcm/PcmResampleInternal.hxx b/src/pcm/PcmResampleInternal.hxx
index 4219b22ed..94cef94ff 100644
--- a/src/pcm/PcmResampleInternal.hxx
+++ b/src/pcm/PcmResampleInternal.hxx
@@ -69,6 +69,15 @@ pcm_resample_lsr_32(PcmResampler *state,
unsigned dest_rate, size_t *dest_size_r,
Error &error);
+const int32_t *
+pcm_resample_lsr_24(PcmResampler *state,
+ unsigned channels,
+ unsigned src_rate,
+ const int32_t *src_buffer,
+ size_t src_size,
+ unsigned dest_rate, size_t *dest_size_r,
+ Error &error);
+
#endif
const int16_t *
diff --git a/src/pcm/PcmResampleLibsamplerate.cxx b/src/pcm/PcmResampleLibsamplerate.cxx
index 1986e8821..9eac2d545 100644
--- a/src/pcm/PcmResampleLibsamplerate.cxx
+++ b/src/pcm/PcmResampleLibsamplerate.cxx
@@ -19,6 +19,7 @@
#include "config.h"
#include "PcmResampleInternal.hxx"
+#include "PcmUtils.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -283,3 +284,27 @@ pcm_resample_lsr_32(PcmResampler *state,
return dest_buffer;
}
+
+const int32_t *
+pcm_resample_lsr_24(PcmResampler *state,
+ unsigned channels,
+ unsigned src_rate,
+ const int32_t *src_buffer, size_t src_size,
+ unsigned dest_rate, size_t *dest_size_r,
+ Error &error)
+{
+ const auto result = pcm_resample_lsr_32(state, channels,
+ src_rate, src_buffer, src_size,
+ dest_rate, dest_size_r,
+ error);
+ if (result != nullptr)
+ /* src_float_to_int_array() clamps for 32 bit
+ integers; now make sure everything's fine for 24
+ bit */
+ /* TODO: eliminate the 32 bit clamp to reduce overhead */
+ PcmClampN<int32_t, int32_t, 24>(const_cast<int32_t *>(result),
+ result,
+ *dest_size_r / sizeof(*result));
+
+ return result;
+}
diff --git a/src/pcm/PcmUtils.hxx b/src/pcm/PcmUtils.hxx
index 108ba85ae..febe12d7b 100644
--- a/src/pcm/PcmUtils.hxx
+++ b/src/pcm/PcmUtils.hxx
@@ -63,4 +63,16 @@ PcmClamp(U x)
return T(x);
}
+/**
+ * Check if the values in this buffer are within the range of the
+ * provided bit size, and clamps them whenever necessary.
+ */
+template<typename T, typename U, unsigned bits>
+static inline void
+PcmClampN(T *dest, const U *src, unsigned n)
+{
+ while (n-- > 0)
+ *dest++ = PcmClamp<T, U, bits>(*src++);
+}
+
#endif
diff --git a/src/system/ByteOrder.hxx b/src/system/ByteOrder.hxx
index 622003254..8beda61c7 100644
--- a/src/system/ByteOrder.hxx
+++ b/src/system/ByteOrder.hxx
@@ -33,11 +33,23 @@
#include <stdint.h>
#if defined(__i386__) || defined(__x86_64__) || defined(__ARMEL__)
-#define IS_LITTLE_ENDIAN true
-#define IS_BIG_ENDIAN false
+/* well-known little-endian */
+# define IS_LITTLE_ENDIAN true
+# define IS_BIG_ENDIAN false
+#elif defined(__MIPSEB__)
+/* well-known big-endian */
+# define IS_LITTLE_ENDIAN false
+# define IS_BIG_ENDIAN true
#else
-#define IS_LITTLE_ENDIAN false
-#define IS_BIG_ENDIAN true
+/* generic compile-time check */
+# include <endian.h>
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# define IS_LITTLE_ENDIAN true
+# define IS_BIG_ENDIAN false
+# else
+# define IS_LITTLE_ENDIAN false
+# define IS_BIG_ENDIAN true
+# endif
#endif
static inline constexpr bool
diff --git a/src/system/fd_util.h b/src/system/fd_util.h
index 9003b1616..b7a9a6dd3 100644
--- a/src/system/fd_util.h
+++ b/src/system/fd_util.h
@@ -104,6 +104,11 @@ socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]);
#endif
+#ifdef HAVE_LIBMPDCLIENT
+/* Avoid symbol conflict with statically linked libmpdclient */
+#define socket_cloexec_nonblock socket_cloexec_nonblock_noconflict
+#endif
+
/**
* Wrapper for socket(), which sets the CLOEXEC and the NONBLOCK flag
* (atomically if supported by the OS).