Compare commits

..

48 Commits

Author SHA1 Message Date
Max Kellermann
57e0cc5442 release v0.18.5 2013-11-23 18:30:12 +01:00
Max Kellermann
73f45d87d5 decoder/{dsf,dsdiff}: eliminate useless assignments 2013-11-23 18:30:12 +01:00
Max Kellermann
ae88ba986e archive/iso9660: eliminate useless assignments 2013-11-23 18:30:12 +01:00
Max Kellermann
d6247902ec input/curl: work around stream resume bug (fixed in libcurl 7.32.0) 2013-11-23 12:13:41 +01:00
Max Kellermann
a566c28a49 input/curl: add global variable "curl_version" 2013-11-23 12:08:46 +01:00
Max Kellermann
2eddb63a83 input/curl: dump version number 2013-11-23 12:02:39 +01:00
Max Kellermann
fc7d5b055d PcmResampleLibsamplerate: clip 24 bit data
Using pcm_resample_lsr_32() for 24 bit samples works, but may cause 24
bit overflows.  This commit makes 24 bit a special case with explicit
clipping.
2013-11-22 23:27:56 +01:00
Max Kellermann
87c8953e8e PcmResample: un-inline Resample24() 2013-11-22 23:24:40 +01:00
Max Kellermann
45d27a52f1 PcmUtils: add function PcmClampN() 2013-11-22 23:24:40 +01:00
Max Kellermann
d22acc59c9 db/proxy: implement method GetUpdateStamp() 2013-11-22 00:45:27 +01:00
Max Kellermann
c064e8d62f DatabasePlugin: add method GetUpdateStamp()
Refactor SimpleDatabase::GetLastModified() to be generic for all
plugins.  Remove the SimpleDatabase assumption from db_stats_print(),
allowing it to be implemented by all database plugins.
2013-11-22 00:35:29 +01:00
Max Kellermann
099a2cb586 Stats: print db statistics only if db is available
Fixes crash on "stats" in certain configurations.
2013-11-22 00:27:37 +01:00
Max Kellermann
042fe2a9d0 Stats: print more unsigned integers 2013-11-22 00:23:27 +01:00
Max Kellermann
ff1c1107f3 Stats: auto-reload statistics with proxy plugin 2013-11-22 00:19:28 +01:00
Max Kellermann
41a3fd0fd0 Stats: use struct DatabaseStats
Eliminate redundant declaration.
2013-11-22 00:12:12 +01:00
Max Kellermann
b9169a5670 Stats: move the GTimer variable out of struct stats 2013-11-22 00:10:53 +01:00
Max Kellermann
2ecd5fa28d Stats: don't export the global variable "stats"
Unused outside of Stats.cxx.
2013-11-22 00:08:43 +01:00
Max Kellermann
e719b6cc41 Stats: print db_update as unsigned integer 2013-11-22 00:04:58 +01:00
Max Kellermann
67b8124a1d Mapper: _get_music_directory_utf8() may return nullptr
If no music_directory is configured, return nullptr instead of an
empty string.  This fixes a crash when db_file is configured without
music_directory.
2013-11-22 00:02:17 +01:00
Florian Schlichting
51ec499c89 system/ByteOrder: testing for endianness in a more general way
Fixes build tests on ia64 and mipsel by testing for endianness in a
more general / portable way.
2013-11-21 23:04:49 +01:00
Max Kellermann
3a4df25db2 util/ByteOrder: add comments 2013-11-21 23:04:31 +01:00
Max Kellermann
37cf78ef45 util/ByteOrder: indent the preprocessor directives
Improve readability.
2013-11-21 23:03:28 +01:00
Max Kellermann
727c622659 configure.ac: auto-detect fluidsynth by default
The option "--enable-fluidsynth" was documented to be "auto" by
default, when it was really "no".
2013-11-21 22:50:58 +01:00
Max Kellermann
74a778e65f configure.ac: prepare for 0.18.5 2013-11-18 20:03:30 +01:00
Denis Krjuchkov
1fc0c9fe8a NEWS: add version 0.18.5 change log 2013-11-18 16:40:00 +06:00
Denis Krjuchkov
740d8ec5ab system/fd_util.h: avoid symbol conflict with statically linked libmpdclient 2013-11-18 16:35:22 +06:00
Denis Krjuchkov
0bcc477d46 decoder/OggFind.cxx: include stdio.h for SEEK_END definition 2013-11-18 16:28:39 +06:00
Max Kellermann
35297f8d4f release v0.18.4 2013-11-13 18:26:01 +01:00
Max Kellermann
6f4202408c doc/example: remove "format" and "audio_output_format"
Just an attempt to prevent users from shooting themselves in the foot
by uncommenting these lines without knowing what they're doing.
2013-11-11 17:18:29 +01:00
Max Kellermann
0b6548a282 util/RefCount: no "constexpr" with libc++
Not supported by libc++.
2013-11-11 12:27:16 +01:00
Max Kellermann
faf5821816 util/LazyRandomEngine: make min()/max() static+constexpr
Required for building with libc++.
2013-11-11 12:27:15 +01:00
Max Kellermann
188673b746 output/httpd: don't use incomplete template argument with libc++ 2013-11-11 08:31:50 +01:00
Max Kellermann
287c70e361 filter/route, ...: add missing stdlib.h includes 2013-11-11 08:20:09 +01:00
Max Kellermann
f6b44af998 DespotifyUtils: add missing stdio.h include 2013-11-11 08:20:09 +01:00
Max Kellermann
84c3d9674f DecoderAPI: add missing math.h include 2013-11-11 08:18:54 +01:00
Jurgen Kramer
47d3758820 decoder/dsdiff: fix byte order bug 2013-11-10 16:49:39 +01:00
Max Kellermann
573ff3a24f DecoderThread: add missing <functional> include 2013-11-09 09:54:12 +01:00
Max Kellermann
32fcc22cb3 configure.ac: prepare for 0.18.4 2013-11-09 09:52:51 +01:00
Max Kellermann
daba1238b5 release v0.18.3 2013-11-08 12:55:12 +01:00
Max Kellermann
d125567f4a doc/developer: add text from the wiki 2013-11-08 12:54:16 +01:00
Max Kellermann
993eca9327 Makefile.am: disable dist-bzip2
bzip2-compressed tarballs are obsolete, xz is better and widely
understood.
2013-11-08 12:29:56 +01:00
Max Kellermann
e314844a4d doc: show .tar.xz in sample unpack command 2013-11-08 12:29:04 +01:00
Max Kellermann
017bc564af doc: replace the remaining wikia links 2013-11-08 12:26:07 +01:00
Max Kellermann
e076ff9085 DecoderAPI: log without holding mutex 2013-11-08 12:15:05 +01:00
Max Kellermann
2789493a5f PlayerThread: fix stuck MPD after song change (0.18.2 regression)
Commit 77c63511 caused MPD to become stuck right after a song change.
The problem was that at some point, the MusicBuffer became full, and
the DecoderThread working on the next song waits for the PlayerThread.
However, the PlayerThread was stuck in a loop of g_usleep() calls, and
never bothered to tell the DecoderThread that the MusicBuffer is not
full anymore.  This bug is very old, but its chance to occur went from
nearly 0% to nearly 100%.

The fix is to wake up the DecoderThread before waiting for it.  As a
side effect, I replaced the g_usleep() call with a Cond::Wait() call.
2013-11-08 12:02:21 +01:00
Max Kellermann
4ed0635447 DecoderInternal: simplify need_chunks()
Remove the "do_wait" parameter which is always true.  Check only
command==NONE and merge the "return" statements.
2013-11-08 11:59:56 +01:00
Max Kellermann
1904e504be DecoderInternal: don't wake up player in need_chunks
Nothing of interest happens here.  No need to wake up the player.
2013-11-08 11:58:23 +01:00
Max Kellermann
834715ea2f configure.ac: prepare for 0.18.3 2013-11-08 11:57:37 +01:00
41 changed files with 367 additions and 151 deletions

17
INSTALL

@@ -3,9 +3,11 @@
Introduction
------------
This document is a very small amount of documentation about what is needed to
install MPD. If more information is desired see the community wiki at
http://mpd.wikia.com.
install MPD. If more information is desired, read the user manual:
http://www.musicpd.org/doc/user/
Dependencies
------------
@@ -161,13 +163,9 @@ Get the latest release from of MPD from <http://www.musicpd.org/>.
Compile
-------
1) unzip and untar the archive
1) unpack the archive
$ tar zxvf mpd-x.x.x.tar.gz
or
$ tar jxvf mpd-x.x.x.tar.bz2
$ tar xf mpd-x.x.x.tar.xz
2) change to directory created
@@ -208,6 +206,5 @@ Using MPD
---------
You can download many different interfaces for MPD at
<http://mpd.wikia.com/wiki/Clients>
MPD can be interfaced directly using telnet (see COMMANDS, if you are brave).
http://www.musicpd.org/clients/

@@ -1,5 +1,5 @@
ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = foreign 1.11 dist-bzip2 dist-xz subdir-objects
AUTOMAKE_OPTIONS = foreign 1.11 dist-xz subdir-objects
AM_CPPFLAGS += -I$(srcdir)/src $(GLIB_CFLAGS)

25
NEWS

@@ -1,3 +1,28 @@
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
* fix build failures due to missing includes
* libc++ compatibility
ver 0.18.3 (2013/11/08)
* fix stuck MPD after song change (0.18.2 regression)
ver 0.18.2 (2013/11/07)
* protocol:
- "close" flushes the output buffer

@@ -1,6 +1,6 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.2, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.18.5, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=18
@@ -8,7 +8,7 @@ VERSION_REVISION=0
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])
AM_INIT_AUTOMAKE([foreign 1.11 dist-bzip2 dist-xz subdir-objects])
AM_INIT_AUTOMAKE([foreign 1.11 dist-xz subdir-objects])
AM_SILENT_RULES
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_MACRO_DIR([m4])
@@ -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)

@@ -68,12 +68,28 @@ foo(const char *abc, int xyz)
<chapter>
<title>Hacking The Source</title>
<para>
MPD sources are managed in a git repository on <ulink
url="http://git.musicpd.org/">git.musicpd.org</ulink>.
</para>
<para>
Always write your code against the latest git:
</para>
<programlisting>git clone git://git.musicpd.org/master/mpd.git</programlisting>
<para>
If you already have a clone, update it:
</para>
<programlisting>git pull --rebase git://git.musicpd.org/master/mpd.git master</programlisting>
<para>
You can do without "--rebase", but we recommend that you rebase
your repository on the "master" repository all the time.
</para>
<para>
Configure with the options <option>--enable-debug
--enable-werror</option>. Enable as many plugins as possible,
@@ -83,8 +99,55 @@ foo(const char *abc, int xyz)
<para>
Don't mix several changes in one single patch. Create a
separate patch for every change. Tools like
<application>stgit</application> help you with that.
<application>stgit</application> help you with that. This way,
we can review your patches more easily, and we can pick the
patches we like most first.
</para>
<section>
<title> Basic stgit usage</title>
<para>
stgit allows you to create a set of patches and refine all of
them: you can go back to any patch at any time, and re-edit it
(both the code and the commit message). You can reorder
patches and insert new patches at any position. It encourages
creating separate patches for tiny changes.
</para>
<para>
stgit needs to be initialized on a git repository: stg init
</para>
<para>
Before you edit the code, create a patch: stg new
my-patch-name (stgit now asks you for the commit message).
</para>
<para>
Now edit the code. Once you're finished, you have to "refresh"
the patch, i.e. your edits are incorporated into the patch you
have created: stg refresh
</para>
<para>
You may now continue editing the same patch, and refresh it as
often as you like. Create more patches, edit and refresh them.
</para>
<para>
To view the list of patches, type stg series. To go back to a
specific patch, type stg goto my-patch-name; now you can
re-edit it (don't forget stg refresh when you're finished with
that patch).
</para>
<para>
When the whole patch series is finished, convert stgit patches
to git commits: stg commit
</para>
</section>
</chapter>
<chapter>

@@ -1,5 +1,5 @@
# An example configuration file for MPD
# See the mpd.conf man page for a more detailed description of each parameter.
# An example configuration file for MPD.
# Read the user manual for documentation: http://www.musicpd.org/doc/user/
# Files and directories #######################################################
@@ -204,16 +204,12 @@ input {
# blocks. Setting this block is optional, though the server will only attempt
# autodetection for one sound card.
#
# See <http://mpd.wikia.com/wiki/Configuration#Audio_Outputs> for examples of
# other audio outputs.
#
# An example of an ALSA output:
#
#audio_output {
# type "alsa"
# name "My ALSA Device"
## device "hw:0,0" # optional
## format "44100:16:2" # optional
## mixer_type "hardware" # optional
## mixer_device "default" # optional
## mixer_control "PCM" # optional
@@ -226,7 +222,6 @@ input {
# type "oss"
# name "My OSS Device"
## device "/dev/dsp" # optional
## format "44100:16:2" # optional
## mixer_type "hardware" # optional
## mixer_device "/dev/mixer" # optional
## mixer_control "PCM" # optional
@@ -330,12 +325,6 @@ input {
# mixer_type "none" # optional
#}
#
# This setting will change all decoded audio to be converted to the specified
# format before being passed to the audio outputs. By default, this setting is
# disabled.
#
#audio_output_format "44100:16:2"
#
# If MPD has been compiled with libsamplerate support, this setting specifies
# the sample rate converter to use. Possible values can be found in the
# mpd.conf man page or the libsamplerate documentation. By default, this is

@@ -67,11 +67,11 @@
<para>
Download the source tarball from <ulink
url="http://mpd.wikia.com/wiki/Server">the MPD home
url="http://www.musicpd.org/download.html">the MPD home
page</ulink> and unpack it:
</para>
<programlisting>tar xjf mpd-version.tar.bz
<programlisting>tar xf mpd-version.tar.xz
cd mpd-version</programlisting>
<para>
@@ -630,7 +630,7 @@ systemctl start mpd.socket</programlisting>
</para>
<para>
The <ulink url="http://mpd.wikia.com/wiki/Clients">MPD
The <ulink url="http://www.musicpd.org/clients/">MPD
Wiki</ulink> contains an extensive list of clients to choose
from.
</para>

@@ -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;
}

@@ -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 {

@@ -62,25 +62,13 @@ db_get_directory(const char *name);
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

@@ -35,6 +35,7 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void
decoder_initialized(Decoder &decoder,
@@ -283,11 +284,11 @@ decoder_read(Decoder *decoder,
assert(nbytes == 0 || !error.IsDefined());
assert(nbytes > 0 || error.IsDefined() || is.IsEOF());
is.Unlock();
if (gcc_unlikely(nbytes == 0 && error.IsDefined()))
LogError(error);
is.Unlock();
return nbytes;
}

@@ -42,20 +42,12 @@ Decoder::~Decoder()
* one.
*/
static DecoderCommand
need_chunks(DecoderControl &dc, bool do_wait)
need_chunks(DecoderControl &dc)
{
if (dc.command == DecoderCommand::STOP ||
dc.command == DecoderCommand::SEEK)
return dc.command;
if (do_wait) {
if (dc.command == DecoderCommand::NONE)
dc.Wait();
dc.client_cond.signal();
return dc.command;
}
return DecoderCommand::NONE;
return dc.command;
}
struct music_chunk *
@@ -80,7 +72,7 @@ decoder_get_chunk(Decoder &decoder)
}
dc.Lock();
cmd = need_chunks(dc, true);
cmd = need_chunks(dc);
dc.Unlock();
} while (cmd == DecoderCommand::NONE);

@@ -38,6 +38,8 @@
#include "tag/ApeReplayGain.hxx"
#include "Log.hxx"
#include <functional>
static constexpr Domain decoder_thread_domain("decoder_thread");
/**

@@ -28,6 +28,8 @@ extern "C" {
#include <despotify.h>
}
#include <stdio.h>
const Domain despotify_domain("despotify");
static struct despotify_session *g_session;

@@ -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 &

@@ -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 *

@@ -36,8 +36,6 @@
#include "util/Domain.hxx"
#include "Log.hxx"
#include <glib.h>
#include <string.h>
static constexpr Domain player_domain("player");
@@ -1043,8 +1041,14 @@ Player::Run()
output thread is still busy, so it's
okay */
/* XXX synchronize in a better way */
g_usleep(10000);
pc.Lock();
/* wake up the decoder (just in case it's
waiting for space in the MusicBuffer) and
wait for it */
dc.Signal();
dc.WaitForDecoder();
continue;
} else if (IsDecoderAtNextSong()) {
/* at the beginning of a new song */

@@ -30,6 +30,7 @@
#include "util/Domain.hxx"
#include <string.h>
#include <stdlib.h>
#define SONG_MTIME "mtime"
#define SONG_END "song_end"

@@ -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();
}
}
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: %u\n"
"db_playtime: %lu\n",
stats.artist_count,
stats.album_count,
stats.song_count,
stats.total_duration);
const time_t update_stamp = GetDatabase()->GetUpdateStamp();
if (update_stamp > 0)
client_printf(client,
"db_update: %lu\n",
(unsigned long)update_stamp);
}
void
stats_print(Client &client)
{
client_printf(client,
"artists: %u\n"
"albums: %u\n"
"songs: %i\n"
"uptime: %li\n"
"playtime: %li\n"
"db_playtime: %li\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);
"uptime: %lu\n"
"playtime: %lu\n",
(unsigned long)g_timer_elapsed(uptime, NULL),
(unsigned long)(client.player_control.GetTotalPlayTime() + 0.5));
if (db_is_simple())
client_printf(client,
"db_update: %li\n",
(long)db_get_mtime());
if (GetDatabase() != nullptr)
db_stats_print(client);
}

@@ -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);

@@ -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) {

@@ -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);

@@ -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);

@@ -47,6 +47,17 @@ public:
}
};
class DffDsdUint64 {
uint32_t hi;
uint32_t lo;
public:
constexpr uint64_t Read() const {
return (uint64_t(FromBE32(hi)) << 32) |
uint64_t(FromBE32(lo));
}
};
bool
dsdlib_read(Decoder *decoder, InputStream &is,
void *data, size_t length);

@@ -43,13 +43,13 @@
struct DsdiffHeader {
DsdId id;
DsdUint64 size;
DffDsdUint64 size;
DsdId format;
};
struct DsdiffChunkHeader {
DsdId id;
DsdUint64 size;
DffDsdUint64 size;
/**
* Read the "size" attribute from the specified header, converting it
@@ -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;
}

@@ -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;
}

@@ -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)
{

@@ -34,6 +34,7 @@
#include <glib.h>
#include <assert.h>
#include <stdlib.h>
struct opus_encoder {
/** the base class */

@@ -56,6 +56,7 @@
#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
class RouteFilter final : public Filter {
/**

@@ -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");

@@ -30,6 +30,11 @@
#include "thread/Mutex.hxx"
#include "event/ServerSocket.hxx"
#ifdef _LIBCPP_VERSION
/* can't use incomplete template arguments with libc++ */
#include "HttpdClient.hxx"
#endif
#include <forward_list>
struct config_param;

@@ -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(this, channels,
src_rate, src_buffer, src_size,
dest_rate, dest_size_r);
}

@@ -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

@@ -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 *

@@ -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;
}

@@ -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

@@ -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

@@ -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).

@@ -49,12 +49,12 @@ public:
*/
void AutoCreate();
result_type min() const {
return engine->min();
static constexpr result_type min() {
return std::mt19937::min();
}
result_type max() const {
return engine->max();
static constexpr result_type max() {
return std::mt19937::max();
}
result_type operator()() {

@@ -42,7 +42,12 @@ class RefCount {
std::atomic_uint n;
public:
constexpr RefCount():n(1) {}
#ifndef _LIBCPP_VERSION
/* the "constexpr" is missing in libc++'s "atomic"
implementation */
constexpr
#endif
RefCount():n(1) {}
void Increment() {
++n;

@@ -36,6 +36,7 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
static void