diff options
author | Max Kellermann <max@duempel.org> | 2013-11-23 18:45:02 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-11-23 18:45:02 +0100 |
commit | 99527051b5751d2ef7c6b593f1beda84d1bcc33f (patch) | |
tree | 39b08616c597fc173022164050ed557650c177b5 | |
parent | bed98303a346dd98e2a239579c032d170440441d (diff) | |
parent | 57e0cc54424561499039967aa501c17d4b179019 (diff) | |
download | mpd-99527051b5751d2ef7c6b593f1beda84d1bcc33f.tar.gz mpd-99527051b5751d2ef7c6b593f1beda84d1bcc33f.tar.xz mpd-99527051b5751d2ef7c6b593f1beda84d1bcc33f.zip |
Merge branch 'v0.18.x'
Diffstat (limited to '')
-rw-r--r-- | NEWS | 16 | ||||
-rw-r--r-- | configure.ac | 8 | ||||
-rw-r--r-- | src/DatabaseGlue.cxx | 6 | ||||
-rw-r--r-- | src/DatabasePlugin.hxx | 9 | ||||
-rw-r--r-- | src/DatabaseSimple.hxx | 16 | ||||
-rw-r--r-- | src/Mapper.cxx | 4 | ||||
-rw-r--r-- | src/Mapper.hxx | 3 | ||||
-rw-r--r-- | src/Stats.cxx | 62 | ||||
-rw-r--r-- | src/Stats.hxx | 20 | ||||
-rw-r--r-- | src/archive/Iso9660ArchivePlugin.cxx | 6 | ||||
-rw-r--r-- | src/db/ProxyDatabasePlugin.cxx | 10 | ||||
-rw-r--r-- | src/db/SimpleDatabasePlugin.hxx | 11 | ||||
-rw-r--r-- | src/decoder/DsdiffDecoderPlugin.cxx | 5 | ||||
-rw-r--r-- | src/decoder/DsfDecoderPlugin.cxx | 4 | ||||
-rw-r--r-- | src/decoder/OggFind.cxx | 2 | ||||
-rw-r--r-- | src/input/CurlInputPlugin.cxx | 32 | ||||
-rw-r--r-- | src/pcm/PcmResample.cxx | 23 | ||||
-rw-r--r-- | src/pcm/PcmResample.hxx | 8 | ||||
-rw-r--r-- | src/pcm/PcmResampleInternal.hxx | 9 | ||||
-rw-r--r-- | src/pcm/PcmResampleLibsamplerate.cxx | 25 | ||||
-rw-r--r-- | src/pcm/PcmUtils.hxx | 12 | ||||
-rw-r--r-- | src/system/ByteOrder.hxx | 20 | ||||
-rw-r--r-- | src/system/fd_util.h | 5 |
23 files changed, 224 insertions, 92 deletions
@@ -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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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). |