Compare commits

...

82 Commits

Author SHA1 Message Date
Max Kellermann
05ad335ae9 release v0.18.7 2014-01-13 11:39:27 +01:00
Max Kellermann
7faeb2ff2b configure.ac: reject libmpcdec SV7 in configure script
Look for symbol "mpc_demux_init" which does not exist in SV7.  This
avoids build failures when SV7 was found by configure.ac.
2014-01-11 21:02:12 +01:00
Max Kellermann
fdd76b3461 decoder/faad: fix memory leak 2014-01-08 22:11:00 +01:00
Max Kellermann
e490e5d0ab playlist/pls: don't free stack buffer 2014-01-08 19:50:44 +01:00
Max Kellermann
3a05c421e0 doc/user: fix typo 2014-01-07 18:06:58 +01:00
Max Kellermann
afc70c120e util/UriUtil: uri_get_suffix() fails if name begins with dot
A file called ".jpg" is not a JPEG file with an empty name; it is
merely a hidden file.
2013-12-29 17:40:51 +01:00
Max Kellermann
d7f80eab68 configure.ac: improved check for libyajl 1.0
If we have libyajl 2.0.1 (without a pkg-config file), our configure.ac
would assume this is the libyajl 1.0 API, because the function
yajl_alloc() exists in both.  This commit changes the library check to
the function yajl_parse_complete() which was removed in the 2.0 API.
This fixes build failure with libyajl 2.0.1.
2013-12-29 14:12:33 +01:00
Max Kellermann
e30b356eb0 daemon: no initgroups() when already running as the configured user
We can assume that initgroups() would be a no-op in that case, however
initgroups() is not allowed for unprivileged users anyway.
2013-12-29 13:59:05 +01:00
Max Kellermann
09a0803116 Daemon: fix typo in comment 2013-12-29 13:59:05 +01:00
Max Kellermann
20ffedc745 Daemon: simplify nested "if" 2013-12-29 13:57:12 +01:00
Max Kellermann
0b1ad27ba8 Daemon: fix typo in cast 2013-12-29 13:47:29 +01:00
Max Kellermann
6a1b2f0387 configure.ac: prepare for 0.18.7 2013-12-29 10:40:59 +01:00
Max Kellermann
fb34519b96 release v0.18.6 2013-12-24 12:01:01 +01:00
Max Kellermann
91fed47648 PlayerThread: log the last song that was played 2013-12-24 11:58:10 +01:00
Max Kellermann
c05691b546 OutputControl: update both ReplayGainFilters
The "mode" of the second ReplayGainFilter was never set, and thus
replay gain was never applied to the new song during cross-fade.
2013-12-24 11:53:21 +01:00
Steven O'Brien
6b3b8c6f2e fix FfmpegDecoderPlugin to use relative timestamps 2013-12-20 22:28:33 +01:00
Max Kellermann
a191db84f2 util/Error: add missing <algorithm> include
For std::move().
2013-12-19 10:58:20 +01:00
Michal Smucr
e4d69f38b0 riff: recognize upper-case "ID3" chunk name
Some tagging libraries (eg. TagLib) produce that variant.
2013-12-19 09:35:54 +01:00
Max Kellermann
97fc001180 input/cdio: fix typo in #include path
Broken by commit 3b0fea5f
2013-12-17 08:58:00 +01:00
Max Kellermann
42a09ff17a mixer/alsa: fix deadlock
This deadlock was a regression by commit 8e38b4f8.  Since we currently
can't resolve this, let's revert the commit, and add a GLib specific
workaround for the build failure.
2013-12-15 19:07:25 +01:00
Max Kellermann
c170fed6f9 .gitignore: ignore "test-driver"
File generated by automake version 1.14.
2013-12-14 12:33:20 +01:00
Max Kellermann
8e38b4f83c mixer/alsa: use BlockingCall() instead of EventLoop::AddCall()
This is safer, and works without epoll().  Fixes a build failure with
uClibc, which does not support epoll().
2013-12-13 14:35:36 +01:00
Max Kellermann
db4ae19246 doc/mpd.conf.5: remove redundant documentation
The real and detailed documentation is in the user manual.
2013-12-11 21:04:28 +01:00
Max Kellermann
82a89c6bfe doc/user: document the "ao" output
Move from doc/mpd.conf.5.
2013-12-11 21:03:11 +01:00
Max Kellermann
166c70cab3 doc/user: document the "fifo" output
Move from doc/mpd.conf.5.
2013-12-11 20:58:06 +01:00
Max Kellermann
de78fe38c8 doc/user: document shout option "protocol" 2013-12-11 20:54:42 +01:00
mobidyc
96fa69ff6b SongUpdate: accept files without metadata
If the file was recognized by a decoder plugin, accept it - don't
require metadata.
2013-12-10 19:34:35 +01:00
Max Kellermann
39d94bd3ea TagFile: add return value API documentation 2013-12-10 19:32:26 +01:00
Lukas Stabe
695ca29274 output/osx: fix build failure 2013-12-10 19:19:31 +01:00
Max Kellermann
02e8da6c98 NEWS: add openal line 2013-12-10 19:19:27 +01:00
Lukas Stabe
0ea5f4ac3a output/openal: check __APPLE__ instead of HAVE_OSX
On OSX, the configure-flag --enable-osx is used to enable the
unsupported osx output. It sets the HAVE_OSX preprocessor define.

src/output/OpenALOutputPlugin.cxx uses this define to determine wether
it is building on OSX, and imports different headers (which have
nothing to do with the osx output) depending on wether or not it is
set.
2013-12-02 13:08:52 +01:00
Max Kellermann
47c50c079d decoder/ffmpeg: use IgnoreError instead of local Error instance 2013-11-28 00:05:26 +01:00
Gaetan Bisson
3b0fea5fae input/cdio_paranoia: support libcdio-paranoia 0.90 2013-11-27 08:25:17 +01:00
Max Kellermann
443516cdda configure.ac: prepare for 0.18.6 2013-11-27 08:25:17 +01:00
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
58 changed files with 556 additions and 312 deletions

1
.gitignore vendored

@@ -31,6 +31,7 @@ libtool
ltmain.sh
missing
mkinstalldirs
/test-driver
mpd
mpd.service
stamp-h1

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)

50
NEWS

@@ -1,3 +1,53 @@
ver 0.18.7 (2013/01/13)
* playlist
- pls: fix crash after parser error
- soundcloud: fix build failure with libyajl 2.0.1
* decoder
- faad: fix memory leak
- mpcdec: reject libmpcdec SV7 in configure script
* daemon: don't initialize supplementary groups when already running
as the configured user
ver 0.18.6 (2013/12/24)
* input
- cdio_paranoia: support libcdio-paranoia 0.90
* tags
- riff: recognize upper-case "ID3" chunk name
* decoder
- ffmpeg: use relative timestamps
* output
- openal: fix build failure on Mac OS X
- osx: fix build failure
* mixer
- alsa: fix build failure with uClibc
* fix replay gain during cross-fade
* accept files without metadata
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.7, 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])
@@ -732,7 +732,7 @@ dnl --------------------------------- Soundcloud ------------------------------
if test x$enable_soundcloud != xno; then
PKG_CHECK_MODULES([YAJL], [yajl >= 2.0],
[found_soundcloud=yes],
AC_CHECK_LIB([yajl], [yajl_alloc],
AC_CHECK_LIB([yajl], [yajl_parse_complete],
[found_soundcloud=yes YAJL_CFLAGS=-DHAVE_YAJL1 YAJL_LIBS=-lyajl],
[found_soundcloud=no]))
fi
@@ -749,6 +749,7 @@ MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia],
if test x$enable_cdio_paranoia = xyes; then
AC_DEFINE([ENABLE_CDIO_PARANOIA], 1,
[Define to enable libcdio_paranoia support])
AC_CHECK_HEADERS(cdio/paranoia/paranoia.h)
fi
AM_CONDITIONAL(ENABLE_CDIO_PARANOIA, test x$enable_cdio_paranoia = xyes)
@@ -874,10 +875,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)
@@ -957,7 +960,7 @@ AM_CONDITIONAL(ENABLE_SNDFILE, test x$enable_sndfile = xyes)
dnl --------------------------------- musepack --------------------------------
MPD_AUTO_LIB(mpc, MPCDEC, mpcdec, main, [-lmpcdec], [],
MPD_AUTO_LIB(mpc, MPCDEC, mpcdec, mpc_demux_init, [-lmpcdec], [],
[mpcdec], [libmpcdec not found])
if test x$enable_mpc = xyes; then
AC_DEFINE(HAVE_MPCDEC, 1, [Define to use libmpcdec for MPC decoding])

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

@@ -363,137 +363,6 @@ errors on bandwidth-limited devices. Some users have reported good results
with this set to 50000, but not all devices support values this high. Most
users do not need to change this. The default is 256000000 / sample_rate(kHz),
or 5804 microseconds for CD-quality audio.
.SH OPTIONAL OSS OUTPUT PARAMETERS
.TP
.B device <dev>
This specifies the device to use for audio output. The default is "/dev/dsp".
.TP
.B mixer_device <mixer dev>
This specifies which mixer to use. The default is "/dev/mixer".
.TP
.B mixer_control <mixer ctrl>
This specifies which mixer control to use (sometimes referred to as the
"device"). The default is to use the main PCM mixer. An example is "Pcm".
.SH OPTIONAL PULSE OUTPUT PARAMETERS
.TP
.B server <server list>
A space separated list of servers to try to connect to. See
<\fBhttp://www.pulseaudio.org/wiki/ServerStrings\fP> for more details. The
default is to let PulseAudio choose a server.
If you specify more than one server name, MPD tries to connect to one
after another until it successfully establishes a connection.
.TP
.B sink <sink>
The sink to output to. The default is to let PulseAudio choose a sink.
.SH OPTIONAL JACK OUTPUT PARAMETERS
.TP
.B client_name <name>
The client name to use when connecting to JACK. The output ports <name>:left
and <name>:right will also be created for the left and right channels,
respectively.
.TP
.B ports <left_port,right_port>
This specifies the left and right ports to connect to for the left and right
channels, respectively. The default is to let JACK choose a pair of ports.
.TP
.B ringbuffer_size <size in bytes>
This specifies the size of the ringbuffer in bytes. The default is 32768.
.SH OPTIONAL AO OUTPUT PARAMETERS
.TP
.B driver <driver>
This specifies the libao driver to use for audio output. Possible values
depend on what libao drivers are available. See
<\fBhttp://www.xiph.org/ao/doc/drivers.html\fP> for information on some
commonly used drivers. Typical values for Linux include "oss" and "alsa09".
The default is "default", which causes libao to select an appropriate plugin.
.TP
.B options <opts>
This specifies the options to use for the selected libao driver. For oss, the
only option available is "dsp". For alsa09, the available options are: "dev",
"buf_size", and "periods". See <\fBhttp://www.xiph.org/ao/doc/drivers.html\fP>
for available options for some commonly used drivers. Options are assigned
using "=", and ";" is used to separate options. An example for oss:
"dsp=/dev/dsp". An example for alsa09: "dev=hw:0,0;buf_size=4096". The
default is "".
.TP
.B write_size <size in bytes>
This specifies how many bytes to write to the audio device at once. This
parameter is to work around a bug in older versions of libao on sound cards
with very small buffers. The default is 1024.
.SH REQUIRED FIFO OUTPUT PARAMETERS
.TP
.B path <path>
This specifies the path of the FIFO to output to. Must be an absolute path.
If the path does not exist it will be created when mpd is started, and removed
when mpd is stopped. The FIFO will be created with the same user and group as
mpd is running as. Default permissions can be modified by using the builtin
shell command "umask". If a FIFO already exists at the specified path it will
be reused, and will \fBnot\fP be removed when mpd is stopped. You can use the
"mkfifo" command to create this, and then you may modify the permissions to
your liking.
.SH REQUIRED SHOUT OUTPUT PARAMETERS
.TP
.B name <name>
This specifies not only the unique audio output name, but also the stream
title.
.TP
.B host <hostname>
This specifies the hostname of the icecast server to connect to.
.TP
.B port <port>
This specifies the port of the icecast server to connect to.
.TP
.B mount <mountpoint>
This specifies the icecast mountpoint to use.
.TP
.B password <password>
This specifies the password to use when logging in to the icecast server.
.TP
.B quality <quality>
This specifies the encoding quality to use. The value must be between 0
and 10. Fractional values, such as 2.5, are permitted. Either the quality or
the bitrate parameter must be specified, but not both. For Ogg, a
higher quality number produces higher quality output. For MP3, it's
just the opposite, with lower numbers producing higher quality output.
.TP
.B bitrate <kbps>
This specifies the bitrate to use for encoding. Either the quality or the
bitrate parameter must be specified, but not both.
.TP
.B format <sample_rate:bits:channels>
This specifies the sample rate, bits per sample, and number of channels to use
for encoding.
.SH OPTIONAL SHOUT OUTPUT PARAMETERS
.TP
.B encoding <encoding>
This specifies which output encoding to use. Should be either "ogg"
or "mp3", "mp3" is needed for shoutcast streaming. The default is "ogg".
.TP
.B protocol <protocol>
This specifies the protocol that wil be used to connect to the
icecast/shoutcast server. The options are "shoutcast", "icecast1" and
"icecast2". The default is "icecast2".
.TP
.B user <username>
This specifies the username to use when logging in to the icecast server. The
default is "source".
.TP
.B public <yes or no>
This specifies whether to request that the stream be listed in all public
stream directories that the icecast server knows about. The default is no.
.TP
.B timeout <seconds>
This specifies the number of seconds to wait before giving up on trying to
connect to the icecast server. The default is 2 seconds.
.TP
.B description <description>
This specifies a description of the stream.
.TP
.B url <url>
This specifies a URL associated with the stream.
.TP
.B genre <genre>
This specifies the genre(s) of the stream.
.SH FILES
.TP
.BI ~/.mpdconf

@@ -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>
@@ -829,7 +829,7 @@ systemctl start mpd.socket</programlisting>
<tbody>
<row>
<entry>
<varname>default_bute_order</varname>
<varname>default_byte_order</varname>
<parameter>little_endian|big_endian</parameter>
</entry>
<entry>
@@ -1398,6 +1398,59 @@ systemctl start mpd.socket</programlisting>
The <varname>ao</varname> plugin uses the portable
<filename>libao</filename> library.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>driver</varname>
<parameter>D</parameter>
</entry>
<entry>
The <filename>libao</filename> driver to use for
audio output. Possible values depend on what libao
drivers are available. See <ulink
url="http://www.xiph.org/ao/doc/drivers.html">http://www.xiph.org/ao/doc/drivers.html</ulink>
for information on some commonly used drivers.
Typical values for Linux include "oss" and "alsa09".
The default is "default", which causes libao to
select an appropriate plugin.
</entry>
</row>
<row>
<entry>
<varname>options</varname>
<parameter>O</parameter>
</entry>
<entry>
Options to pass to the selected
<filename>libao</filename> driver.
</entry>
</row>
<row>
<entry>
<varname>write_size</varname>
<parameter>O</parameter>
</entry>
<entry>
This specifies how many bytes to write to the audio
device at once. This parameter is to work around a
bug in older versions of libao on sound cards with
very small buffers. The default is 1024.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
@@ -1408,6 +1461,38 @@ systemctl start mpd.socket</programlisting>
FIFO (First In, First Out) file. The data can be read by
another program.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>path</varname>
<parameter>P</parameter>
</entry>
<entry>
This specifies the path of the FIFO to write to.
Must be an absolute path. If the path does not
exist, it will be created when MPD is started, and
removed when MPD is stopped. The FIFO will be
created with the same user and group as MPD is
running as. Default permissions can be modified by
using the builtin shell command "umask". If a FIFO
already exists at the specified path it will be
reused, and will not be removed when MPD is stopped.
You can use the "mkfifo" command to create this, and
then you may modify the permissions to your liking.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
@@ -1883,6 +1968,18 @@ systemctl start mpd.socket</programlisting>
Defaults to 2 seconds.
</entry>
</row>
<row>
<entry>
<varname>protocol</varname>
<parameter>icecast2|icecast1|shoutcast</parameter>
</entry>
<entry>
Specifies the protocol that wil be used to connect
to the icecast/shoutcast server. The default
is "<parameter>icecast2</parameter>".
</entry>
</row>
<row>
<entry>
<varname>mount</varname>

@@ -52,7 +52,7 @@ static char *user_name;
static uid_t user_uid = (uid_t)-1;
/** the Unix group id which MPD runs as */
static gid_t user_gid = (pid_t)-1;
static gid_t user_gid = (gid_t)-1;
/** the absolute path of the pidfile */
static AllocatedPath pidfile = AllocatedPath::Null();
@@ -106,18 +106,21 @@ daemonize_set_user(void)
return;
/* set gid */
if (user_gid != (gid_t)-1 && user_gid != getgid()) {
if (setgid(user_gid) == -1) {
FormatFatalSystemError("Failed to set group %d",
(int)user_gid);
}
if (user_gid != (gid_t)-1 && user_gid != getgid() &&
setgid(user_gid) == -1) {
FormatFatalSystemError("Failed to set group %d",
(int)user_gid);
}
#ifdef _BSD_SOURCE
/* init suplementary groups
/* init supplementary groups
* (must be done before we change our uid)
*/
if (!had_group && initgroups(user_name, user_gid) == -1) {
if (!had_group &&
/* no need to set the new user's supplementary groups if
we are already this user */
user_uid != getuid() &&
initgroups(user_name, user_gid) == -1) {
FormatFatalSystemError("Failed to set supplementary groups "
"of user \"%s\"",
user_name);

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

@@ -101,6 +101,8 @@ audio_output_set_replay_gain_mode(struct audio_output *ao,
{
if (ao->replay_gain_filter != nullptr)
replay_gain_filter_set_mode(ao->replay_gain_filter, mode);
if (ao->other_replay_gain_filter != nullptr)
replay_gain_filter_set_mode(ao->other_replay_gain_filter, mode);
}
void

@@ -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 */
@@ -1077,8 +1081,11 @@ Player::Run()
delete cross_fade_tag;
if (song != nullptr)
if (song != nullptr) {
const auto uri = song->GetURI();
FormatDefault(player_domain, "played \"%s\"", uri.c_str());
song->Free();
}
pc.Lock();

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

@@ -95,8 +95,7 @@ Song::UpdateFile()
TagBuilder tag_builder;
if (!tag_file_scan(path_fs,
&full_tag_handler, &tag_builder) ||
!tag_builder.IsDefined())
&full_tag_handler, &tag_builder))
return false;
if (tag_builder.IsEmpty())

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

@@ -28,6 +28,9 @@ struct tag_handler;
/**
* Scan the tags of a song file. Invokes matching decoder plugins,
* but does not invoke the special "APE" and "ID3" scanners.
*
* @return true if the file was recognized (even if no metadata was
* found)
*/
bool
tag_file_scan(Path path,

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

@@ -393,6 +393,7 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
if (!ret) {
LogError(error);
NeAACDecClose(decoder);
decoder_buffer_free(buffer);
return;
}
@@ -461,6 +462,7 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
/* cleanup */
NeAACDecClose(decoder);
decoder_buffer_free(buffer);
}
static bool

@@ -120,8 +120,7 @@ mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
if (whence == AVSEEK_SIZE)
return stream->input.size;
Error error;
if (!stream->input.LockSeek(pos, whence, error))
if (!stream->input.LockSeek(pos, whence, IgnoreError()))
return -1;
return stream->input.offset;
@@ -252,13 +251,14 @@ static DecoderCommand
ffmpeg_send_packet(Decoder &decoder, InputStream &is,
const AVPacket *packet,
AVCodecContext *codec_context,
const AVRational *time_base,
const AVStream *stream,
AVFrame *frame,
uint8_t **buffer, int *buffer_size)
{
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts, *time_base));
time_from_ffmpeg(packet->pts - stream->start_time,
stream->time_base));
AVPacket packet2 = *packet;
@@ -342,11 +342,9 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
PADDING = 16,
};
Error error;
unsigned char buffer[BUFFER_SIZE];
size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE);
if (nbytes <= PADDING || !is.LockRewind(error))
if (nbytes <= PADDING || !is.LockRewind(IgnoreError()))
return nullptr;
/* some ffmpeg parsers (e.g. ac3_parser.c) read a few bytes
@@ -473,7 +471,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
if (packet.stream_index == audio_stream)
cmd = ffmpeg_send_packet(decoder, input,
&packet, codec_context,
&av_stream->time_base,
av_stream,
frame,
&interleaved_buffer, &interleaved_buffer_size);
else
@@ -484,7 +482,8 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
if (cmd == DecoderCommand::SEEK) {
int64_t where =
time_to_ffmpeg(decoder_seek_where(decoder),
av_stream->time_base);
av_stream->time_base) +
av_stream->start_time;
if (av_seek_frame(format_context, audio_stream, where,
AV_TIME_BASE) < 0)

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

@@ -41,7 +41,12 @@
#include <glib.h>
#include <assert.h>
#ifdef HAVE_CDIO_PARANOIA_PARANOIA_H
#include <cdio/paranoia/paranoia.h>
#else
#include <cdio/paranoia.h>
#endif
#include <cdio/cd_types.h>
struct CdioParanoiaInputStream {

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

@@ -24,6 +24,7 @@
#include "Main.hxx"
#include "event/MultiSocketMonitor.hxx"
#include "event/Loop.hxx"
#include "event/Call.hxx"
#include "util/ASCII.hxx"
#include "util/ReusableArray.hxx"
#include "util/Error.hxx"
@@ -46,10 +47,22 @@ class AlsaMixerMonitor final : private MultiSocketMonitor {
public:
AlsaMixerMonitor(EventLoop &_loop, snd_mixer_t *_mixer)
:MultiSocketMonitor(_loop), mixer(_mixer) {
#ifdef USE_EPOLL
_loop.AddCall([this](){ InvalidateSockets(); });
#else
_loop.AddIdle(InitAlsaMixerMonitor, this);
#endif
}
private:
#ifndef USE_EPOLL
static gboolean InitAlsaMixerMonitor(gpointer data) {
AlsaMixerMonitor &amm = *(AlsaMixerMonitor *)data;
amm.InvalidateSockets();
return false;
}
#endif
virtual int PrepareSockets() override;
virtual void DispatchSockets() override;
};

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

@@ -363,9 +363,9 @@ osx_output_open(struct audio_output *ao, AudioFormat &audio_format,
OSStatus status = AudioUnitInitialize(od->au);
if (status != noErr) {
error.Set(osx_output_domain, status,
"Unable to initialize OS X audio unit: %s",
GetMacOSStatusCommentString(status));
error.Format(osx_output_domain, status,
"Unable to initialize OS X audio unit: %s",
GetMacOSStatusCommentString(status));
return false;
}

@@ -25,7 +25,7 @@
#include <glib.h>
#ifndef HAVE_OSX
#ifndef __APPLE__
#include <AL/al.h>
#include <AL/alc.h>
#else

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

@@ -68,7 +68,6 @@ pls_parser(GKeyFile *keyfile, std::forward_list<SongPointer> &songs)
FormatError(pls_domain, "Invalid PLS entry %s: '%s'",
key, error->message);
g_error_free(error);
g_free(key);
return;
}

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

@@ -87,7 +87,8 @@ riff_seek_id3(FILE *file)
/* pad byte */
++size;
if (memcmp(chunk.id, "id3 ", 4) == 0)
if (memcmp(chunk.id, "id3 ", 4) == 0 ||
memcmp(chunk.id, "ID3 ", 4) == 0)
/* found it! */
return size;

@@ -24,6 +24,7 @@
#include "Compiler.h"
#include <string>
#include <algorithm>
#include <assert.h>

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

@@ -32,7 +32,8 @@ const char *
uri_get_suffix(const char *uri)
{
const char *suffix = strrchr(uri, '.');
if (suffix == nullptr)
if (suffix == nullptr || suffix == uri ||
suffix[-1] == '/' || suffix[-1] == '\\')
return nullptr;
++suffix;

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

@@ -29,6 +29,10 @@ public:
"jpg"));
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo.png/bar.jpg"),
"jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix(".jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/.jpg"));
}
void TestRemoveAuth() {