Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fe45f28204 | ||
![]() |
861067412f | ||
![]() |
7eca886608 | ||
![]() |
79b6f9e89e | ||
![]() |
3d17c06777 | ||
![]() |
d6c08fb79f | ||
![]() |
ef02b20811 | ||
![]() |
8bf46a665e | ||
![]() |
c4fca2aa61 | ||
![]() |
87268c2297 | ||
![]() |
e93975cb46 | ||
![]() |
b6fa22bd84 | ||
![]() |
a0ef27a0cd | ||
![]() |
e304d0f8ee | ||
![]() |
ab7b38d4b9 | ||
![]() |
eaf675dc92 | ||
![]() |
57068e526c | ||
![]() |
c14a00eec9 | ||
![]() |
219c42522f | ||
![]() |
e3a0f15837 | ||
![]() |
a6bb27483b | ||
![]() |
7ada7def9e | ||
![]() |
421c4ae907 | ||
![]() |
4907f610d6 | ||
![]() |
f9d1bbbffb | ||
![]() |
86e8b3b4bd | ||
![]() |
a26ead035a | ||
![]() |
704be54c3a | ||
![]() |
2406152576 | ||
![]() |
af260b5a64 | ||
![]() |
4efa96df21 | ||
![]() |
8b62127770 | ||
![]() |
f06fe1ea98 | ||
![]() |
d16fb79708 | ||
![]() |
c38f29ce56 | ||
![]() |
78abcd7df7 | ||
![]() |
23dce21647 | ||
![]() |
40280fa6cf | ||
![]() |
fe9299ceff | ||
![]() |
c3f111a56c | ||
![]() |
250318329f | ||
![]() |
14c538c9c7 | ||
![]() |
abe4c57663 |
.gitignoreMakefile.amNEWSconfigure.ac
doc
src
CommandLine.cxxDecoderAPI.cxxDecoderInternal.cxxDecoderList.cxxDecoderThread.cxxOutputThread.cxxPlaylist.hxxPlaylistControl.cxx
command
decoder
AudiofileDecoderPlugin.cxxDsdiffDecoderPlugin.cxxDsfDecoderPlugin.cxxFfmpegDecoderPlugin.cxxGmeDecoderPlugin.cxx
event
notify.hxxoutput
playlist
protocol
system
thread
util
win32
test
3
.gitignore
vendored
3
.gitignore
vendored
@@ -40,7 +40,7 @@ tags
|
||||
.#*
|
||||
.stgit*
|
||||
src/dsd2pcm/dsd2pcm
|
||||
src/win/mpd_win32_rc.rc
|
||||
src/win32/mpd_win32_rc.rc
|
||||
doc/doxygen.conf
|
||||
doc/protocol.html
|
||||
doc/protocol
|
||||
@@ -63,6 +63,7 @@ test/run_normalize
|
||||
test/tmp
|
||||
test/run_inotify
|
||||
test/test_queue_priority
|
||||
test/test_protocol
|
||||
test/run_ntp_server
|
||||
test/run_resolver
|
||||
test/run_tcp_connect
|
||||
|
43
Makefile.am
43
Makefile.am
@@ -151,7 +151,7 @@ src_mpd_SOURCES = \
|
||||
src/IOThread.cxx src/IOThread.hxx \
|
||||
src/Main.cxx src/Main.hxx \
|
||||
src/Instance.cxx src/Instance.hxx \
|
||||
src/Win32Main.cxx \
|
||||
src/win32/Win32Main.cxx \
|
||||
src/GlobalEvents.cxx src/GlobalEvents.hxx \
|
||||
src/Daemon.cxx src/Daemon.hxx \
|
||||
src/AudioCompress/compress.c \
|
||||
@@ -211,14 +211,14 @@ src_mpd_SOURCES = \
|
||||
# Windows resource file
|
||||
#
|
||||
|
||||
src/win/mpd_win32_rc.$(OBJEXT): src/win/mpd_win32_rc.rc
|
||||
src/win32/mpd_win32_rc.$(OBJEXT): src/win32/mpd_win32_rc.rc
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
if HAVE_WINDOWS
|
||||
noinst_DATA = src/win/mpd_win32_rc.rc
|
||||
noinst_DATA = src/win32/mpd_win32_rc.rc
|
||||
|
||||
src_mpd_DEPENDENCIES = src/win/mpd_win32_rc.$(OBJEXT)
|
||||
src_mpd_LDFLAGS = -Wl,src/win/mpd_win32_rc.$(OBJEXT)
|
||||
EXTRA_src_mpd_DEPENDENCIES = src/win32/mpd_win32_rc.$(OBJEXT)
|
||||
src_mpd_LDFLAGS = -Wl,src/win32/mpd_win32_rc.$(OBJEXT)
|
||||
endif
|
||||
|
||||
if ENABLE_DESPOTIFY
|
||||
@@ -476,12 +476,6 @@ endif
|
||||
libdecoder_plugins_a_SOURCES = \
|
||||
src/decoder/PcmDecoderPlugin.cxx \
|
||||
src/decoder/PcmDecoderPlugin.hxx \
|
||||
src/decoder/DsdiffDecoderPlugin.cxx \
|
||||
src/decoder/DsdiffDecoderPlugin.hxx \
|
||||
src/decoder/DsfDecoderPlugin.cxx \
|
||||
src/decoder/DsfDecoderPlugin.hxx \
|
||||
src/decoder/DsdLib.cxx \
|
||||
src/decoder/DsdLib.hxx \
|
||||
src/DecoderBuffer.cxx src/DecoderBuffer.hxx \
|
||||
src/DecoderPlugin.cxx \
|
||||
src/DecoderList.cxx src/DecoderList.hxx
|
||||
@@ -525,6 +519,16 @@ DECODER_LIBS = \
|
||||
|
||||
DECODER_SRC =
|
||||
|
||||
if ENABLE_DSD
|
||||
libdecoder_plugins_a_SOURCES += \
|
||||
src/decoder/DsdiffDecoderPlugin.cxx \
|
||||
src/decoder/DsdiffDecoderPlugin.hxx \
|
||||
src/decoder/DsfDecoderPlugin.cxx \
|
||||
src/decoder/DsfDecoderPlugin.hxx \
|
||||
src/decoder/DsdLib.cxx \
|
||||
src/decoder/DsdLib.hxx
|
||||
endif
|
||||
|
||||
if HAVE_MAD
|
||||
libdecoder_plugins_a_SOURCES += \
|
||||
src/decoder/MadDecoderPlugin.cxx \
|
||||
@@ -1064,6 +1068,7 @@ C_TESTS = \
|
||||
test/test_mixramp \
|
||||
test/test_icy_parser \
|
||||
test/test_pcm \
|
||||
test/test_protocol \
|
||||
test/test_queue_priority
|
||||
|
||||
if ENABLE_ARCHIVE
|
||||
@@ -1538,6 +1543,16 @@ test_test_archive_LDADD = \
|
||||
$(GLIB_LIBS) \
|
||||
$(CPPUNIT_LIBS)
|
||||
|
||||
test_test_protocol_SOURCES = \
|
||||
src/protocol/ArgParser.cxx \
|
||||
test/test_protocol.cxx
|
||||
test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0
|
||||
test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations
|
||||
test_test_protocol_LDADD = \
|
||||
libsystem.a \
|
||||
libutil.a \
|
||||
$(CPPUNIT_LIBS)
|
||||
|
||||
test_test_queue_priority_SOURCES = \
|
||||
src/Queue.cxx \
|
||||
test/test_queue_priority.cxx
|
||||
@@ -1548,6 +1563,8 @@ test_test_queue_priority_LDADD = \
|
||||
libutil.a \
|
||||
$(CPPUNIT_LIBS)
|
||||
|
||||
if ENABLE_DSD
|
||||
|
||||
noinst_PROGRAMS += src/pcm/dsd2pcm/dsd2pcm
|
||||
|
||||
src_pcm_dsd2pcm_dsd2pcm_SOURCES = \
|
||||
@@ -1560,6 +1577,8 @@ src_pcm_dsd2pcm_dsd2pcm_LDADD = libutil.a
|
||||
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
#
|
||||
# Documentation
|
||||
@@ -1633,4 +1652,4 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
|
||||
test/test_archive_zzip.sh \
|
||||
$(wildcard scripts/*.sh) \
|
||||
$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
|
||||
src/win/mpd_win32_rc.rc.in src/win/mpd.ico
|
||||
src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico
|
||||
|
29
NEWS
29
NEWS
@@ -1,3 +1,32 @@
|
||||
ver 0.18.16 (2014/09/26)
|
||||
* fix DSD breakage due to typo in configure.ac
|
||||
|
||||
ver 0.18.15 (2014/09/26)
|
||||
* command
|
||||
- list: reset used size after the list has been processed
|
||||
* fix MixRamp
|
||||
* work around build failure on NetBSD
|
||||
|
||||
ver 0.18.14 (2014/09/11)
|
||||
* protocol
|
||||
- fix range parser bug on certain 32 bit architectures
|
||||
* decoder
|
||||
- audiofile: fix crash after seeking
|
||||
- ffmpeg: fix crash with ffmpeg/libav version 11
|
||||
- fix assertion failure after seeking
|
||||
|
||||
ver 0.18.13 (2014/08/31)
|
||||
* protocol
|
||||
- don't change song on "seekcur" in random mode
|
||||
* decoder
|
||||
- dsdiff, dsf: fix endless loop on malformed file
|
||||
- ffmpeg: support ffmpeg/libav version 11
|
||||
- gme: fix song duration
|
||||
* output
|
||||
- alsa: fix endless loop at end of file in dsd_usb mode
|
||||
* fix state file saver
|
||||
* fix build failure on Darwin
|
||||
|
||||
ver 0.18.12 (2014/07/30)
|
||||
* database
|
||||
- proxy: fix build failure with libmpdclient 2.2
|
||||
|
59
configure.ac
59
configure.ac
@@ -1,6 +1,6 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.18.12, mpd-devel@musicpd.org)
|
||||
AC_INIT(mpd, 0.18.16, mpd-devel@musicpd.org)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=18
|
||||
@@ -70,7 +70,7 @@ host_is_darwin=no
|
||||
case "$host_os" in
|
||||
mingw32* | windows*)
|
||||
AC_CONFIG_FILES([
|
||||
src/win/mpd_win32_rc.rc
|
||||
src/win32/mpd_win32_rc.rc
|
||||
])
|
||||
AC_CHECK_TOOL(WINDRES, windres)
|
||||
AM_CPPFLAGS="$AM_CPPFLAGS -DWIN32_LEAN_AND_MEAN"
|
||||
@@ -214,6 +214,11 @@ AC_ARG_ENABLE(documentation,
|
||||
[build documentation (default: disable)]),,
|
||||
[enable_documentation=no])
|
||||
|
||||
AC_ARG_ENABLE(dsd,
|
||||
AS_HELP_STRING([--enable-dsd],
|
||||
[enable DSD decoder (default: enable)]),,
|
||||
[enable_dsd=yes])
|
||||
|
||||
AC_ARG_ENABLE(ffmpeg,
|
||||
AS_HELP_STRING([--enable-ffmpeg],
|
||||
[enable FFMPEG support]),,
|
||||
@@ -846,6 +851,14 @@ if test x$enable_audiofile = xyes; then
|
||||
AC_DEFINE(HAVE_AUDIOFILE, 1, [Define for audiofile support])
|
||||
fi
|
||||
|
||||
dnl ----------------------------------- DSD -----------------------------------
|
||||
|
||||
if test x$enable_dsd = xyes; then
|
||||
AC_DEFINE(ENABLE_DSD, 1, [Define for the DSD decoder])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_DSD, test x$enable_dsd = xyes)
|
||||
|
||||
dnl ----------------------------------- FAAD ----------------------------------
|
||||
AM_PATH_FAAD()
|
||||
|
||||
@@ -1081,27 +1094,6 @@ AM_CONDITIONAL(ENABLE_WILDMIDI, test x$enable_wildmidi = xyes)
|
||||
|
||||
dnl ------------------------ Post Decoder Plugins Tests -----------------------
|
||||
|
||||
if
|
||||
test x$enable_aac = xno &&
|
||||
test x$enable_audiofile = xno &&
|
||||
test x$enable_ffmpeg = xno &&
|
||||
test x$enable_flac = xno &&
|
||||
test x$enable_fluidsynth = xno &&
|
||||
test x$enable_mad = xno &&
|
||||
test x$enable_mikmod = xno; then
|
||||
test x$enable_modplug = xno &&
|
||||
test x$enable_mpc = xno &&
|
||||
test x$enable_mpg123 = xno &&
|
||||
test x$enable_opus = xno &&
|
||||
test x$enable_sidplay = xno &&
|
||||
test x$enable_tremor = xno &&
|
||||
test x$enable_vorbis = xno &&
|
||||
test x$enable_wavpack = xno &&
|
||||
test x$enable_wildmidi = xno &&
|
||||
|
||||
AC_MSG_ERROR([No input plugins supported!])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_XIPH,
|
||||
test x$enable_vorbis = xyes || test x$enable_tremor = xyes || test x$enable_flac = xyes || test x$enable_opus = xyes)
|
||||
|
||||
@@ -1410,27 +1402,6 @@ esac
|
||||
|
||||
AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes)
|
||||
|
||||
dnl --------------------- Post Audio Output Plugins Tests ---------------------
|
||||
if
|
||||
test x$enable_alsa = xno &&
|
||||
test x$enable_roar = xno &&
|
||||
test x$enable_ao = xno &&
|
||||
test x$enable_fifo = xno &&
|
||||
test x$enable_httpd_output = xno &&
|
||||
test x$enable_jack = xno &&
|
||||
test x$enable_openal = xno &&
|
||||
test x$enable_oss = xno &&
|
||||
test x$enable_osx = xno &&
|
||||
test x$enable_pipe_output = xno &&
|
||||
test x$enable_pulse = xno &&
|
||||
test x$enable_recorder_output = xno &&
|
||||
test x$enable_shout = xno &&
|
||||
test x$enable_solaris_output = xno &&
|
||||
test x$enable_winmm_output = xno; then
|
||||
|
||||
AC_MSG_ERROR([No Audio Output types configured!])
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Documentation
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
@@ -576,7 +576,12 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>songs</varname>: number of albums
|
||||
<varname>albums</varname>: number of albums
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>songs</varname>: number of songs
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2013 The Music Player Daemon Project
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -69,7 +69,7 @@ static void version(void)
|
||||
puts("Music Player Daemon " VERSION "\n"
|
||||
"\n"
|
||||
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||
"Copyright (C) 2008-2013 Max Kellermann <max@duempel.org>\n"
|
||||
"Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
"\n"
|
||||
|
@@ -47,6 +47,7 @@ decoder_initialized(Decoder &decoder,
|
||||
|
||||
assert(dc.state == DecoderState::START);
|
||||
assert(dc.pipe != nullptr);
|
||||
assert(dc.pipe->IsEmpty());
|
||||
assert(decoder.stream_tag == nullptr);
|
||||
assert(decoder.decoder_tag == nullptr);
|
||||
assert(!decoder.seeking);
|
||||
@@ -405,6 +406,9 @@ decoder_data(Decoder &decoder,
|
||||
length == 0)
|
||||
return cmd;
|
||||
|
||||
assert(!decoder.initial_seek_pending);
|
||||
assert(!decoder.initial_seek_running);
|
||||
|
||||
/* send stream tags */
|
||||
|
||||
if (update_stream_tag(decoder, is)) {
|
||||
|
@@ -83,6 +83,9 @@ void
|
||||
decoder_flush_chunk(Decoder &decoder)
|
||||
{
|
||||
DecoderControl &dc = decoder.dc;
|
||||
assert(!decoder.seeking);
|
||||
assert(!decoder.initial_seek_running);
|
||||
assert(!decoder.initial_seek_pending);
|
||||
|
||||
assert(decoder.chunk != nullptr);
|
||||
|
||||
|
@@ -73,8 +73,10 @@ const struct DecoderPlugin *const decoder_plugins[] = {
|
||||
#ifdef HAVE_AUDIOFILE
|
||||
&audiofile_decoder_plugin,
|
||||
#endif
|
||||
#ifdef ENABLE_DSD
|
||||
&dsdiff_decoder_plugin,
|
||||
&dsf_decoder_plugin,
|
||||
#endif
|
||||
#ifdef HAVE_FAAD
|
||||
&faad_decoder_plugin,
|
||||
#endif
|
||||
|
@@ -26,6 +26,7 @@
|
||||
#include "Song.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "Mapper.hxx"
|
||||
#include "MusicPipe.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "DecoderAPI.hxx"
|
||||
@@ -418,9 +419,18 @@ decoder_task(void *arg)
|
||||
dc.replay_gain_prev_db = dc.replay_gain_db;
|
||||
dc.replay_gain_db = 0;
|
||||
|
||||
/* fall through */
|
||||
decoder_run(dc);
|
||||
break;
|
||||
|
||||
case DecoderCommand::SEEK:
|
||||
/* this seek was too late, and the decoder had
|
||||
already finished; start a new decoder */
|
||||
|
||||
/* we need to clear the pipe here; usually the
|
||||
PlayerThread is responsible, but it is not
|
||||
aware that the decoder has finished */
|
||||
dc.pipe->Clear(*dc.buffer);
|
||||
|
||||
decoder_run(dc);
|
||||
break;
|
||||
|
||||
|
@@ -385,11 +385,20 @@ ao_filter_chunk(struct audio_output *ao, const struct music_chunk *chunk,
|
||||
if (length > other_length)
|
||||
length = other_length;
|
||||
|
||||
float mix_ratio = chunk->mix_ratio;
|
||||
if (mix_ratio >= 0)
|
||||
/* reverse the mix ratio (because the
|
||||
arguments to pcm_mix() are reversed), but
|
||||
only if the mix ratio is non-negative; a
|
||||
negative mix ratio is a MixRamp special
|
||||
case */
|
||||
mix_ratio = 1.0 - mix_ratio;
|
||||
|
||||
void *dest = ao->cross_fade_buffer.Get(other_length);
|
||||
memcpy(dest, other_data, other_length);
|
||||
if (!pcm_mix(dest, data, length,
|
||||
ao->in_audio_format.format,
|
||||
1.0 - chunk->mix_ratio)) {
|
||||
mix_ratio)) {
|
||||
FormatError(output_domain,
|
||||
"Cannot cross-fade format %s",
|
||||
sample_format_to_string(ao->in_audio_format.format));
|
||||
|
@@ -234,6 +234,10 @@ public:
|
||||
|
||||
void PlayPrevious(PlayerControl &pc);
|
||||
|
||||
PlaylistResult SeekSongOrder(PlayerControl &pc,
|
||||
unsigned song_order,
|
||||
float seek_time);
|
||||
|
||||
PlaylistResult SeekSongPosition(PlayerControl &pc,
|
||||
unsigned song_position,
|
||||
float seek_time);
|
||||
|
@@ -190,17 +190,12 @@ playlist::PlayPrevious(PlayerControl &pc)
|
||||
}
|
||||
|
||||
PlaylistResult
|
||||
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
|
||||
playlist::SeekSongOrder(PlayerControl &pc, unsigned i, float seek_time)
|
||||
{
|
||||
if (!queue.IsValidPosition(song))
|
||||
return PlaylistResult::BAD_RANGE;
|
||||
assert(queue.IsValidOrder(i));
|
||||
|
||||
const Song *queued_song = GetQueuedSong();
|
||||
|
||||
unsigned i = queue.random
|
||||
? queue.PositionToOrder(song)
|
||||
: song;
|
||||
|
||||
pc.ClearError();
|
||||
stop_on_error = true;
|
||||
error_count = 0;
|
||||
@@ -228,6 +223,19 @@ playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
|
||||
return PlaylistResult::SUCCESS;
|
||||
}
|
||||
|
||||
PlaylistResult
|
||||
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
|
||||
{
|
||||
if (!queue.IsValidPosition(song))
|
||||
return PlaylistResult::BAD_RANGE;
|
||||
|
||||
unsigned i = queue.random
|
||||
? queue.PositionToOrder(song)
|
||||
: song;
|
||||
|
||||
return SeekSongOrder(pc, i, seek_time);
|
||||
}
|
||||
|
||||
PlaylistResult
|
||||
playlist::SeekSongId(PlayerControl &pc, unsigned id, float seek_time)
|
||||
{
|
||||
@@ -257,5 +265,5 @@ playlist::SeekCurrent(PlayerControl &pc, float seek_time, bool relative)
|
||||
if (seek_time < 0)
|
||||
seek_time = 0;
|
||||
|
||||
return SeekSongPosition(pc, current, seek_time);
|
||||
return SeekSongOrder(pc, current, seek_time);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ void
|
||||
CommandListBuilder::Reset()
|
||||
{
|
||||
list.clear();
|
||||
size = 0;
|
||||
mode = Mode::DISABLED;
|
||||
}
|
||||
|
||||
|
@@ -110,9 +110,9 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
|
||||
|
||||
Error error;
|
||||
if (is.LockSeek(offset, whence, error)) {
|
||||
LogError(error, "Seek failed");
|
||||
return is.GetOffset();
|
||||
} else {
|
||||
LogError(error, "Seek failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@@ -377,7 +377,7 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is,
|
||||
const unsigned buffer_samples = buffer_frames * frame_size;
|
||||
const size_t buffer_size = buffer_samples * sample_size;
|
||||
|
||||
while (chunk_size > 0) {
|
||||
while (chunk_size >= frame_size) {
|
||||
/* see how much aligned data from the remaining chunk
|
||||
fits into the local buffer */
|
||||
size_t now_size = buffer_size;
|
||||
|
@@ -238,7 +238,7 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
|
||||
const unsigned buffer_samples = buffer_frames * frame_size;
|
||||
const size_t buffer_size = buffer_samples * sample_size;
|
||||
|
||||
while (chunk_size > 0) {
|
||||
while (chunk_size >= frame_size) {
|
||||
/* see how much aligned data from the remaining chunk
|
||||
fits into the local buffer */
|
||||
size_t now_size = buffer_size;
|
||||
|
@@ -383,10 +383,23 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
|
||||
nbytes -= PADDING;
|
||||
|
||||
AVProbeData avpd;
|
||||
|
||||
/* new versions of ffmpeg may add new attributes, and leaving
|
||||
them uninitialized may crash; hopefully, zero-initializing
|
||||
everything we don't know is ok */
|
||||
memset(&avpd, 0, sizeof(avpd));
|
||||
|
||||
avpd.buf = buffer;
|
||||
avpd.buf_size = nbytes;
|
||||
avpd.filename = is.uri.c_str();
|
||||
|
||||
#ifdef AVPROBE_SCORE_MIME
|
||||
/* this attribute was added in libav/ffmpeg version 11, but
|
||||
unfortunately it's "uint8_t" instead of "char", and it's
|
||||
not "const" - wtf? */
|
||||
avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType());
|
||||
#endif
|
||||
|
||||
return av_probe_input_format(&avpd, true);
|
||||
}
|
||||
|
||||
@@ -433,9 +446,18 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
|
||||
AVStream *av_stream = format_context->streams[audio_stream];
|
||||
|
||||
AVCodecContext *codec_context = av_stream->codec;
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
|
||||
const AVCodecDescriptor *codec_descriptor =
|
||||
avcodec_descriptor_get(codec_context->codec_id);
|
||||
if (codec_descriptor != nullptr)
|
||||
FormatDebug(ffmpeg_domain, "codec '%s'",
|
||||
codec_descriptor->name);
|
||||
#else
|
||||
if (codec_context->codec_name[0] != 0)
|
||||
FormatDebug(ffmpeg_domain, "codec '%s'",
|
||||
codec_context->codec_name);
|
||||
#endif
|
||||
|
||||
AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);
|
||||
|
||||
|
@@ -235,7 +235,7 @@ gme_scan_file(const char *path_fs,
|
||||
|
||||
if (ti->length > 0)
|
||||
tag_handler_invoke_duration(handler, handler_ctx,
|
||||
ti->length / 100);
|
||||
ti->length / 1000);
|
||||
|
||||
if (ti->song != nullptr) {
|
||||
if (gme_track_count(emu) > 1) {
|
||||
|
@@ -118,7 +118,7 @@ BufferedSocket::OnSocketReady(unsigned flags)
|
||||
if (!ReadToBuffer() || !ResumeInput())
|
||||
return false;
|
||||
|
||||
if (input.IsFull())
|
||||
if (!input.IsFull())
|
||||
ScheduleRead();
|
||||
}
|
||||
|
||||
|
@@ -64,7 +64,9 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
|
||||
void
|
||||
TimeoutMonitor::Run()
|
||||
{
|
||||
#ifndef USE_EPOLL
|
||||
#ifdef USE_EPOLL
|
||||
active = false;
|
||||
#else
|
||||
Cancel();
|
||||
#endif
|
||||
|
||||
|
@@ -28,7 +28,7 @@ struct notify {
|
||||
Cond cond;
|
||||
bool pending;
|
||||
|
||||
#ifndef WIN32
|
||||
#if !defined(WIN32) && !defined(__NetBSD__)
|
||||
constexpr
|
||||
#endif
|
||||
notify():pending(false) {}
|
||||
|
@@ -802,6 +802,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
{
|
||||
AlsaOutput *ad = (AlsaOutput *)ao;
|
||||
|
||||
assert(size > 0);
|
||||
assert(size % ad->in_frame_size == 0);
|
||||
|
||||
if (ad->must_prepare) {
|
||||
@@ -814,11 +815,21 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
}
|
||||
}
|
||||
|
||||
const size_t original_size = size;
|
||||
chunk = ad->pcm_export->Export(chunk, size, size);
|
||||
if (size == 0)
|
||||
/* the DoP (DSD over PCM) filter converts two frames
|
||||
at a time and ignores the last odd frame; if there
|
||||
was only one frame (e.g. the last frame in the
|
||||
file), the result is empty; to avoid an endless
|
||||
loop, bail out here, and pretend the one frame has
|
||||
been played */
|
||||
return original_size;
|
||||
|
||||
assert(size % ad->out_frame_size == 0);
|
||||
|
||||
size /= ad->out_frame_size;
|
||||
assert(size > 0);
|
||||
|
||||
while (true) {
|
||||
snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size);
|
||||
|
@@ -727,6 +727,8 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
OssOutput *od = (OssOutput *)ao;
|
||||
ssize_t ret;
|
||||
|
||||
assert(size > 0);
|
||||
|
||||
/* reopen the device since it was closed by dropBufferedAudio */
|
||||
if (od->fd < 0 && !oss_reopen(od, error))
|
||||
return 0;
|
||||
@@ -735,6 +737,8 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
|
||||
chunk = od->pcm_export->Export(chunk, size, size);
|
||||
#endif
|
||||
|
||||
assert(size > 0);
|
||||
|
||||
while (true) {
|
||||
ret = write(od->fd, chunk, size);
|
||||
if (ret > 0) {
|
||||
|
@@ -171,7 +171,7 @@ static const char *const embcue_playlist_suffixes[] = {
|
||||
};
|
||||
|
||||
const struct playlist_plugin embcue_playlist_plugin = {
|
||||
"cue",
|
||||
"embcue",
|
||||
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@@ -81,7 +81,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
|
||||
/* compatibility with older MPD versions: specifying
|
||||
"-1" makes MPD display the whole list */
|
||||
*value_r1 = 0;
|
||||
*value_r2 = std::numeric_limits<unsigned>::max();
|
||||
*value_r2 = std::numeric_limits<int>::max();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
|
||||
}
|
||||
|
||||
if (test == test2)
|
||||
value = std::numeric_limits<unsigned>::max();
|
||||
value = std::numeric_limits<int>::max();
|
||||
|
||||
if (value < 0) {
|
||||
command_error(client, ACK_ERROR_ARG,
|
||||
|
@@ -40,6 +40,16 @@
|
||||
/* well-known big-endian */
|
||||
# define IS_LITTLE_ENDIAN false
|
||||
# define IS_BIG_ENDIAN true
|
||||
#elif defined(__APPLE__)
|
||||
/* compile-time check for MacOS */
|
||||
# include <machine/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
|
||||
#else
|
||||
/* generic compile-time check */
|
||||
# include <endian.h>
|
||||
|
@@ -41,7 +41,21 @@ class PosixCond {
|
||||
pthread_cond_t cond;
|
||||
|
||||
public:
|
||||
#ifdef __NetBSD__
|
||||
/* NetBSD's PTHREAD_COND_INITIALIZER is not compatible with
|
||||
"constexpr" */
|
||||
PosixCond() {
|
||||
pthread_cond_init(&cond, nullptr);
|
||||
}
|
||||
|
||||
~PosixCond() {
|
||||
pthread_cond_destroy(&cond);
|
||||
}
|
||||
#else
|
||||
/* optimized constexpr constructor for sane POSIX
|
||||
implementations */
|
||||
constexpr PosixCond():cond(PTHREAD_COND_INITIALIZER) {}
|
||||
#endif
|
||||
|
||||
PosixCond(const PosixCond &other) = delete;
|
||||
PosixCond &operator=(const PosixCond &other) = delete;
|
||||
|
@@ -41,7 +41,21 @@ class PosixMutex {
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
public:
|
||||
#ifdef __NetBSD__
|
||||
/* NetBSD's PTHREAD_MUTEX_INITIALIZER is not compatible with
|
||||
"constexpr" */
|
||||
PosixMutex() {
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
}
|
||||
|
||||
~PosixMutex() {
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
#else
|
||||
/* optimized constexpr constructor for sane POSIX
|
||||
implementations */
|
||||
constexpr PosixMutex():mutex(PTHREAD_MUTEX_INITIALIZER) {}
|
||||
#endif
|
||||
|
||||
PosixMutex(const PosixMutex &other) = delete;
|
||||
PosixMutex &operator=(const PosixMutex &other) = delete;
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
/**
|
||||
* Determine whether two strings are equal, ignoring case for ASCII
|
||||
|
Before (image error) Size: 345 KiB After (image error) Size: 345 KiB |
@@ -3,7 +3,7 @@
|
||||
#define VERSION_NUMBER @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@
|
||||
#define VERSION_NUMBER_STR "@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@"
|
||||
|
||||
MPD_ICON ICON "@top_srcdir@/src/win/mpd.ico"
|
||||
MPD_ICON ICON "@top_srcdir@/src/win32/mpd.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILETYPE VFT_APP
|
@@ -175,8 +175,10 @@ decoder_replay_gain(gcc_unused Decoder &decoder,
|
||||
}
|
||||
|
||||
void
|
||||
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
|
||||
decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp)
|
||||
{
|
||||
fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
|
||||
mix_ramp.GetStart(), mix_ramp.GetEnd());
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
62
test/test_protocol.cxx
Normal file
62
test/test_protocol.cxx
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "config.h"
|
||||
#include "protocol/ArgParser.hxx"
|
||||
#include "protocol/Result.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/TestFactoryRegistry.h>
|
||||
#include <cppunit/ui/text/TestRunner.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static enum ack last_error = ack(-1);
|
||||
|
||||
void
|
||||
command_error(gcc_unused Client &client, enum ack error,
|
||||
gcc_unused const char *fmt, ...)
|
||||
{
|
||||
last_error = error;
|
||||
}
|
||||
|
||||
class ArgParserTest : public CppUnit::TestFixture {
|
||||
CPPUNIT_TEST_SUITE(ArgParserTest);
|
||||
CPPUNIT_TEST(TestRange);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void TestRange();
|
||||
};
|
||||
|
||||
void
|
||||
ArgParserTest::TestRange()
|
||||
{
|
||||
Client &client = *(Client *)nullptr;
|
||||
unsigned a, b;
|
||||
|
||||
CPPUNIT_ASSERT(check_range(client, &a, &b, "1"));
|
||||
CPPUNIT_ASSERT_EQUAL(1u, a);
|
||||
CPPUNIT_ASSERT_EQUAL(2u, b);
|
||||
|
||||
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5"));
|
||||
CPPUNIT_ASSERT_EQUAL(1u, a);
|
||||
CPPUNIT_ASSERT_EQUAL(5u, b);
|
||||
|
||||
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:"));
|
||||
CPPUNIT_ASSERT_EQUAL(1u, a);
|
||||
CPPUNIT_ASSERT(b >= 999999u);
|
||||
|
||||
CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2"));
|
||||
CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest);
|
||||
|
||||
int
|
||||
main(gcc_unused int argc, gcc_unused char **argv)
|
||||
{
|
||||
CppUnit::TextUi::TestRunner runner;
|
||||
auto ®istry = CppUnit::TestFactoryRegistry::getRegistry();
|
||||
runner.addTest(registry.makeTest());
|
||||
return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
Reference in New Issue
Block a user