[Pkg-mpd-commits] [pkg-mpd] 02/05: Imported Upstream version 0.18.12
Florian Schlichting
fsfs at moszumanska.debian.org
Sun Aug 3 21:54:59 UTC 2014
This is an automated email from the git hooks/post-receive script.
fsfs pushed a commit to branch master
in repository pkg-mpd.
commit 3832f02c93f0f5e53aadf8c6921e5ed2a8627766
Author: Florian Schlichting <fsfs at debian.org>
Date: Sun Aug 3 22:33:39 2014 +0200
Imported Upstream version 0.18.12
---
Makefile.am | 3 +
Makefile.in | 98 +++++++------
NEWS | 14 ++
configure | 20 +--
configure.ac | 2 +-
doc/doxygen.conf | 2 +-
src/{DatabaseSelection.cxx => BulkEdit.hxx} | 38 ++---
src/DatabaseSelection.cxx | 12 ++
src/DatabaseSelection.hxx | 9 ++
src/DecoderAPI.cxx | 34 +++++
src/DecoderAPI.hxx | 19 +++
src/DecoderBuffer.cxx | 18 +++
src/DecoderBuffer.hxx | 18 +++
src/Playlist.cxx | 10 +-
src/Playlist.hxx | 19 ++-
src/PlaylistControl.cxx | 2 +-
src/PlaylistEdit.cxx | 35 +++++
src/SongFilter.cxx | 10 ++
src/SongFilter.hxx | 11 ++
src/command/DatabaseCommands.cxx | 3 +
src/command/PlaylistCommands.cxx | 3 +
src/command/QueueCommands.cxx | 8 +-
src/db/ProxyDatabasePlugin.cxx | 27 +++-
src/decoder/AudiofileDecoderPlugin.cxx | 46 +++++--
src/decoder/DsdLib.cxx | 10 +-
src/decoder/DsdLib.hxx | 4 -
src/decoder/DsdiffDecoderPlugin.cxx | 46 +++----
src/decoder/DsfDecoderPlugin.cxx | 11 +-
src/decoder/FaadDecoderPlugin.cxx | 199 ++++++++++++++-------------
src/decoder/MadDecoderPlugin.cxx | 29 +---
src/decoder/OpusDecoderPlugin.cxx | 1 +
src/decoder/SndfileDecoderPlugin.cxx | 55 ++++----
src/output/HttpdClient.cxx | 1 +
src/playlist/PlsPlaylistPlugin.cxx | 1 +
test/{run_decoder.cxx => FakeDecoderAPI.cxx} | 155 ++++++---------------
test/dump_playlist.cxx | 83 -----------
test/read_tags.cxx | 75 +---------
test/run_decoder.cxx | 34 +++++
38 files changed, 601 insertions(+), 564 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index c7cf631..25352e3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -181,6 +181,7 @@ src_mpd_SOURCES = \
src/PlaylistInfo.hxx \
src/PlaylistDatabase.cxx src/PlaylistDatabase.hxx \
src/PlaylistUpdate.cxx \
+ src/BulkEdit.hxx \
src/IdTable.hxx \
src/Queue.cxx src/Queue.hxx \
src/QueuePrint.cxx src/QueuePrint.hxx \
@@ -1218,6 +1219,7 @@ test_dump_playlist_LDADD = \
libpcm.a \
$(GLIB_LIBS)
test_dump_playlist_SOURCES = test/dump_playlist.cxx \
+ test/FakeDecoderAPI.cxx \
$(DECODER_SRC) \
src/Log.cxx \
src/IOThread.cxx \
@@ -1271,6 +1273,7 @@ test_read_tags_LDADD = \
libutil.a \
$(GLIB_LIBS)
test_read_tags_SOURCES = test/read_tags.cxx \
+ test/FakeDecoderAPI.cxx \
src/Log.cxx \
src/IOThread.cxx \
src/ReplayGainInfo.cxx \
diff --git a/Makefile.in b/Makefile.in
index 998d0f2..4d22168 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1021,21 +1021,22 @@ am__src_mpd_SOURCES_DIST = src/check.h src/gerror.h \
src/PlaylistVector.cxx src/PlaylistVector.hxx \
src/PlaylistInfo.hxx src/PlaylistDatabase.cxx \
src/PlaylistDatabase.hxx src/PlaylistUpdate.cxx \
- src/IdTable.hxx src/Queue.cxx src/Queue.hxx src/QueuePrint.cxx \
- src/QueuePrint.hxx src/QueueSave.cxx src/QueueSave.hxx \
- src/ReplayGainConfig.cxx src/ReplayGainConfig.hxx \
- src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
- src/SignalHandlers.cxx src/SignalHandlers.hxx src/Song.cxx \
- src/Song.hxx src/SongUpdate.cxx src/SongPrint.cxx \
- src/SongPrint.hxx src/SongSave.cxx src/SongSave.hxx \
- src/SongSort.cxx src/SongSort.hxx src/StateFile.cxx \
- src/StateFile.hxx src/Stats.cxx src/Stats.hxx src/TagPrint.cxx \
- src/TagPrint.hxx src/TagSave.cxx src/TagSave.hxx \
- src/TagFile.cxx src/TagFile.hxx src/TextFile.cxx \
- src/TextFile.hxx src/TextInputStream.cxx src/Volume.cxx \
- src/Volume.hxx src/SongFilter.cxx src/SongFilter.hxx \
- src/SongPointer.hxx src/PlaylistFile.cxx src/PlaylistFile.hxx \
- src/Timer.cxx src/DespotifyUtils.cxx src/DespotifyUtils.hxx \
+ src/BulkEdit.hxx src/IdTable.hxx src/Queue.cxx src/Queue.hxx \
+ src/QueuePrint.cxx src/QueuePrint.hxx src/QueueSave.cxx \
+ src/QueueSave.hxx src/ReplayGainConfig.cxx \
+ src/ReplayGainConfig.hxx src/ReplayGainInfo.cxx \
+ src/ReplayGainInfo.hxx src/SignalHandlers.cxx \
+ src/SignalHandlers.hxx src/Song.cxx src/Song.hxx \
+ src/SongUpdate.cxx src/SongPrint.cxx src/SongPrint.hxx \
+ src/SongSave.cxx src/SongSave.hxx src/SongSort.cxx \
+ src/SongSort.hxx src/StateFile.cxx src/StateFile.hxx \
+ src/Stats.cxx src/Stats.hxx src/TagPrint.cxx src/TagPrint.hxx \
+ src/TagSave.cxx src/TagSave.hxx src/TagFile.cxx \
+ src/TagFile.hxx src/TextFile.cxx src/TextFile.hxx \
+ src/TextInputStream.cxx src/Volume.cxx src/Volume.hxx \
+ src/SongFilter.cxx src/SongFilter.hxx src/SongPointer.hxx \
+ src/PlaylistFile.cxx src/PlaylistFile.hxx src/Timer.cxx \
+ src/DespotifyUtils.cxx src/DespotifyUtils.hxx \
src/InotifyDomain.cxx src/InotifyDomain.hxx \
src/InotifySource.cxx src/InotifySource.hxx \
src/InotifyQueue.cxx src/InotifyQueue.hxx \
@@ -1275,16 +1276,18 @@ test_DumpDatabase_OBJECTS = $(am_test_DumpDatabase_OBJECTS)
@ENABLE_TEST_TRUE@ libconf.a libutil.a libsystem.a libfs.a \
@ENABLE_TEST_TRUE@ $(am__DEPENDENCIES_1)
am__test_dump_playlist_SOURCES_DIST = test/dump_playlist.cxx \
- src/Log.cxx src/IOThread.cxx src/Song.cxx src/TagSave.cxx \
- src/TagFile.cxx src/CheckAudioFormat.cxx \
- src/TextInputStream.cxx src/cue/CueParser.cxx \
- src/cue/CueParser.hxx src/ReplayGainInfo.cxx \
- src/decoder/FlacMetadata.cxx src/DespotifyUtils.cxx
+ test/FakeDecoderAPI.cxx src/Log.cxx src/IOThread.cxx \
+ src/Song.cxx src/TagSave.cxx src/TagFile.cxx \
+ src/CheckAudioFormat.cxx src/TextInputStream.cxx \
+ src/cue/CueParser.cxx src/cue/CueParser.hxx \
+ src/ReplayGainInfo.cxx src/decoder/FlacMetadata.cxx \
+ src/DespotifyUtils.cxx
@ENABLE_TEST_TRUE@@HAVE_FLAC_TRUE at am__objects_70 = src/ReplayGainInfo.$(OBJEXT) \
@ENABLE_TEST_TRUE@@HAVE_FLAC_TRUE@ src/decoder/FlacMetadata.$(OBJEXT)
@ENABLE_DESPOTIFY_TRUE@@ENABLE_TEST_TRUE at am__objects_71 = src/DespotifyUtils.$(OBJEXT)
@ENABLE_TEST_TRUE at am_test_dump_playlist_OBJECTS = \
@ENABLE_TEST_TRUE@ test/dump_playlist.$(OBJEXT) \
+ at ENABLE_TEST_TRUE@ test/FakeDecoderAPI.$(OBJEXT) \
@ENABLE_TEST_TRUE@ $(am__objects_60) src/Log.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/IOThread.$(OBJEXT) src/Song.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/TagSave.$(OBJEXT) src/TagFile.$(OBJEXT) \
@@ -1342,12 +1345,14 @@ test_read_mixer_OBJECTS = $(am_test_read_mixer_OBJECTS)
@ENABLE_TEST_TRUE@ libmixer_plugins.a $(am__DEPENDENCIES_10) \
@ENABLE_TEST_TRUE@ libconf.a libutil.a libevent.a libsystem.a \
@ENABLE_TEST_TRUE@ libfs.a $(am__DEPENDENCIES_1)
-am__test_read_tags_SOURCES_DIST = test/read_tags.cxx src/Log.cxx \
- src/IOThread.cxx src/ReplayGainInfo.cxx \
- src/CheckAudioFormat.cxx src/DespotifyUtils.cxx
+am__test_read_tags_SOURCES_DIST = test/read_tags.cxx \
+ test/FakeDecoderAPI.cxx src/Log.cxx src/IOThread.cxx \
+ src/ReplayGainInfo.cxx src/CheckAudioFormat.cxx \
+ src/DespotifyUtils.cxx
@ENABLE_TEST_TRUE at am_test_read_tags_OBJECTS = \
- at ENABLE_TEST_TRUE@ test/read_tags.$(OBJEXT) src/Log.$(OBJEXT) \
- at ENABLE_TEST_TRUE@ src/IOThread.$(OBJEXT) \
+ at ENABLE_TEST_TRUE@ test/read_tags.$(OBJEXT) \
+ at ENABLE_TEST_TRUE@ test/FakeDecoderAPI.$(OBJEXT) \
+ at ENABLE_TEST_TRUE@ src/Log.$(OBJEXT) src/IOThread.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/ReplayGainInfo.$(OBJEXT) \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.$(OBJEXT) \
@ENABLE_TEST_TRUE@ $(am__objects_60) $(am__objects_71)
@@ -2341,21 +2346,22 @@ src_mpd_SOURCES = $(mpd_headers) $(DECODER_SRC) $(OUTPUT_API_SRC) \
src/PlaylistVector.cxx src/PlaylistVector.hxx \
src/PlaylistInfo.hxx src/PlaylistDatabase.cxx \
src/PlaylistDatabase.hxx src/PlaylistUpdate.cxx \
- src/IdTable.hxx src/Queue.cxx src/Queue.hxx src/QueuePrint.cxx \
- src/QueuePrint.hxx src/QueueSave.cxx src/QueueSave.hxx \
- src/ReplayGainConfig.cxx src/ReplayGainConfig.hxx \
- src/ReplayGainInfo.cxx src/ReplayGainInfo.hxx \
- src/SignalHandlers.cxx src/SignalHandlers.hxx src/Song.cxx \
- src/Song.hxx src/SongUpdate.cxx src/SongPrint.cxx \
- src/SongPrint.hxx src/SongSave.cxx src/SongSave.hxx \
- src/SongSort.cxx src/SongSort.hxx src/StateFile.cxx \
- src/StateFile.hxx src/Stats.cxx src/Stats.hxx src/TagPrint.cxx \
- src/TagPrint.hxx src/TagSave.cxx src/TagSave.hxx \
- src/TagFile.cxx src/TagFile.hxx src/TextFile.cxx \
- src/TextFile.hxx src/TextInputStream.cxx src/Volume.cxx \
- src/Volume.hxx src/SongFilter.cxx src/SongFilter.hxx \
- src/SongPointer.hxx src/PlaylistFile.cxx src/PlaylistFile.hxx \
- src/Timer.cxx $(am__append_1) $(am__append_2) $(am__append_3) \
+ src/BulkEdit.hxx src/IdTable.hxx src/Queue.cxx src/Queue.hxx \
+ src/QueuePrint.cxx src/QueuePrint.hxx src/QueueSave.cxx \
+ src/QueueSave.hxx src/ReplayGainConfig.cxx \
+ src/ReplayGainConfig.hxx src/ReplayGainInfo.cxx \
+ src/ReplayGainInfo.hxx src/SignalHandlers.cxx \
+ src/SignalHandlers.hxx src/Song.cxx src/Song.hxx \
+ src/SongUpdate.cxx src/SongPrint.cxx src/SongPrint.hxx \
+ src/SongSave.cxx src/SongSave.hxx src/SongSort.cxx \
+ src/SongSort.hxx src/StateFile.cxx src/StateFile.hxx \
+ src/Stats.cxx src/Stats.hxx src/TagPrint.cxx src/TagPrint.hxx \
+ src/TagSave.cxx src/TagSave.hxx src/TagFile.cxx \
+ src/TagFile.hxx src/TextFile.cxx src/TextFile.hxx \
+ src/TextInputStream.cxx src/Volume.cxx src/Volume.hxx \
+ src/SongFilter.cxx src/SongFilter.hxx src/SongPointer.hxx \
+ src/PlaylistFile.cxx src/PlaylistFile.hxx src/Timer.cxx \
+ $(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_7) $(am__append_40) $(am__append_41) \
$(am__append_42)
@HAVE_WINDOWS_TRUE at noinst_DATA = src/win/mpd_win32_rc.rc
@@ -2894,8 +2900,9 @@ SPARSE_SRC = $(addprefix $(top_srcdir)/,$(filter %.c,$(src_mpd_SOURCES)))
@ENABLE_TEST_TRUE@ $(GLIB_LIBS)
@ENABLE_TEST_TRUE at test_dump_playlist_SOURCES = test/dump_playlist.cxx \
- at ENABLE_TEST_TRUE@ $(DECODER_SRC) src/Log.cxx src/IOThread.cxx \
- at ENABLE_TEST_TRUE@ src/Song.cxx src/TagSave.cxx src/TagFile.cxx \
+ at ENABLE_TEST_TRUE@ test/FakeDecoderAPI.cxx $(DECODER_SRC) \
+ at ENABLE_TEST_TRUE@ src/Log.cxx src/IOThread.cxx src/Song.cxx \
+ at ENABLE_TEST_TRUE@ src/TagSave.cxx src/TagFile.cxx \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.cxx \
@ENABLE_TEST_TRUE@ src/TextInputStream.cxx \
@ENABLE_TEST_TRUE@ src/cue/CueParser.cxx src/cue/CueParser.hxx \
@@ -2935,8 +2942,8 @@ SPARSE_SRC = $(addprefix $(top_srcdir)/,$(filter %.c,$(src_mpd_SOURCES)))
@ENABLE_TEST_TRUE@ $(GLIB_LIBS)
@ENABLE_TEST_TRUE at test_read_tags_SOURCES = test/read_tags.cxx \
- at ENABLE_TEST_TRUE@ src/Log.cxx src/IOThread.cxx \
- at ENABLE_TEST_TRUE@ src/ReplayGainInfo.cxx \
+ at ENABLE_TEST_TRUE@ test/FakeDecoderAPI.cxx src/Log.cxx \
+ at ENABLE_TEST_TRUE@ src/IOThread.cxx src/ReplayGainInfo.cxx \
@ENABLE_TEST_TRUE@ src/CheckAudioFormat.cxx $(DECODER_SRC) \
@ENABLE_TEST_TRUE@ $(am__append_78)
@ENABLE_TEST_TRUE@@HAVE_ID3TAG_TRUE at test_dump_rva2_LDADD = \
@@ -4409,6 +4416,8 @@ test/DumpDatabase$(EXEEXT): $(test_DumpDatabase_OBJECTS) $(test_DumpDatabase_DEP
$(AM_V_CXXLD)$(CXXLINK) $(test_DumpDatabase_OBJECTS) $(test_DumpDatabase_LDADD) $(LIBS)
test/dump_playlist.$(OBJEXT): test/$(am__dirstamp) \
test/$(DEPDIR)/$(am__dirstamp)
+test/FakeDecoderAPI.$(OBJEXT): test/$(am__dirstamp) \
+ test/$(DEPDIR)/$(am__dirstamp)
src/IOThread.$(OBJEXT): src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/TagFile.$(OBJEXT): src/$(am__dirstamp) \
@@ -5089,6 +5098,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote at src/util/$(DEPDIR)/growing_fifo.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at src/util/$(DEPDIR)/list_sort.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/DumpDatabase.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/FakeDecoderAPI.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/FakeReplayGainConfig.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/ShutdownHandler.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at test/$(DEPDIR)/dump_playlist.Po at am__quote@
diff --git a/NEWS b/NEWS
index d8e9016..8cc6cdd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,17 @@
+ver 0.18.12 (2014/07/30)
+* database
+ - proxy: fix build failure with libmpdclient 2.2
+ - proxy: fix add/search and other commands with libmpdclient < 2.9
+* decoder
+ - audiofile: improve responsiveness
+ - audiofile: fix WAV stream playback
+ - dsdiff, dsf: fix stream playback
+ - dsdiff: fix metadata parser bug (uninitialized variables)
+ - faad: estimate song duration for remote files
+ - sndfile: improve responsiveness
+* randomize next song when enabling "random" mode while not playing
+* randomize next song when adding to single-song queue
+
ver 0.18.11 (2014/05/12)
* decoder
- opus: fix missing song length on high-latency files
diff --git a/configure b/configure
index 6079fe2..44cc171 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for mpd 0.18.11.
+# Generated by GNU Autoconf 2.69 for mpd 0.18.12.
#
# Report bugs to <mpd-devel at musicpd.org>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mpd'
PACKAGE_TARNAME='mpd'
-PACKAGE_VERSION='0.18.11'
-PACKAGE_STRING='mpd 0.18.11'
+PACKAGE_VERSION='0.18.12'
+PACKAGE_STRING='mpd 0.18.12'
PACKAGE_BUGREPORT='mpd-devel at musicpd.org'
PACKAGE_URL=''
@@ -1673,7 +1673,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures mpd 0.18.11 to adapt to many kinds of systems.
+\`configure' configures mpd 0.18.12 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1743,7 +1743,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of mpd 0.18.11:";;
+ short | recursive ) echo "Configuration of mpd 0.18.12:";;
esac
cat <<\_ACEOF
@@ -2041,7 +2041,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-mpd configure 0.18.11
+mpd configure 0.18.12
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2494,7 +2494,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by mpd $as_me 0.18.11, which was
+It was created by mpd $as_me 0.18.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3364,7 +3364,7 @@ fi
# Define the identity of the package.
PACKAGE='mpd'
- VERSION='0.18.11'
+ VERSION='0.18.12'
cat >>confdefs.h <<_ACEOF
@@ -18461,7 +18461,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by mpd $as_me 0.18.11, which was
+This file was extended by mpd $as_me 0.18.12, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -18527,7 +18527,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-mpd config.status 0.18.11
+mpd config.status 0.18.12
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 48933c4..36f785f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ(2.60)
-AC_INIT(mpd, 0.18.11, mpd-devel at musicpd.org)
+AC_INIT(mpd, 0.18.12, mpd-devel at musicpd.org)
VERSION_MAJOR=0
VERSION_MINOR=18
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
index ba4e372..81bd1ec 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf
@@ -31,7 +31,7 @@ PROJECT_NAME = MPD
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 0.18.11
+PROJECT_NUMBER = 0.18.12
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
diff --git a/src/DatabaseSelection.cxx b/src/BulkEdit.hxx
similarity index 57%
copy from src/DatabaseSelection.cxx
copy to src/BulkEdit.hxx
index 96018cb..422dc4f 100644
--- a/src/DatabaseSelection.cxx
+++ b/src/BulkEdit.hxx
@@ -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
@@ -17,21 +17,25 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "DatabaseSelection.hxx"
-#include "SongFilter.hxx"
+#ifndef MPD_BULK_EDIT_HXX
+#define MPD_BULK_EDIT_HXX
-DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
- const SongFilter *_filter)
- :uri(_uri), recursive(_recursive), filter(_filter)
-{
- /* optimization: if the caller didn't specify a base URI, pick
- the one from SongFilter */
- if (uri.empty() && filter != nullptr)
- uri = filter->GetBase();
-}
+#include "Partition.hxx"
-bool
-DatabaseSelection::Match(const Song &song) const
-{
- return filter == nullptr || filter->Match(song);
-}
+/**
+ * Begin a "bulk edit" and commit it automatically.
+ */
+class ScopeBulkEdit {
+ Partition &partition;
+
+public:
+ ScopeBulkEdit(Partition &_partition):partition(_partition) {
+ partition.playlist.BeginBulk();
+ }
+
+ ~ScopeBulkEdit() {
+ partition.playlist.CommitBulk(partition.pc);
+ }
+};
+
+#endif
diff --git a/src/DatabaseSelection.cxx b/src/DatabaseSelection.cxx
index 96018cb..ffe5f7d 100644
--- a/src/DatabaseSelection.cxx
+++ b/src/DatabaseSelection.cxx
@@ -31,6 +31,18 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
}
bool
+DatabaseSelection::IsEmpty() const
+{
+ return uri.empty() && (filter == nullptr || filter->IsEmpty());
+}
+
+bool
+DatabaseSelection::HasOtherThanBase() const
+{
+ return filter != nullptr && filter->HasOtherThanBase();
+}
+
+bool
DatabaseSelection::Match(const Song &song) const
{
return filter == nullptr || filter->Match(song);
diff --git a/src/DatabaseSelection.hxx b/src/DatabaseSelection.hxx
index 6c1a1dc..4825c73 100644
--- a/src/DatabaseSelection.hxx
+++ b/src/DatabaseSelection.hxx
@@ -45,6 +45,15 @@ struct DatabaseSelection {
const SongFilter *_filter=nullptr);
gcc_pure
+ bool IsEmpty() const;
+
+ /**
+ * Does this selection contain constraints other than "base"?
+ */
+ gcc_pure
+ bool HasOtherThanBase() const;
+
+ gcc_pure
bool Match(const Song &song) const;
};
diff --git a/src/DecoderAPI.cxx b/src/DecoderAPI.cxx
index 4fea02b..e4122d6 100644
--- a/src/DecoderAPI.cxx
+++ b/src/DecoderAPI.cxx
@@ -292,6 +292,40 @@ decoder_read(Decoder *decoder,
return nbytes;
}
+bool
+decoder_read_full(Decoder *decoder, InputStream &is,
+ void *_buffer, size_t size)
+{
+ uint8_t *buffer = (uint8_t *)_buffer;
+
+ while (size > 0) {
+ size_t nbytes = decoder_read(decoder, is, buffer, size);
+ if (nbytes == 0)
+ return false;
+
+ buffer += nbytes;
+ size -= nbytes;
+ }
+
+ return true;
+}
+
+bool
+decoder_skip(Decoder *decoder, InputStream &is, size_t size)
+{
+ while (size > 0) {
+ char buffer[1024];
+ size_t nbytes = decoder_read(decoder, is, buffer,
+ std::min(sizeof(buffer), size));
+ if (nbytes == 0)
+ return false;
+
+ size -= nbytes;
+ }
+
+ return true;
+}
+
void
decoder_timestamp(Decoder &decoder, double t)
{
diff --git a/src/DecoderAPI.hxx b/src/DecoderAPI.hxx
index 2ee4248..a9da763 100644
--- a/src/DecoderAPI.hxx
+++ b/src/DecoderAPI.hxx
@@ -113,6 +113,25 @@ decoder_read(Decoder &decoder, InputStream &is,
}
/**
+ * Blocking read from the input stream. Attempts to fill the buffer
+ * completely; there is no partial result.
+ *
+ * @return true on success, false on error or command or not enough
+ * data
+ */
+bool
+decoder_read_full(Decoder *decoder, InputStream &is,
+ void *buffer, size_t size);
+
+/**
+ * Skip data on the #InputStream.
+ *
+ * @return true on success, false on error or command
+ */
+bool
+decoder_skip(Decoder *decoder, InputStream &is, size_t size);
+
+/**
* Sets the time stamp for the next data chunk [seconds]. The MPD
* core automatically counts it up, and a decoder plugin only needs to
* use this function if it thinks that adding to the time stamp based
diff --git a/src/DecoderBuffer.cxx b/src/DecoderBuffer.cxx
index 6aad53c..4a5125b 100644
--- a/src/DecoderBuffer.cxx
+++ b/src/DecoderBuffer.cxx
@@ -70,6 +70,12 @@ decoder_buffer_free(DecoderBuffer *buffer)
g_free(buffer);
}
+const InputStream &
+decoder_buffer_get_stream(const DecoderBuffer *buffer)
+{
+ return *buffer->is;
+}
+
bool
decoder_buffer_is_empty(const DecoderBuffer *buffer)
{
@@ -82,6 +88,12 @@ decoder_buffer_is_full(const DecoderBuffer *buffer)
return buffer->consumed == 0 && buffer->length == buffer->size;
}
+void
+decoder_buffer_clear(DecoderBuffer *buffer)
+{
+ buffer->length = buffer->consumed = 0;
+}
+
static void
decoder_buffer_shift(DecoderBuffer *buffer)
{
@@ -118,6 +130,12 @@ decoder_buffer_fill(DecoderBuffer *buffer)
return true;
}
+size_t
+decoder_buffer_available(const DecoderBuffer *buffer)
+{
+ return buffer->length - buffer->consumed;;
+}
+
const void *
decoder_buffer_read(const DecoderBuffer *buffer, size_t *length_r)
{
diff --git a/src/DecoderBuffer.hxx b/src/DecoderBuffer.hxx
index 92cc31a..65c6e0d 100644
--- a/src/DecoderBuffer.hxx
+++ b/src/DecoderBuffer.hxx
@@ -20,6 +20,8 @@
#ifndef MPD_DECODER_BUFFER_HXX
#define MPD_DECODER_BUFFER_HXX
+#include "Compiler.h"
+
#include <stddef.h>
/**
@@ -50,12 +52,21 @@ decoder_buffer_new(Decoder *decoder, InputStream &is,
void
decoder_buffer_free(DecoderBuffer *buffer);
+gcc_pure
+const InputStream &
+decoder_buffer_get_stream(const DecoderBuffer *buffer);
+
+gcc_pure
bool
decoder_buffer_is_empty(const DecoderBuffer *buffer);
+gcc_pure
bool
decoder_buffer_is_full(const DecoderBuffer *buffer);
+void
+decoder_buffer_clear(DecoderBuffer *buffer);
+
/**
* Read data from the input_stream and append it to the buffer.
*
@@ -67,6 +78,13 @@ bool
decoder_buffer_fill(DecoderBuffer *buffer);
/**
+ * How many bytes are stored in the buffer?
+ */
+gcc_pure
+size_t
+decoder_buffer_available(const DecoderBuffer *buffer);
+
+/**
* Reads data from the buffer. This data is not yet consumed, you
* have to call decoder_buffer_consume() to do that. The returned
* buffer becomes invalid after a decoder_buffer_fill() or a
diff --git a/src/Playlist.cxx b/src/Playlist.cxx
index 8d9ab24..526f352 100644
--- a/src/Playlist.cxx
+++ b/src/Playlist.cxx
@@ -103,6 +103,12 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const Song *prev)
if (!playing)
return;
+ if (prev == nullptr && bulk_edit)
+ /* postponed until CommitBulk() to avoid always
+ queueing the first song that is being added (in
+ random mode) */
+ return;
+
assert(!queue.IsEmpty());
assert((queued < 0) == (prev == nullptr));
@@ -294,7 +300,9 @@ playlist::SetRandom(PlayerControl &pc, bool status)
if (queue.random) {
/* shuffle the queue order, but preserve current */
- const int current_position = GetCurrentPosition();
+ const int current_position = playing
+ ? GetCurrentPosition()
+ : -1;
queue.ShuffleOrder();
diff --git a/src/Playlist.hxx b/src/Playlist.hxx
index 7d7e9b1..b660ecb 100644
--- a/src/Playlist.hxx
+++ b/src/Playlist.hxx
@@ -46,6 +46,18 @@ struct playlist {
bool stop_on_error;
/**
+ * If true, then a bulk edit has been initiated by
+ * BeginBulk(), and UpdateQueuedSong() and OnModified() will
+ * be postponed until CommitBulk()
+ */
+ bool bulk_edit;
+
+ /**
+ * Has the queue been modified during bulk edit mode?
+ */
+ bool bulk_modified;
+
+ /**
* Number of errors since playback was started. If this
* number exceeds the length of the playlist, MPD gives up,
* because all songs have been tried.
@@ -69,7 +81,9 @@ struct playlist {
int queued;
playlist(unsigned max_length)
- :queue(max_length), playing(false), current(-1), queued(-1) {
+ :queue(max_length), playing(false),
+ bulk_edit(false),
+ current(-1), queued(-1) {
}
~playlist() {
@@ -126,6 +140,9 @@ protected:
void UpdateQueuedSong(PlayerControl &pc, const Song *prev);
public:
+ void BeginBulk();
+ void CommitBulk(PlayerControl &pc);
+
void Clear(PlayerControl &pc);
/**
diff --git a/src/PlaylistControl.cxx b/src/PlaylistControl.cxx
index 2dbd75d..58971a4 100644
--- a/src/PlaylistControl.cxx
+++ b/src/PlaylistControl.cxx
@@ -153,7 +153,7 @@ playlist::PlayNext(PlayerControl &pc)
queue.ShuffleOrder();
/* note that current and queued are
- now invalid, but playlist_play_order() will
+ now invalid, but PlayOrder() will
discard them anyway */
}
diff --git a/src/PlaylistEdit.cxx b/src/PlaylistEdit.cxx
index 3eea249..0dffd3d 100644
--- a/src/PlaylistEdit.cxx
+++ b/src/PlaylistEdit.cxx
@@ -40,6 +40,12 @@
void
playlist::OnModified()
{
+ if (bulk_edit) {
+ /* postponed to CommitBulk() */
+ bulk_modified = true;
+ return;
+ }
+
queue.IncrementVersion();
idle_add(IDLE_PLAYLIST);
@@ -56,6 +62,35 @@ playlist::Clear(PlayerControl &pc)
OnModified();
}
+void
+playlist::BeginBulk()
+{
+ assert(!bulk_edit);
+
+ bulk_edit = true;
+ bulk_modified = false;
+}
+
+void
+playlist::CommitBulk(PlayerControl &pc)
+{
+ assert(bulk_edit);
+
+ bulk_edit = false;
+ if (!bulk_modified)
+ return;
+
+ if (queued < 0)
+ /* if no song was queued, UpdateQueuedSong() is being
+ ignored in "bulk" edit mode; now that we have
+ shuffled all new songs, we can pick a random one
+ (instead of always picking the first one that was
+ added) */
+ UpdateQueuedSong(pc, nullptr);
+
+ OnModified();
+}
+
PlaylistResult
playlist::AppendFile(PlayerControl &pc,
const char *path_utf8, unsigned *added_id)
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index 49c966b..235dfe7 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -203,6 +203,16 @@ SongFilter::Match(const Song &song) const
return true;
}
+bool
+SongFilter::HasOtherThanBase() const
+{
+ for (const auto &i : items)
+ if (i.GetTag() != LOCATE_TAG_BASE_TYPE)
+ return true;
+
+ return false;
+}
+
std::string
SongFilter::GetBase() const
{
diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx
index b15127c..8c46ed5 100644
--- a/src/SongFilter.hxx
+++ b/src/SongFilter.hxx
@@ -109,6 +109,11 @@ public:
return items;
}
+ gcc_pure
+ bool IsEmpty() const {
+ return items.empty();
+ }
+
/**
* Is there at least one item with "fold case" enabled?
*/
@@ -122,6 +127,12 @@ public:
}
/**
+ * Does this filter contain constraints other than "base"?
+ */
+ gcc_pure
+ bool HasOtherThanBase() const;
+
+ /**
* Returns the "base" specification (if there is one) or an
* empty string.
*/
diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx
index b86cbda..a7d2467 100644
--- a/src/command/DatabaseCommands.cxx
+++ b/src/command/DatabaseCommands.cxx
@@ -30,6 +30,7 @@
#include "util/Error.hxx"
#include "SongFilter.hxx"
#include "protocol/Result.hxx"
+#include "BulkEdit.hxx"
#include <assert.h>
#include <string.h>
@@ -92,6 +93,8 @@ handle_match_add(Client &client, int argc, char *argv[], bool fold_case)
return CommandResult::ERROR;
}
+ const ScopeBulkEdit bulk_edit(client.partition);
+
const DatabaseSelection selection("", true, &filter);
Error error;
return AddFromDatabase(client.partition, selection, error)
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index d178fa0..c444129 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.cxx
@@ -26,6 +26,7 @@
#include "PlaylistFile.hxx"
#include "PlaylistVector.hxx"
#include "PlaylistQueue.hxx"
+#include "BulkEdit.hxx"
#include "TimePrint.hxx"
#include "Client.hxx"
#include "protocol/ArgParser.hxx"
@@ -67,6 +68,8 @@ handle_load(Client &client, int argc, char *argv[])
} else if (!check_range(client, &start_index, &end_index, argv[2]))
return CommandResult::ERROR;
+ const ScopeBulkEdit bulk_edit(client.partition);
+
const PlaylistResult result =
playlist_open_into_queue(argv[1],
start_index, end_index,
diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx
index a21eb75..a987e1b 100644
--- a/src/command/QueueCommands.cxx
+++ b/src/command/QueueCommands.cxx
@@ -28,6 +28,7 @@
#include "ClientFile.hxx"
#include "Client.hxx"
#include "Partition.hxx"
+#include "BulkEdit.hxx"
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
#include "ls.hxx"
@@ -43,7 +44,6 @@ CommandResult
handle_add(Client &client, gcc_unused int argc, char *argv[])
{
char *uri = argv[1];
- PlaylistResult result;
if (memcmp(uri, "file:///", 8) == 0) {
const char *path_utf8 = uri + 7;
@@ -59,7 +59,7 @@ handle_add(Client &client, gcc_unused int argc, char *argv[])
if (!client_allow_file(client, path_fs, error))
return print_error(client, error);
- result = client.partition.AppendFile(path_utf8);
+ auto result = client.partition.AppendFile(path_utf8);
return print_playlist_result(client, result);
}
@@ -70,10 +70,12 @@ handle_add(Client &client, gcc_unused int argc, char *argv[])
return CommandResult::ERROR;
}
- result = client.partition.AppendURI(uri);
+ auto result = client.partition.AppendURI(uri);
return print_playlist_result(client, result);
}
+ const ScopeBulkEdit bulk_edit(client.partition);
+
const DatabaseSelection selection(uri, true);
Error error;
return AddFromDatabase(client.partition, selection, error)
diff --git a/src/db/ProxyDatabasePlugin.cxx b/src/db/ProxyDatabasePlugin.cxx
index 00b5d44..cb1bcdc 100644
--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -398,8 +398,13 @@ Convert(const struct mpd_song *song)
Song *s = Song::NewDetached(mpd_song_get_uri(song));
s->mtime = mpd_song_get_last_modified(song);
+
+#if LIBMPDCLIENT_CHECK_VERSION(2,3,0)
s->start_ms = mpd_song_get_start(song) * 1000;
s->end_ms = mpd_song_get_end(song) * 1000;
+#else
+ s->start_ms = s->end_ms = 0;
+#endif
TagBuilder tag;
tag.SetTime(mpd_song_get_duration(song));
@@ -561,6 +566,23 @@ SearchSongs(struct mpd_connection *connection,
return result && CheckError(connection, error);
}
+/**
+ * Check whether we can use the "base" constraint. Requires
+ * libmpdclient 2.9 and MPD 0.18.
+ */
+gcc_pure
+static bool
+ServerSupportsSearchBase(const struct mpd_connection *connection)
+{
+#if LIBMPDCLIENT_CHECK_VERSION(2,9,0)
+ return mpd_connection_cmp_server_version(connection, 0, 18, 0) >= 0;
+#else
+ (void)connection;
+
+ return false;
+#endif
+}
+
bool
ProxyDatabase::Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -572,7 +594,10 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
- if (!visit_directory && !visit_playlist && selection.recursive)
+ if (!visit_directory && !visit_playlist && selection.recursive &&
+ (ServerSupportsSearchBase(connection)
+ ? !selection.IsEmpty()
+ : selection.HasOtherThanBase()))
/* this optimized code path can only be used under
certain conditions */
return ::SearchSongs(connection, selection, visit_song, error);
diff --git a/src/decoder/AudiofileDecoderPlugin.cxx b/src/decoder/AudiofileDecoderPlugin.cxx
index ab3557e..9f097f9 100644
--- a/src/decoder/AudiofileDecoderPlugin.cxx
+++ b/src/decoder/AudiofileDecoderPlugin.cxx
@@ -31,12 +31,27 @@
#include <af_vfs.h>
#include <assert.h>
+#include <stdio.h>
/* pick 1020 since its devisible for 8,16,24, and 32-bit audio */
#define CHUNK_SIZE 1020
static constexpr Domain audiofile_domain("audiofile");
+struct AudioFileInputStream {
+ Decoder *const decoder;
+ InputStream &is;
+
+ size_t Read(void *buffer, size_t size) {
+ /* libaudiofile does not like partial reads at all,
+ and will abort playback; therefore always force full
+ reads */
+ return decoder_read_full(decoder, is, buffer, size)
+ ? size
+ : 0;
+ }
+};
+
static int audiofile_get_duration(const char *file)
{
int total_time;
@@ -54,29 +69,26 @@ static int audiofile_get_duration(const char *file)
static ssize_t
audiofile_file_read(AFvirtualfile *vfile, void *data, size_t length)
{
- InputStream &is = *(InputStream *)vfile->closure;
+ AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
- Error error;
- size_t nbytes = is.LockRead(data, length, error);
- if (nbytes == 0 && error.IsDefined()) {
- LogError(error);
- return -1;
- }
-
- return nbytes;
+ return afis.Read(data, length);
}
static AFfileoffset
audiofile_file_length(AFvirtualfile *vfile)
{
- InputStream &is = *(InputStream *)vfile->closure;
+ AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
+ InputStream &is = afis.is;
+
return is.GetSize();
}
static AFfileoffset
audiofile_file_tell(AFvirtualfile *vfile)
{
- InputStream &is = *(InputStream *)vfile->closure;
+ AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
+ InputStream &is = afis.is;
+
return is.GetOffset();
}
@@ -91,11 +103,14 @@ audiofile_file_destroy(AFvirtualfile *vfile)
static AFfileoffset
audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
{
- InputStream &is = *(InputStream *)vfile->closure;
+ AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
+ InputStream &is = afis.is;
+
int whence = (is_relative ? SEEK_CUR : SEEK_SET);
Error error;
if (is.LockSeek(offset, whence, error)) {
+ LogError(error, "Seek failed");
return is.GetOffset();
} else {
return -1;
@@ -103,10 +118,10 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
}
static AFvirtualfile *
-setup_virtual_fops(InputStream &stream)
+setup_virtual_fops(AudioFileInputStream &afis)
{
AFvirtualfile *vf = new AFvirtualfile();
- vf->closure = &stream;
+ vf->closure = &afis;
vf->write = nullptr;
vf->read = audiofile_file_read;
vf->length = audiofile_file_length;
@@ -173,7 +188,8 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is)
return;
}
- vf = setup_virtual_fops(is);
+ AudioFileInputStream afis{&decoder, is};
+ vf = setup_virtual_fops(afis);
af_fp = afOpenVirtualFile(vf, "r", nullptr);
if (af_fp == AF_NULL_FILEHANDLE) {
diff --git a/src/decoder/DsdLib.cxx b/src/decoder/DsdLib.cxx
index 67cc7e9..eafedda 100644
--- a/src/decoder/DsdLib.cxx
+++ b/src/decoder/DsdLib.cxx
@@ -49,14 +49,6 @@ DsdId::Equals(const char *s) const
return memcmp(value, s, sizeof(value)) == 0;
}
-bool
-dsdlib_read(Decoder *decoder, InputStream &is,
- void *data, size_t length)
-{
- size_t nbytes = decoder_read(decoder, is, data, length);
- return nbytes == length;
-}
-
/**
* Skip the #input_stream to the specified offset.
*/
@@ -149,7 +141,7 @@ dsdlib_tag_id3(InputStream &is,
id3_byte_t *dsdid3data;
dsdid3data = dsdid3;
- if (!dsdlib_read(nullptr, is, dsdid3data, count))
+ if (!decoder_read_full(nullptr, is, dsdid3data, count))
return;
id3_tag = id3_tag_parse(dsdid3data, count);
diff --git a/src/decoder/DsdLib.hxx b/src/decoder/DsdLib.hxx
index 53160cf..5c61271 100644
--- a/src/decoder/DsdLib.hxx
+++ b/src/decoder/DsdLib.hxx
@@ -59,10 +59,6 @@ public:
};
bool
-dsdlib_read(Decoder *decoder, InputStream &is,
- void *data, size_t length);
-
-bool
dsdlib_skip_to(Decoder *decoder, InputStream &is,
int64_t offset);
diff --git a/src/decoder/DsdiffDecoderPlugin.cxx b/src/decoder/DsdiffDecoderPlugin.cxx
index a3c0149..60b2e76 100644
--- a/src/decoder/DsdiffDecoderPlugin.cxx
+++ b/src/decoder/DsdiffDecoderPlugin.cxx
@@ -93,14 +93,14 @@ static bool
dsdiff_read_id(Decoder *decoder, InputStream &is,
DsdId *id)
{
- return dsdlib_read(decoder, is, id, sizeof(*id));
+ return decoder_read_full(decoder, is, id, sizeof(*id));
}
static bool
dsdiff_read_chunk_header(Decoder *decoder, InputStream &is,
DsdiffChunkHeader *header)
{
- return dsdlib_read(decoder, is, header, sizeof(*header));
+ return decoder_read_full(decoder, is, header, sizeof(*header));
}
static bool
@@ -112,8 +112,7 @@ dsdiff_read_payload(Decoder *decoder, InputStream &is,
if (size != (uint64_t)length)
return false;
- size_t nbytes = decoder_read(decoder, is, data, length);
- return nbytes == length;
+ return decoder_read_full(decoder, is, data, length);
}
/**
@@ -145,8 +144,8 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is,
} else if (header.id.Equals("CHNL")) {
uint16_t channels;
if (header.GetSize() < sizeof(channels) ||
- !dsdlib_read(decoder, is,
- &channels, sizeof(channels)) ||
+ !decoder_read_full(decoder, is,
+ &channels, sizeof(channels)) ||
!dsdlib_skip_to(decoder, is, chunk_end_offset))
return false;
@@ -154,8 +153,8 @@ dsdiff_read_prop_snd(Decoder *decoder, InputStream &is,
} else if (header.id.Equals("CMPR")) {
DsdId type;
if (header.GetSize() < sizeof(type) ||
- !dsdlib_read(decoder, is,
- &type, sizeof(type)) ||
+ !decoder_read_full(decoder, is,
+ &type, sizeof(type)) ||
!dsdlib_skip_to(decoder, is, chunk_end_offset))
return false;
@@ -208,7 +207,7 @@ dsdiff_handle_native_tag(InputStream &is,
struct dsdiff_native_tag metatag;
- if (!dsdlib_read(nullptr, is, &metatag, sizeof(metatag)))
+ if (!decoder_read_full(nullptr, is, &metatag, sizeof(metatag)))
return;
uint32_t length = FromBE32(metatag.size);
@@ -221,7 +220,7 @@ dsdiff_handle_native_tag(InputStream &is,
char *label;
label = string;
- if (!dsdlib_read(nullptr, is, label, (size_t)length))
+ if (!decoder_read_full(nullptr, is, label, (size_t)length))
return;
string[length] = '\0';
@@ -251,15 +250,17 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
if (!dsdiff_read_chunk_header(decoder, is, chunk_header))
return false;
+ metadata->diar_offset = 0;
+ metadata->diti_offset = 0;
+
#ifdef HAVE_ID3TAG
- metadata->id3_size = 0;
+ metadata->id3_offset = 0;
#endif
/* Now process all the remaining chunk headers in the stream
and record their position and size */
- const auto size = is.GetSize();
- while (is.GetOffset() < size) {
+ do {
uint64_t chunk_size = chunk_header->GetSize();
/* DIIN chunk, is directly followed by other chunks */
@@ -285,16 +286,11 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
metadata->id3_size = chunk_size;
}
#endif
- if (chunk_size != 0) {
- if (!dsdlib_skip(decoder, is, chunk_size))
- break;
- }
- if (is.GetOffset() < size) {
- if (!dsdiff_read_chunk_header(decoder, is, chunk_header))
- return false;
- }
- }
+ if (!dsdlib_skip(decoder, is, chunk_size))
+ break;
+ } while (dsdiff_read_chunk_header(decoder, is, chunk_header));
+
/* done processing chunk headers, process tags if any */
#ifdef HAVE_ID3TAG
@@ -328,7 +324,7 @@ dsdiff_read_metadata(Decoder *decoder, InputStream &is,
DsdiffChunkHeader *chunk_header)
{
DsdiffHeader header;
- if (!dsdlib_read(decoder, is, &header, sizeof(header)) ||
+ if (!decoder_read_full(decoder, is, &header, sizeof(header)) ||
!header.id.Equals("FRM8") ||
!header.format.Equals("DSD "))
return false;
@@ -391,10 +387,10 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is,
now_size = now_frames * frame_size;
}
- size_t nbytes = decoder_read(decoder, is, buffer, now_size);
- if (nbytes != now_size)
+ if (!decoder_read_full(&decoder, is, buffer, now_size))
return false;
+ const size_t nbytes = now_size;
chunk_size -= nbytes;
if (lsbitfirst)
diff --git a/src/decoder/DsfDecoderPlugin.cxx b/src/decoder/DsfDecoderPlugin.cxx
index 5ef94e6..ad5483c 100644
--- a/src/decoder/DsfDecoderPlugin.cxx
+++ b/src/decoder/DsfDecoderPlugin.cxx
@@ -103,7 +103,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is,
DsfMetaData *metadata)
{
DsfHeader dsf_header;
- if (!dsdlib_read(decoder, is, &dsf_header, sizeof(dsf_header)) ||
+ if (!decoder_read_full(decoder, is, &dsf_header, sizeof(dsf_header)) ||
!dsf_header.id.Equals("DSD "))
return false;
@@ -117,7 +117,8 @@ dsf_read_metadata(Decoder *decoder, InputStream &is,
/* read the 'fmt ' chunk of the DSF file */
DsfFmtChunk dsf_fmt_chunk;
- if (!dsdlib_read(decoder, is, &dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) ||
+ if (!decoder_read_full(decoder, is,
+ &dsf_fmt_chunk, sizeof(dsf_fmt_chunk)) ||
!dsf_fmt_chunk.id.Equals("fmt "))
return false;
@@ -143,7 +144,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is,
/* read the 'data' chunk of the DSF file */
DsfDataChunk data_chunk;
- if (!dsdlib_read(decoder, is, &data_chunk, sizeof(data_chunk)) ||
+ if (!decoder_read_full(decoder, is, &data_chunk, sizeof(data_chunk)) ||
!data_chunk.id.Equals("data"))
return false;
@@ -247,10 +248,10 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
now_size = now_frames * frame_size;
}
- size_t nbytes = decoder_read(&decoder, is, buffer, now_size);
- if (nbytes != now_size)
+ if (!decoder_read_full(&decoder, is, buffer, now_size))
return false;
+ const size_t nbytes = now_size;
chunk_size -= nbytes;
if (bitreverse)
diff --git a/src/decoder/FaadDecoderPlugin.cxx b/src/decoder/FaadDecoderPlugin.cxx
index 9fd2016..b446ac5 100644
--- a/src/decoder/FaadDecoderPlugin.cxx
+++ b/src/decoder/FaadDecoderPlugin.cxx
@@ -34,8 +34,6 @@
#include <string.h>
#include <unistd.h>
-#define AAC_MAX_CHANNELS 6
-
static const unsigned adts_sample_rates[] =
{ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
@@ -66,16 +64,13 @@ adts_check_frame(const unsigned char *data)
static size_t
adts_find_frame(DecoderBuffer *buffer)
{
- size_t length, frame_length;
- bool ret;
-
while (true) {
+ size_t length;
const uint8_t *data = (const uint8_t *)
decoder_buffer_read(buffer, &length);
if (data == nullptr || length < 8) {
/* not enough data yet */
- ret = decoder_buffer_fill(buffer);
- if (!ret)
+ if (!decoder_buffer_fill(buffer))
/* failed */
return 0;
@@ -86,7 +81,7 @@ adts_find_frame(DecoderBuffer *buffer)
const uint8_t *p = (const uint8_t *)memchr(data, 0xff, length);
if (p == nullptr) {
/* no marker - discard the buffer */
- decoder_buffer_consume(buffer, length);
+ decoder_buffer_clear(buffer);
continue;
}
@@ -97,7 +92,7 @@ adts_find_frame(DecoderBuffer *buffer)
}
/* is it a frame? */
- frame_length = adts_check_frame(data);
+ const size_t frame_length = adts_check_frame(data);
if (frame_length == 0) {
/* it's just some random 0xff byte; discard it
and continue searching */
@@ -109,15 +104,11 @@ adts_find_frame(DecoderBuffer *buffer)
/* available buffer size is smaller than the
frame will be - attempt to read more
data */
- ret = decoder_buffer_fill(buffer);
- if (!ret) {
+ if (!decoder_buffer_fill(buffer)) {
/* not enough data; discard this frame
to prevent a possible buffer
overflow */
- data = (const uint8_t *)
- decoder_buffer_read(buffer, &length);
- if (data != nullptr)
- decoder_buffer_consume(buffer, length);
+ decoder_buffer_clear(buffer);
}
continue;
@@ -131,13 +122,18 @@ adts_find_frame(DecoderBuffer *buffer)
static float
adts_song_duration(DecoderBuffer *buffer)
{
- unsigned int frames, frame_length;
+ const InputStream &is = decoder_buffer_get_stream(buffer);
+ const bool estimate = !is.CheapSeeking();
+ const auto file_size = is.GetSize();
+ if (estimate && file_size <= 0)
+ return -1;
+
unsigned sample_rate = 0;
- float frames_per_second;
/* Read all frames to ensure correct time and bitrate */
+ unsigned frames;
for (frames = 0;; frames++) {
- frame_length = adts_find_frame(buffer);
+ const unsigned frame_length = adts_find_frame(buffer);
if (frame_length == 0)
break;
@@ -150,36 +146,52 @@ adts_song_duration(DecoderBuffer *buffer)
assert(frame_length <= buffer_length);
sample_rate = adts_sample_rates[(data[2] & 0x3c) >> 2];
+ if (sample_rate == 0)
+ break;
}
decoder_buffer_consume(buffer, frame_length);
+
+ if (estimate && frames == 128) {
+ /* if this is a remote file, don't slurp the
+ whole file just for checking the song
+ duration; instead, stop after some time and
+ extrapolate the song duration from what we
+ have until now */
+
+ const auto offset = is.GetOffset()
+ - decoder_buffer_available(buffer);
+ if (offset <= 0)
+ return -1;
+
+ frames = (frames * file_size) / offset;
+ break;
+ }
}
- frames_per_second = (float)sample_rate / 1024.0;
- if (frames_per_second <= 0)
+ if (sample_rate == 0)
return -1;
+ float frames_per_second = (float)sample_rate / 1024.0;
+ assert(frames_per_second > 0);
+
return (float)frames / frames_per_second;
}
static float
faad_song_duration(DecoderBuffer *buffer, InputStream &is)
{
- size_t fileread;
- size_t tagsize;
- size_t length;
- bool success;
-
const auto size = is.GetSize();
- fileread = size >= 0 ? size : 0;
+ const size_t fileread = size >= 0 ? size : 0;
decoder_buffer_fill(buffer);
+ size_t length;
const uint8_t *data = (const uint8_t *)
decoder_buffer_read(buffer, &length);
if (data == nullptr)
return -1;
- tagsize = 0;
+ size_t tagsize = 0;
if (length >= 10 && !memcmp(data, "ID3", 3)) {
/* skip the ID3 tag */
@@ -188,7 +200,7 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
tagsize += 10;
- success = decoder_buffer_skip(buffer, tagsize) &&
+ const bool success = decoder_buffer_skip(buffer, tagsize) &&
decoder_buffer_fill(buffer);
if (!success)
return -1;
@@ -198,22 +210,20 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
return -1;
}
- if (is.IsSeekable() && length >= 2 &&
- data[0] == 0xFF && ((data[1] & 0xF6) == 0xF0)) {
+ if (length >= 8 && adts_check_frame(data) > 0) {
/* obtain the duration from the ADTS header */
+
+ if (!is.IsSeekable())
+ return -1;
+
float song_length = adts_song_duration(buffer);
is.LockSeek(tagsize, SEEK_SET, IgnoreError());
-
- data = (const uint8_t *)decoder_buffer_read(buffer, &length);
- if (data != nullptr)
- decoder_buffer_consume(buffer, length);
- decoder_buffer_fill(buffer);
+ decoder_buffer_clear(buffer);
return song_length;
} else if (length >= 5 && memcmp(data, "ADIF", 4) == 0) {
/* obtain the duration from the ADIF header */
- unsigned bit_rate;
size_t skip_size = (data[4] & 0x80) ? 9 : 0;
if (8 + skip_size > length)
@@ -221,7 +231,7 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
header */
return -1;
- bit_rate = ((data[4 + skip_size] & 0x0F) << 19) |
+ unsigned bit_rate = ((data[4 + skip_size] & 0x0F) << 19) |
(data[5 + skip_size] << 11) |
(data[6 + skip_size] << 3) |
(data[7 + skip_size] & 0xE0);
@@ -234,6 +244,21 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
return -1;
}
+static NeAACDecHandle
+faad_decoder_new()
+{
+ const NeAACDecHandle decoder = NeAACDecOpen();
+
+ NeAACDecConfigurationPtr config =
+ NeAACDecGetCurrentConfiguration(decoder);
+ config->outputFormat = FAAD_FMT_16BIT;
+ config->downMatrix = 1;
+ config->dontUpSampleImplicitSBR = 0;
+ NeAACDecSetConfiguration(decoder, config);
+
+ return decoder;
+}
+
/**
* Wrapper for NeAACDecInit() which works around some API
* inconsistencies in libfaad.
@@ -242,17 +267,6 @@ static bool
faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
AudioFormat &audio_format, Error &error)
{
- int32_t nbytes;
- uint32_t sample_rate;
- uint8_t channels;
-#ifdef HAVE_FAAD_LONG
- /* neaacdec.h declares all arguments as "unsigned long", but
- internally expects uint32_t pointers. To avoid gcc
- warnings, use this workaround. */
- unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
-#else
- uint32_t *sample_rate_p = &sample_rate;
-#endif
size_t length;
const unsigned char *data = (const unsigned char *)
@@ -262,11 +276,21 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
return false;
}
- nbytes = NeAACDecInit(decoder,
- /* deconst hack, libfaad requires this */
- const_cast<unsigned char *>(data),
- length,
- sample_rate_p, &channels);
+ uint8_t channels;
+ uint32_t sample_rate;
+#ifdef HAVE_FAAD_LONG
+ /* neaacdec.h declares all arguments as "unsigned long", but
+ internally expects uint32_t pointers. To avoid gcc
+ warnings, use this workaround. */
+ unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
+#else
+ uint32_t *sample_rate_p = &sample_rate;
+#endif
+ long nbytes = NeAACDecInit(decoder,
+ /* deconst hack, libfaad requires this */
+ const_cast<unsigned char *>(data),
+ length,
+ sample_rate_p, &channels);
if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream");
return false;
@@ -306,29 +330,21 @@ faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer *buffer,
static float
faad_get_file_time_float(InputStream &is)
{
- DecoderBuffer *buffer;
- float length;
+ DecoderBuffer *const buffer =
+ decoder_buffer_new(nullptr, is,
+ FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
- buffer = decoder_buffer_new(nullptr, is,
- FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- length = faad_song_duration(buffer, is);
+ float length = faad_song_duration(buffer, is);
if (length < 0) {
- bool ret;
AudioFormat audio_format;
- NeAACDecHandle decoder = NeAACDecOpen();
-
- NeAACDecConfigurationPtr config =
- NeAACDecGetCurrentConfiguration(decoder);
- config->outputFormat = FAAD_FMT_16BIT;
- NeAACDecSetConfiguration(decoder, config);
+ NeAACDecHandle decoder = faad_decoder_new();
decoder_buffer_fill(buffer);
- ret = faad_decoder_init(decoder, buffer, audio_format,
- IgnoreError());
- if (ret)
+ if (faad_decoder_init(decoder, buffer, audio_format,
+ IgnoreError()))
length = 0;
NeAACDecClose(decoder);
@@ -347,38 +363,25 @@ faad_get_file_time_float(InputStream &is)
static int
faad_get_file_time(InputStream &is)
{
- int file_time = -1;
- float length;
-
- if ((length = faad_get_file_time_float(is)) >= 0)
- file_time = length + 0.5;
+ float length = faad_get_file_time_float(is);
+ if (length < 0)
+ return -1;
- return file_time;
+ return int(length + 0.5);
}
static void
faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
{
- float total_time = 0;
- AudioFormat audio_format;
- bool ret;
- uint16_t bit_rate = 0;
- DecoderBuffer *buffer;
+ DecoderBuffer *const buffer =
+ decoder_buffer_new(&mpd_decoder, is,
+ FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
- buffer = decoder_buffer_new(&mpd_decoder, is,
- FAAD_MIN_STREAMSIZE * AAC_MAX_CHANNELS);
- total_time = faad_song_duration(buffer, is);
+ const float total_time = faad_song_duration(buffer, is);
/* create the libfaad decoder */
- NeAACDecHandle decoder = NeAACDecOpen();
-
- NeAACDecConfigurationPtr config =
- NeAACDecGetCurrentConfiguration(decoder);
- config->outputFormat = FAAD_FMT_16BIT;
- config->downMatrix = 1;
- config->dontUpSampleImplicitSBR = 0;
- NeAACDecSetConfiguration(decoder, config);
+ const NeAACDecHandle decoder = faad_decoder_new();
while (!decoder_buffer_is_full(buffer) && !is.LockIsEOF() &&
decoder_get_command(mpd_decoder) == DecoderCommand::NONE) {
@@ -389,8 +392,8 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
/* initialize it */
Error error;
- ret = faad_decoder_init(decoder, buffer, audio_format, error);
- if (!ret) {
+ AudioFormat audio_format;
+ if (!faad_decoder_init(decoder, buffer, audio_format, error)) {
LogError(error);
NeAACDecClose(decoder);
decoder_buffer_free(buffer);
@@ -404,21 +407,20 @@ faad_stream_decode(Decoder &mpd_decoder, InputStream &is)
/* the decoder loop */
DecoderCommand cmd;
+ uint16_t bit_rate = 0;
do {
- size_t frame_size;
- const void *decoded;
- NeAACDecFrameInfo frame_info;
-
/* find the next frame */
- frame_size = adts_find_frame(buffer);
+ const size_t frame_size = adts_find_frame(buffer);
if (frame_size == 0)
/* end of file */
break;
/* decode it */
- decoded = faad_decoder_decode(decoder, buffer, &frame_info);
+ NeAACDecFrameInfo frame_info;
+ const void *const decoded =
+ faad_decoder_decode(decoder, buffer, &frame_info);
if (frame_info.error > 0) {
FormatWarning(faad_decoder_domain,
@@ -470,7 +472,6 @@ faad_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx)
{
int file_time = faad_get_file_time(is);
-
if (file_time < 0)
return false;
diff --git a/src/decoder/MadDecoderPlugin.cxx b/src/decoder/MadDecoderPlugin.cxx
index 9dd86c5..6f619b3 100644
--- a/src/decoder/MadDecoderPlugin.cxx
+++ b/src/decoder/MadDecoderPlugin.cxx
@@ -353,18 +353,8 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
memcpy(allocated, stream.this_frame, count);
mad_stream_skip(&(stream), count);
- while (count < tagsize) {
- size_t len;
-
- len = decoder_read(decoder, input_stream,
- allocated + count, tagsize - count);
- if (len == 0)
- break;
- else
- count += len;
- }
-
- if (count != tagsize) {
+ if (!decoder_read_full(decoder, input_stream,
+ allocated + count, tagsize - count)) {
LogDebug(mad_domain, "error parsing ID3 tag");
g_free(allocated);
return;
@@ -413,20 +403,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
mad_stream_skip(&stream, tagsize);
} else {
mad_stream_skip(&stream, count);
-
- while (count < tagsize) {
- size_t len = tagsize - count;
- char ignored[1024];
- if (len > sizeof(ignored))
- len = sizeof(ignored);
-
- len = decoder_read(decoder, input_stream,
- ignored, len);
- if (len == 0)
- break;
- else
- count += len;
- }
+ decoder_skip(decoder, input_stream, tagsize - count);
}
#endif
}
diff --git a/src/decoder/OpusDecoderPlugin.cxx b/src/decoder/OpusDecoderPlugin.cxx
index f3d7b34..01ea368 100644
--- a/src/decoder/OpusDecoderPlugin.cxx
+++ b/src/decoder/OpusDecoderPlugin.cxx
@@ -40,6 +40,7 @@
#include <glib.h>
#include <string.h>
+#include <stdio.h>
static constexpr opus_int32 opus_sample_rate = 48000;
diff --git a/src/decoder/SndfileDecoderPlugin.cxx b/src/decoder/SndfileDecoderPlugin.cxx
index 77b1329..bcdf6d7 100644
--- a/src/decoder/SndfileDecoderPlugin.cxx
+++ b/src/decoder/SndfileDecoderPlugin.cxx
@@ -31,10 +31,24 @@
static constexpr Domain sndfile_domain("sndfile");
+struct SndfileInputStream {
+ Decoder *const decoder;
+ InputStream &is;
+
+ size_t Read(void *buffer, size_t size) {
+ /* libsndfile chokes on partial reads; therefore
+ always force full reads */
+ return decoder_read_full(decoder, is, buffer, size)
+ ? size
+ : 0;
+ }
+};
+
static sf_count_t
sndfile_vio_get_filelen(void *user_data)
{
- const InputStream &is = *(const InputStream *)user_data;
+ SndfileInputStream &sis = *(SndfileInputStream *)user_data;
+ const InputStream &is = sis.is;
return is.GetSize();
}
@@ -42,10 +56,14 @@ sndfile_vio_get_filelen(void *user_data)
static sf_count_t
sndfile_vio_seek(sf_count_t offset, int whence, void *user_data)
{
- InputStream &is = *(InputStream *)user_data;
+ SndfileInputStream &sis = *(SndfileInputStream *)user_data;
+ InputStream &is = sis.is;
- if (!is.LockSeek(offset, whence, IgnoreError()))
+ Error error;
+ if (!is.LockSeek(offset, whence, error)) {
+ LogError(error, "Seek failed");
return -1;
+ }
return is.GetOffset();
}
@@ -53,30 +71,9 @@ sndfile_vio_seek(sf_count_t offset, int whence, void *user_data)
static sf_count_t
sndfile_vio_read(void *ptr, sf_count_t count, void *user_data)
{
- InputStream &is = *(InputStream *)user_data;
-
- sf_count_t total_bytes = 0;
- Error error;
-
- /* this loop is necessary because libsndfile chokes on partial
- reads */
-
- do {
- size_t nbytes = is.LockRead((char *)ptr + total_bytes,
- count - total_bytes, error);
- if (nbytes == 0) {
- if (error.IsDefined()) {
- LogError(error);
- return -1;
- }
-
- break;
- }
-
- total_bytes += nbytes;
- } while (total_bytes < count);
+ SndfileInputStream &sis = *(SndfileInputStream *)user_data;
- return total_bytes;
+ return sis.Read(ptr, count);
}
static sf_count_t
@@ -91,7 +88,8 @@ sndfile_vio_write(gcc_unused const void *ptr,
static sf_count_t
sndfile_vio_tell(void *user_data)
{
- const InputStream &is = *(const InputStream *)user_data;
+ SndfileInputStream &sis = *(SndfileInputStream *)user_data;
+ const InputStream &is = sis.is;
return is.GetOffset();
}
@@ -137,7 +135,8 @@ sndfile_stream_decode(Decoder &decoder, InputStream &is)
info.format = 0;
- sf = sf_open_virtual(&vio, SFM_READ, &info, &is);
+ SndfileInputStream sis{&decoder, is};
+ sf = sf_open_virtual(&vio, SFM_READ, &info, &sis);
if (sf == nullptr) {
LogWarning(sndfile_domain, "sf_open_virtual() failed");
return;
diff --git a/src/output/HttpdClient.cxx b/src/output/HttpdClient.cxx
index 8e13fda..dc33705 100644
--- a/src/output/HttpdClient.cxx
+++ b/src/output/HttpdClient.cxx
@@ -30,6 +30,7 @@
#include <assert.h>
#include <string.h>
+#include <stdio.h>
HttpdClient::~HttpdClient()
{
diff --git a/src/playlist/PlsPlaylistPlugin.cxx b/src/playlist/PlsPlaylistPlugin.cxx
index 99be3ad..7b5c882 100644
--- a/src/playlist/PlsPlaylistPlugin.cxx
+++ b/src/playlist/PlsPlaylistPlugin.cxx
@@ -31,6 +31,7 @@
#include <glib.h>
#include <string>
+#include <stdio.h>
static constexpr Domain pls_domain("pls");
diff --git a/test/run_decoder.cxx b/test/FakeDecoderAPI.cxx
similarity index 50%
copy from test/run_decoder.cxx
copy to test/FakeDecoderAPI.cxx
index 2f7330a..ca09ca9 100644
--- a/test/run_decoder.cxx
+++ b/test/FakeDecoderAPI.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2011 The Music Player Daemon Project
+ * Copyright (C) 2003-2012 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,57 +18,21 @@
*/
#include "config.h"
-#include "IOThread.hxx"
-#include "DecoderList.hxx"
#include "DecoderAPI.hxx"
-#include "InputInit.hxx"
#include "InputStream.hxx"
-#include "AudioFormat.hxx"
#include "util/Error.hxx"
-#include "thread/Cond.hxx"
-#include "Log.hxx"
-#include "stdbin.h"
+#include "Compiler.h"
#include <glib.h>
-#include <assert.h>
#include <unistd.h>
-#include <stdlib.h>
-
-static void
-my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
- const gchar *message, gcc_unused gpointer user_data)
-{
- if (log_domain != NULL)
- g_printerr("%s: %s\n", log_domain, message);
- else
- g_printerr("%s\n", message);
-}
-
-struct Decoder {
- const char *uri;
-
- const struct DecoderPlugin *plugin;
-
- bool initialized;
-};
void
-decoder_initialized(Decoder &decoder,
- const AudioFormat audio_format,
+decoder_initialized(gcc_unused Decoder &decoder,
+ gcc_unused const AudioFormat audio_format,
gcc_unused bool seekable,
- float duration)
+ gcc_unused float total_time)
{
- struct audio_format_string af_string;
-
- assert(!decoder.initialized);
- assert(audio_format.IsValid());
-
- g_printerr("audio_format=%s duration=%f\n",
- audio_format_to_string(audio_format, &af_string),
- duration);
-
- decoder.initialized = true;
}
DecoderCommand
@@ -101,6 +65,40 @@ decoder_read(gcc_unused Decoder *decoder,
return is.LockRead(buffer, length, IgnoreError());
}
+bool
+decoder_read_full(Decoder *decoder, InputStream &is,
+ void *_buffer, size_t size)
+{
+ uint8_t *buffer = (uint8_t *)_buffer;
+
+ while (size > 0) {
+ size_t nbytes = decoder_read(decoder, is, buffer, size);
+ if (nbytes == 0)
+ return false;
+
+ buffer += nbytes;
+ size -= nbytes;
+ }
+
+ return true;
+}
+
+bool
+decoder_skip(Decoder *decoder, InputStream &is, size_t size)
+{
+ while (size > 0) {
+ char buffer[1024];
+ size_t nbytes = decoder_read(decoder, is, buffer,
+ std::min(sizeof(buffer), size));
+ if (nbytes == 0)
+ return false;
+
+ size -= nbytes;
+ }
+
+ return true;
+}
+
void
decoder_timestamp(gcc_unused Decoder &decoder,
gcc_unused double t)
@@ -144,78 +142,3 @@ void
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
{
}
-
-int main(int argc, char **argv)
-{
- const char *decoder_name;
-
- if (argc != 3) {
- g_printerr("Usage: run_decoder DECODER URI >OUT\n");
- return 1;
- }
-
- Decoder decoder;
- decoder_name = argv[1];
- decoder.uri = argv[2];
-
-#if !GLIB_CHECK_VERSION(2,32,0)
- g_thread_init(NULL);
-#endif
-
- g_log_set_default_handler(my_log_func, NULL);
-
- io_thread_init();
- io_thread_start();
-
- Error error;
- if (!input_stream_global_init(error)) {
- LogError(error);
- return 2;
- }
-
- decoder_plugin_init_all();
-
- decoder.plugin = decoder_plugin_from_name(decoder_name);
- if (decoder.plugin == NULL) {
- g_printerr("No such decoder: %s\n", decoder_name);
- return 1;
- }
-
- decoder.initialized = false;
-
- if (decoder.plugin->file_decode != NULL) {
- decoder.plugin->FileDecode(decoder, decoder.uri);
- } else if (decoder.plugin->stream_decode != NULL) {
- Mutex mutex;
- Cond cond;
-
- InputStream *is =
- InputStream::Open(decoder.uri, mutex, cond, error);
- if (is == NULL) {
- if (error.IsDefined())
- LogError(error);
- else
- g_printerr("InputStream::Open() failed\n");
-
- return 1;
- }
-
- decoder.plugin->StreamDecode(decoder, *is);
-
- is->Close();
- } else {
- g_printerr("Decoder plugin is not usable\n");
- return 1;
- }
-
- decoder_plugin_deinit_all();
- input_stream_global_finish();
- io_thread_deinit();
-
- if (!decoder.initialized) {
- g_printerr("Decoding failed\n");
- return 1;
- }
-
- return 0;
-}
diff --git a/test/dump_playlist.cxx b/test/dump_playlist.cxx
index d115629..4ac0298 100644
--- a/test/dump_playlist.cxx
+++ b/test/dump_playlist.cxx
@@ -24,7 +24,6 @@
#include "Directory.hxx"
#include "InputStream.hxx"
#include "ConfigGlobal.hxx"
-#include "DecoderAPI.hxx"
#include "DecoderList.hxx"
#include "InputInit.hxx"
#include "IOThread.hxx"
@@ -53,88 +52,6 @@ my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level,
g_printerr("%s\n", message);
}
-void
-decoder_initialized(gcc_unused Decoder &decoder,
- gcc_unused const AudioFormat audio_format,
- gcc_unused bool seekable,
- gcc_unused float total_time)
-{
-}
-
-DecoderCommand
-decoder_get_command(gcc_unused Decoder &decoder)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_command_finished(gcc_unused Decoder &decoder)
-{
-}
-
-double
-decoder_seek_where(gcc_unused Decoder &decoder)
-{
- return 1.0;
-}
-
-void
-decoder_seek_error(gcc_unused Decoder &decoder)
-{
-}
-
-size_t
-decoder_read(gcc_unused Decoder *decoder,
- InputStream &is,
- void *buffer, size_t length)
-{
- return is.LockRead(buffer, length, IgnoreError());
-}
-
-void
-decoder_timestamp(gcc_unused Decoder &decoder,
- gcc_unused double t)
-{
-}
-
-DecoderCommand
-decoder_data(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- const void *data, size_t datalen,
- gcc_unused uint16_t kbit_rate)
-{
- gcc_unused ssize_t nbytes = write(1, data, datalen);
- return DecoderCommand::NONE;
-}
-
-DecoderCommand
-decoder_tag(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- gcc_unused Tag &&tag)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_replay_gain(gcc_unused Decoder &decoder,
- const ReplayGainInfo *rgi)
-{
- const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM];
- if (tuple->IsDefined())
- g_printerr("replay_gain[album]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
-
- tuple = &rgi->tuples[REPLAY_GAIN_TRACK];
- if (tuple->IsDefined())
- g_printerr("replay_gain[track]: gain=%f peak=%f\n",
- tuple->gain, tuple->peak);
-}
-
-void
-decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
-{
-}
-
int main(int argc, char **argv)
{
const char *uri;
diff --git a/test/read_tags.cxx b/test/read_tags.cxx
index 90f1424..52b2561 100644
--- a/test/read_tags.cxx
+++ b/test/read_tags.cxx
@@ -20,7 +20,7 @@
#include "config.h"
#include "IOThread.hxx"
#include "DecoderList.hxx"
-#include "DecoderAPI.hxx"
+#include "DecoderPlugin.hxx"
#include "InputInit.hxx"
#include "InputStream.hxx"
#include "AudioFormat.hxx"
@@ -42,79 +42,6 @@
#include <locale.h>
#endif
-void
-decoder_initialized(gcc_unused Decoder &decoder,
- gcc_unused const AudioFormat audio_format,
- gcc_unused bool seekable,
- gcc_unused float total_time)
-{
-}
-
-DecoderCommand
-decoder_get_command(gcc_unused Decoder &decoder)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_command_finished(gcc_unused Decoder &decoder)
-{
-}
-
-double
-decoder_seek_where(gcc_unused Decoder &decoder)
-{
- return 1.0;
-}
-
-void
-decoder_seek_error(gcc_unused Decoder &decoder)
-{
-}
-
-size_t
-decoder_read(gcc_unused Decoder *decoder,
- InputStream &is,
- void *buffer, size_t length)
-{
- return is.LockRead(buffer, length, IgnoreError());
-}
-
-void
-decoder_timestamp(gcc_unused Decoder &decoder,
- gcc_unused double t)
-{
-}
-
-DecoderCommand
-decoder_data(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- const void *data, size_t datalen,
- gcc_unused uint16_t kbit_rate)
-{
- gcc_unused ssize_t nbytes = write(1, data, datalen);
- return DecoderCommand::NONE;
-}
-
-DecoderCommand
-decoder_tag(gcc_unused Decoder &decoder,
- gcc_unused InputStream *is,
- gcc_unused Tag &&tag)
-{
- return DecoderCommand::NONE;
-}
-
-void
-decoder_replay_gain(gcc_unused Decoder &decoder,
- gcc_unused const ReplayGainInfo *replay_gain_info)
-{
-}
-
-void
-decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp)
-{
-}
-
static bool empty = true;
static void
diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx
index 2f7330a..7db8dde 100644
--- a/test/run_decoder.cxx
+++ b/test/run_decoder.cxx
@@ -101,6 +101,40 @@ decoder_read(gcc_unused Decoder *decoder,
return is.LockRead(buffer, length, IgnoreError());
}
+bool
+decoder_read_full(Decoder *decoder, InputStream &is,
+ void *_buffer, size_t size)
+{
+ uint8_t *buffer = (uint8_t *)_buffer;
+
+ while (size > 0) {
+ size_t nbytes = decoder_read(decoder, is, buffer, size);
+ if (nbytes == 0)
+ return false;
+
+ buffer += nbytes;
+ size -= nbytes;
+ }
+
+ return true;
+}
+
+bool
+decoder_skip(Decoder *decoder, InputStream &is, size_t size)
+{
+ while (size > 0) {
+ char buffer[1024];
+ size_t nbytes = decoder_read(decoder, is, buffer,
+ std::min(sizeof(buffer), size));
+ if (nbytes == 0)
+ return false;
+
+ size -= nbytes;
+ }
+
+ return true;
+}
+
void
decoder_timestamp(gcc_unused Decoder &decoder,
gcc_unused double t)
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mpd/pkg-mpd.git
More information about the Pkg-mpd-commits
mailing list