Compare commits

...

21 Commits

Author SHA1 Message Date
Max Kellermann
82e261ad33 release v0.19.12 2015-12-15 21:54:42 +01:00
Benno Fünfstück
cae2811762 fix mpd crash on invalid utf8 stream title 2015-12-15 21:49:53 +01:00
Ben Boeckel
09112c6869 docs: add vlc and mpv to the list of example applications
These are other popular clients. In particular, VLC is available on
mobile devices.

Signed-off-by: Ben Boeckel <mathstuf@gmail.com>
2015-12-15 21:30:26 +01:00
Christian Hesse
77aaf1baee fix LimitRTTIME in systemd unit file
systemd does not understand LimitRTTIME=-1. For no limit we have to use
the string 'infinity' (see systemd.exec(5)).

Signed-off-by: Christian Hesse <mail@eworm.de>
2015-12-15 21:17:04 +01:00
Jörg Krause
6626c2d00d Makefile.am: fix static build with alsa
Add ALSA_LIBS to MIXER_LIBS, otherwise building mpd in a static context fails
with lot of undefined references to alsa-lib (libasound) required by
src/mixer/plugins/AlsaMixerPlugin.cxx.

Signed-off-by: Jörg Krause <joerg.krause@embedded.rocks>
2015-12-15 21:16:45 +01:00
Michael Paquier
315f9d98f6 Main: fix build failure on non-Linux systems 2015-11-10 08:38:53 +01:00
Max Kellermann
f087518e7a configure.ac: prepare for 0.19.12 2015-11-10 08:33:50 +01:00
Max Kellermann
db9997a106 release v0.19.11 2015-10-27 10:42:20 +01:00
Max Kellermann
0cbfb610f2 systemd: remove obsolete ControlGroup settings
This systemd feature has been removed a while ago without replacement,
and it turns out that systemd developers suggest not using control
groups at all to assign real-time privileges.  Therfore, a replacement
feature will not be implement in future systemd releases, and we can
really remove those lines completely.

See http://bugs.musicpd.org/view.php?id=4413
2015-10-27 10:36:23 +01:00
Max Kellermann
f901cd042b doc/user: section about real-time scheduling 2015-10-27 10:31:50 +01:00
Max Kellermann
5719207dfa gme: don't loop forever, fall back to GME's default play length
Fixes http://bugs.musicpd.org/view.php?id=4432
2015-10-26 17:16:20 +01:00
Max Kellermann
a84fbbe327 decoder/gme: free the gme_info_t as early as possible 2015-10-26 17:15:24 +01:00
Max Kellermann
93c97972b9 decoder/gme: call decoder_seek_error() on seek error 2015-10-26 16:32:39 +01:00
Max Kellermann
ac61d43720 output/Command: flush the mixer cache when enabling/disabling output
Fixes mixer lag (http://bugs.musicpd.org/view.php?id=4425).
2015-10-26 16:29:07 +01:00
Max Kellermann
1958f78cc1 decoder/ffmpeg: fix crash due to wrong avio_alloc_context() call
Allocate the buffer dynamically using av_malloc(), and free
AVIOContext.buffer in the destructor, as mandated by the libavformat
documentation.

Fixes http://bugs.musicpd.org/view.php?id=4446
2015-10-26 13:06:29 +01:00
Max Kellermann
a7ee64a25b decoder/mpcdec: use SampleTraits<SampleFormat::S24_P32>
Eliminates some duplicate code, and as a side effect, this works
around clang 3.8 compiler warning because a negative value was
shifted.
2015-10-16 18:12:32 +02:00
Max Kellermann
2a58f22649 decoder/mpcdec: use Clamp() 2015-10-16 18:11:42 +02:00
Max Kellermann
f066bb7716 unix/Daemon, playlist/...: remove unused Domain variables 2015-10-16 18:08:59 +02:00
Max Kellermann
4e3d182189 encoder/flac: fix crash with 32 bit playback
Copy to encoder->audio_format *after* adjusting the sample format to
S24_P32.

Fixes http://bugs.musicpd.org/view.php?id=4433
2015-10-16 18:05:34 +02:00
Max Kellermann
205fba74cf tag/ApeLoader: fix buffer overflow after unterminated key 2015-10-16 14:55:40 +02:00
Max Kellermann
a9bcf8d50d configure.ac: prepare for 0.19.11 2015-10-16 14:55:40 +02:00
19 changed files with 133 additions and 75 deletions

@@ -1219,6 +1219,7 @@ liboutput_plugins_a_SOURCES = \
MIXER_LIBS = \
libmixer_plugins.a \
$(ALSA_LIBS) \
$(PULSE_LIBS)
MIXER_API_SRC = \

16
NEWS

@@ -1,3 +1,19 @@
ver 0.19.12 (2015/12/15)
* fix assertion failure on malformed UTF-8 tag
* fix build failure on non-Linux systems
* fix LimitRTTIME in systemd unit file
ver 0.19.11 (2015/10/27)
* tags
- ape: fix buffer overflow
* decoder
- ffmpeg: fix crash due to wrong avio_alloc_context() call
- gme: don't loop forever, fall back to GME's default play length
* encoder
- flac: fix crash with 32 bit playback
* mixer
- fix mixer lag after enabling/disabling output
ver 0.19.10 (2015/06/21)
* input
- curl: fix deadlock on small responses

@@ -1,10 +1,10 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.19.10, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.19.12, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=19
VERSION_REVISION=10
VERSION_REVISION=12
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx])

@@ -1190,6 +1190,58 @@ database {
plugin).
</para>
</section>
<section id="realtime">
<title>Real-Time Scheduling</title>
<para>
On Linux, <application>MPD</application> attempts to configure
<ulink
url="https://en.wikipedia.org/wiki/Real-time_computing">real-time
scheduling</ulink> for some threads that benefit from it.
</para>
<para>
This is only possible you allow <application>MPD</application>
to do it. This privilege is controlled by
<varname>RLIMIT_RTPRIO</varname>
<varname>RLIMIT_RTTIME</varname>. You can configure this
privilege with <command>ulimit</command> before launching
<application>MPD</application>:
</para>
<programlisting>ulimit -HS -r 50; mpd</programlisting>
<para>
Or you can use the <command>prlimit</command> program from the
<application>util-linux</application> package:
</para>
<programlisting>prlimit --rtprio=50 --rttime=unlimited mpd</programlisting>
<para>
The <application>systemd</application> service file shipped
with <application>MPD</application> comes with this setting.
</para>
<para>
This works only if the Linux kernel was compiled with
<varname>CONFIG_RT_GROUP_SCHED</varname> disabled. Use the
following command to check this option for your current
kernel:
</para>
<programlisting>zgrep ^CONFIG_RT_GROUP_SCHED /proc/config.gz</programlisting>
<note>
<para>
There is a rumor that real-time scheduling improves audio
quality. That is not true. All it does is reduce the
probability of skipping (audio buffer xruns) when the
computer is under heavy load.
</para>
</note>
</section>
</chapter>
<chapter id="use">
@@ -2595,7 +2647,8 @@ buffer_size: 16384</programlisting>
/ <ulink
url="http://icecast.org/"><application>IceCast</application></ulink>.
HTTP streaming clients like
<application>mplayer</application> can connect to it.
<application>mplayer</application>, <application>VLC</application>,
and <application>mpv</application> can connect to it.
</para>
<para>

@@ -54,7 +54,6 @@
#include "system/FatalError.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "thread/Id.hxx"
#include "thread/Slack.hxx"
#include "lib/icu/Init.hxx"
@@ -123,8 +122,6 @@
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
static constexpr Domain main_domain("main");
#ifdef ANDROID
Context *context;
#endif
@@ -633,7 +630,7 @@ static int mpd_main_after_fork(struct options options)
config_get_unsigned(CONF_AUTO_UPDATE_DEPTH,
INT_MAX));
#else
FormatWarning(main_domain,
FormatWarning(config_domain,
"inotify: auto_update was disabled. enable during compilation phase");
#endif
}

@@ -92,14 +92,14 @@ struct AvioStream {
AVIOContext *io;
unsigned char buffer[8192];
AvioStream(Decoder *_decoder, InputStream &_input)
:decoder(_decoder), input(_input), io(nullptr) {}
~AvioStream() {
if (io != nullptr)
if (io != nullptr) {
av_free(io->buffer);
av_free(io);
}
}
bool Open();
@@ -153,11 +153,20 @@ mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
bool
AvioStream::Open()
{
io = avio_alloc_context(buffer, sizeof(buffer),
constexpr size_t BUFFER_SIZE = 8192;
auto buffer = (unsigned char *)av_malloc(BUFFER_SIZE);
if (buffer == nullptr)
return false;
io = avio_alloc_context(buffer, BUFFER_SIZE,
false, this,
mpd_ffmpeg_stream_read, nullptr,
input.IsSeekable()
? mpd_ffmpeg_stream_seek : nullptr);
/* If avio_alloc_context() fails, who frees the buffer? The
libavformat API documentation does not specify this, it
only says that AVIOContext.buffer must be freed in the end,
however no AVIOContext exists in that failure code path. */
return io != nullptr;
}

@@ -156,8 +156,11 @@ gme_file_decode(Decoder &decoder, Path path_fs)
return;
}
const SignedSongTime song_len = ti->length > 0
? SignedSongTime::FromMS(ti->length)
const int length = ti->play_length;
gme_free_info(ti);
const SignedSongTime song_len = length > 0
? SignedSongTime::FromMS(length)
: SignedSongTime::Negative();
/* initialize the MPD decoder */
@@ -168,7 +171,6 @@ gme_file_decode(Decoder &decoder, Path path_fs)
SampleFormat::S16, GME_CHANNELS,
error)) {
LogError(error);
gme_free_info(ti);
gme_delete(emu);
return;
}
@@ -179,8 +181,8 @@ gme_file_decode(Decoder &decoder, Path path_fs)
if (gme_err != nullptr)
LogWarning(gme_domain, gme_err);
if (ti->length > 0)
gme_set_fade(emu, ti->length);
if (length > 0)
gme_set_fade(emu, length);
/* play */
DecoderCommand cmd;
@@ -196,16 +198,17 @@ gme_file_decode(Decoder &decoder, Path path_fs)
if (cmd == DecoderCommand::SEEK) {
unsigned where = decoder_seek_time(decoder).ToMS();
gme_err = gme_seek(emu, where);
if (gme_err != nullptr)
if (gme_err != nullptr) {
LogWarning(gme_domain, gme_err);
decoder_command_finished(decoder);
decoder_seek_error(decoder);
} else
decoder_command_finished(decoder);
}
if (gme_track_ended(emu))
break;
} while (cmd != DecoderCommand::STOP);
gme_free_info(ti);
gme_delete(emu);
}
@@ -236,9 +239,9 @@ gme_scan_file(Path path_fs,
assert(ti != nullptr);
if (ti->length > 0)
if (ti->play_length > 0)
tag_handler_invoke_duration(handler, handler_ctx,
SongTime::FromMS(ti->length));
SongTime::FromMS(ti->play_length));
if (ti->song != nullptr) {
if (gme_track_count(emu) > 1) {

@@ -22,10 +22,12 @@
#include "../DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "CheckAudioFormat.hxx"
#include "pcm/Traits.hxx"
#include "tag/TagHandler.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/Macros.hxx"
#include "util/Clamp.hxx"
#include "Log.hxx"
#include <mpc/mpcdec.h>
@@ -42,6 +44,9 @@ struct mpc_decoder_data {
static constexpr Domain mpcdec_domain("mpcdec");
static constexpr SampleFormat mpcdec_sample_format = SampleFormat::S24_P32;
typedef SampleTraits<mpcdec_sample_format> MpcdecSampleTraits;
static mpc_int32_t
mpc_read_cb(mpc_reader *reader, void *ptr, mpc_int32_t size)
{
@@ -91,18 +96,15 @@ mpc_getsize_cb(mpc_reader *reader)
}
/* this _looks_ performance-critical, don't de-inline -- eric */
static inline int32_t
static inline MpcdecSampleTraits::value_type
mpc_to_mpd_sample(MPC_SAMPLE_FORMAT sample)
{
/* only doing 16-bit audio for now */
int32_t val;
MpcdecSampleTraits::value_type val;
enum {
bits = 24,
};
const int clip_min = -1 << (bits - 1);
const int clip_max = (1 << (bits - 1)) - 1;
constexpr int bits = MpcdecSampleTraits::BITS;
constexpr auto clip_min = MpcdecSampleTraits::MIN;
constexpr auto clip_max = MpcdecSampleTraits::MAX;
#ifdef MPC_FIXED_POINT
const int shift = bits - MPC_FIXED_POINT_SCALE_SHIFT;
@@ -117,16 +119,12 @@ mpc_to_mpd_sample(MPC_SAMPLE_FORMAT sample)
val = sample * float_scale;
#endif
if (val < clip_min)
val = clip_min;
else if (val > clip_max)
val = clip_max;
return val;
return Clamp(val, clip_min, clip_max);
}
static void
mpc_to_mpd_buffer(int32_t *dest, const MPC_SAMPLE_FORMAT *src,
mpc_to_mpd_buffer(MpcdecSampleTraits::pointer_type dest,
const MPC_SAMPLE_FORMAT *src,
unsigned num_samples)
{
while (num_samples-- > 0)
@@ -162,7 +160,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
Error error;
AudioFormat audio_format;
if (!audio_format_init_checked(audio_format, info.sample_freq,
SampleFormat::S24_P32,
mpcdec_sample_format,
info.channels, error)) {
LogError(error);
mpc_demux_exit(demux);
@@ -214,7 +212,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
mpc_uint32_t ret = frame.samples;
ret *= info.channels;
int32_t chunk[ARRAY_SIZE(sample_buffer)];
MpcdecSampleTraits::value_type chunk[ARRAY_SIZE(sample_buffer)];
mpc_to_mpd_buffer(chunk, sample_buffer, ret);
long bit_rate = vbr_update_bits * audio_format.sample_rate

@@ -157,8 +157,6 @@ flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
unsigned bits_per_sample;
encoder->audio_format = audio_format;
/* FIXME: flac should support 32bit as well */
switch (audio_format.format) {
case SampleFormat::S8:
@@ -178,6 +176,8 @@ flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
audio_format.format = SampleFormat::S24_P32;
}
encoder->audio_format = audio_format;
/* allocate the encoder */
encoder->fse = FLAC__stream_encoder_new();
if (encoder->fse == nullptr) {

@@ -26,7 +26,6 @@
#include "util/NumberParser.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
extern "C"
{
@@ -60,8 +59,6 @@ struct ShineEncoder {
bool WriteChunk(bool flush);
};
static constexpr Domain shine_encoder_domain("shine_encoder");
inline bool
ShineEncoder::Configure(const config_param &param,
gcc_unused Error &error)

@@ -26,7 +26,6 @@
#include "AudioFormat.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include <assert.h>
#include <string.h>
@@ -50,8 +49,6 @@ public:
Error &error) override;
};
static constexpr Domain volume_domain("pcm_volume");
static Filter *
volume_filter_init(gcc_unused const config_param &param,
gcc_unused Error &error)

@@ -25,13 +25,10 @@
#include "output/Internal.hxx"
#include "pcm/Volume.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
#include <assert.h>
static constexpr Domain mixer_domain("mixer");
static int
output_mixer_get_volume(const AudioOutput &ao)
{

@@ -30,6 +30,7 @@
#include "Internal.hxx"
#include "PlayerControl.hxx"
#include "mixer/MixerControl.hxx"
#include "mixer/Volume.hxx"
#include "Idle.hxx"
extern unsigned audio_output_state_version;
@@ -47,6 +48,11 @@ audio_output_enable_index(MultipleOutputs &outputs, unsigned idx)
ao.enabled = true;
idle_add(IDLE_OUTPUT);
if (ao.mixer != nullptr) {
InvalidateHardwareVolume();
idle_add(IDLE_MIXER);
}
ao.player_control->UpdateAudio();
++audio_output_state_version;
@@ -70,6 +76,7 @@ audio_output_disable_index(MultipleOutputs &outputs, unsigned idx)
Mixer *mixer = ao.mixer;
if (mixer != nullptr) {
mixer_close(mixer);
InvalidateHardwareVolume();
idle_add(IDLE_MIXER);
}
@@ -94,6 +101,7 @@ audio_output_toggle_index(MultipleOutputs &outputs, unsigned idx)
Mixer *mixer = ao.mixer;
if (mixer != nullptr) {
mixer_close(mixer);
InvalidateHardwareVolume();
idle_add(IDLE_MIXER);
}
}

@@ -22,7 +22,6 @@
#include "../OutputAPI.hxx"
#include "config/ConfigError.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include <string>
@@ -44,8 +43,6 @@ struct PipeOutput {
bool Configure(const config_param &param, Error &error);
};
static constexpr Domain pipe_output_domain("pipe_output");
inline bool
PipeOutput::Configure(const config_param &param, Error &error)
{

@@ -25,14 +25,11 @@
#include "input/InputStream.hxx"
#include "tag/TagBuilder.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "Log.hxx"
#include <string.h>
static constexpr Domain xspf_domain("xspf");
/**
* This is the state object for the GLib XML parser.
*/

@@ -78,12 +78,12 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
/* get the key */
const char *key = p;
while (remaining > size && *p != '\0') {
p++;
remaining--;
}
p++;
remaining--;
const char *key_end = (const char *)memchr(p, '\0', remaining);
if (key_end == nullptr)
break;
p = key_end + 1;
remaining -= p - key;
/* get the value */
if (remaining < size)

@@ -40,9 +40,9 @@ FindInvalidUTF8(const char *p, const char *const end)
/* now call the other SequenceLengthUTF8() overload
which also validates the continuations */
const size_t t = SequenceLengthUTF8(p);
assert(s == t);
if (t == 0)
return p;
assert(s == t);
p += s;
}

@@ -22,7 +22,6 @@
#include "system/FatalError.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
#include "util/Domain.hxx"
#include "PidFile.hxx"
#include "Log.hxx"
@@ -37,8 +36,6 @@
#include <grp.h>
#endif
static constexpr Domain daemon_domain("daemon");
#ifndef WIN32
/** the Unix user name which MPD runs as */

@@ -7,16 +7,7 @@ ExecStart=@prefix@/bin/mpd --no-daemon
# allow MPD to use real-time priority 50
LimitRTPRIO=50
LimitRTTIME=-1
# move MPD to a top-level cgroup, as real-time budget assignment fails
# in cgroup /system/mpd.service, because /system has a zero real-time
# budget; see
# http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime/
ControlGroup=cpu:/mpd
# assign a real-time budget
ControlGroupAttribute=cpu.rt_runtime_us 500000
LimitRTTIME=infinity
[Install]
WantedBy=multi-user.target