Compare commits

...

60 Commits

Author SHA1 Message Date
Max Kellermann
f33d2fb2e7 release v0.19.8 2015-01-14 23:12:24 +01:00
Max Kellermann
a9eec35aff Merge tag 'v0.18.22' into v0.19.x 2015-01-14 23:12:08 +01:00
Max Kellermann
8534f2d1e2 release v0.18.22 2015-01-14 23:04:49 +01:00
Max Kellermann
00740fb23b android/build.py: prepend "./" to "configure" if path is empty
Fixes in-tree build when the script is called as "android/build.py"
and not "./android/build.py".
2015-01-09 16:51:52 +01:00
Max Kellermann
37e9010887 input/async: reset the "open" flag after seeking successfully
Fixes a problem with the "curl" input plugin: IsEOF() always returns
true because the "open" flag was cleared by
CurlInputStream::RequestDone() when end-of-stream was reached.  This
flag stays false even when seeking to another position has succeeded.

This patch resets the "open" flag to true after seeking successfully.
2015-01-06 12:46:28 +01:00
Max Kellermann
4bd2c75056 thread/Name: disable pthread_setname_np() on NetBSD
NetBSD's pthread_setname_np() prototype is incompatible with the rest
of the world, and it requires to pass the string argument as a
non-const pointer.  Instead of working around this misdesign, I hereby
disable the feature on NetBSD.
2015-01-06 12:08:36 +01:00
Max Kellermann
b9ed850b98 thread/Name: enable FormatThreadName() with prctl()
Add macro HAVE_THREAD_NAME which is set when any method to set the
thread name is available.  Use that macro in FormatThreadName()
instead of just checking for HAVE_PTHREAD_SETNAME_NP.
2015-01-06 12:04:30 +01:00
Max Kellermann
11cea17496 thread/Name: indent preprocessor commands 2015-01-06 12:04:15 +01:00
Max Kellermann
163597ef69 db/simple: fix implicit nullptr/bool conversion
Return false on error, not nullptr.
2014-12-26 14:34:03 +01:00
Max Kellermann
95f84afd33 fs/Traits, ...: work around -Wtautological-pointer-compare
New in clang 3.6.
2014-12-26 14:34:03 +01:00
Max Kellermann
9f7fd1fbfb db/lazy, input/mms: add "override" keywords
Fixes -Winconsistent-missing-override (clang 3.6).
2014-12-26 14:29:29 +01:00
Max Kellermann
940cab8620 Merge branch 'v0.18.x' into v0.19.x 2014-12-26 14:28:52 +01:00
Max Kellermann
5b84c99d79 doc/user: remove autoconf/automake from Debian build dependencies 2014-12-26 14:00:50 +01:00
Max Kellermann
b295024574 doc/user: add more Debian build dependencies 2014-12-26 13:56:26 +01:00
Max Kellermann
34180f1745 doc/user: add libicu-dev to Debian build dependencies 2014-12-26 13:54:33 +01:00
Max Kellermann
665031467a db/proxy, output/shout: fix implicit nullptr/bool conversion
Return false on error, not nullptr.
2014-12-26 13:50:54 +01:00
Max Kellermann
df33171107 db/{simple,proxy}, ...: add "override" keywords
Fixes -Winconsistent-missing-override (clang 3.6).
2014-12-26 13:47:04 +01:00
Max Kellermann
53f4044890 util/{ASCII,UriUtil}, ...: work around -Wtautological-pointer-compare
New in clang 3.6.
2014-12-26 13:43:32 +01:00
Max Kellermann
a5049136ff DatabaseGlue: convert nullptr check to assertion 2014-12-26 13:43:32 +01:00
Max Kellermann
705b3c6b63 util/ASCII: fix indent 2014-12-26 13:37:38 +01:00
Max Kellermann
6b4ac66962 Compiler.h: add macro CLANG_CHECK_VERSION() 2014-12-26 13:31:03 +01:00
Max Kellermann
0964b06240 Compiler.h: add macro GCC_OLDER_THAN() 2014-12-26 13:30:44 +01:00
Max Kellermann
92eeca3ba7 util/Manual: reimplement GCC_CHECK_VERSION() using GCC_MAKE_VERSION() 2014-12-26 13:30:22 +01:00
Max Kellermann
2a86554ac4 Compiler.h: add macro GCC_MAKE_VERSION() 2014-12-26 13:30:11 +01:00
Max Kellermann
805caa30ce configure.ac: prepare for 0.18.22 2014-12-26 13:23:04 +01:00
Max Kellermann
a56949e9fa decoder/ffmpeg: support interleaved floating point 2014-12-23 20:51:08 +01:00
Max Kellermann
43da4c0eca input/mms: limit the mmsx_read() size 2014-12-23 20:34:45 +01:00
Max Kellermann
b9c7771830 decoder/DsdLib: add missing stdlib.h include 2014-12-23 10:08:46 +01:00
Jan Brittenson
35db88affe DSF ID3 tags hitting 4k size limit
Here's a change to dynamically allocate the DSD ID3 tag buffer.
Pretty much anything with cover art is going to exceed the existing,
static 4k limit...  Here's a change to dynamically allocate the buffer
and sanity check it at some upper limit.  I rather arbitrarily pulled
256k out of thin air just to keep a corrupt file from causing it to
trying to allocate a buffer larger than available memory.
2014-12-23 09:49:33 +01:00
Max Kellermann
e38faca455 configure.ac: prepare for 0.19.8 2014-12-23 09:48:31 +01:00
Max Kellermann
0255e8710c android: release v0.19.7 2014-12-23 09:42:52 +01:00
Max Kellermann
6d89020f80 release v0.19.7 2014-12-17 19:20:54 +01:00
Max Kellermann
9c56c49e73 Merge tag 'v0.18.21' into v0.19.x 2014-12-17 19:19:13 +01:00
Max Kellermann
acb798e544 release v0.18.21 2014-12-17 19:13:47 +01:00
Max Kellermann
c5720a15c7 LogBackend: force-flush stderr on WIN32
setvbuf() does not seem to have an effect on Windows.
2014-12-17 19:12:25 +01:00
Max Kellermann
90709b332a LogInit: make stderr line-buffered
Make sure everything gets logged right away.  No delays because
stdio's buffer is not yet full.
2014-12-17 19:12:01 +01:00
Max Kellermann
81f17d10c8 util/HugeAllocator: enable MEM_COMMIT on Windows
Without MEM_COMMIT, the reserved address space is not accessible, and
MPD crashes.
2014-12-17 19:10:58 +01:00
k44
773de38bd9 playlist/embcue: fix filename suffix detection
The definition of the playlist_plugin struct member of the embcue
plugin was incorrect.
2014-12-16 18:43:05 +01:00
Max Kellermann
a48704925d storage/nfs: add timeout 2014-12-15 00:45:13 +01:00
Max Kellermann
fa4beeee75 decoder/ffmpeg: detect and fix negative time stamps
Works around assertion failure due to something that appears to be a
(minor) FFmpeg bug.
2014-12-15 00:40:46 +01:00
Max Kellermann
d8351772d3 configure.ac: prepare for 0.18.21 2014-12-15 00:39:52 +01:00
Max Kellermann
68d1abdb85 storage/nfs: clear last_error in SetState()
Fixes bogus assertion failure.
2014-12-15 00:39:30 +01:00
Max Kellermann
7e8474a85a lib/nfs/Connection: unregister socket with SocketMonitor::Steal()
SocketMonitor::Cancel() does not actually unregister the socket; it
only disables the event.
2014-12-15 00:31:12 +01:00
Max Kellermann
82da364b8b lib/nfs/Connection: implement mount timeout 2014-12-15 00:05:53 +01:00
Max Kellermann
7fa91ec175 lib/nfs/Connection: add debug flag "in_destroy" 2014-12-15 00:03:30 +01:00
Max Kellermann
1d3a09d377 lib/nfs/Connection: add assertion 2014-12-14 22:51:37 +01:00
Max Kellermann
02563a35f0 lib/nfs/Connection: fix reconnect after mount failure
When mounting had not yet finished, SocketMonitor::IsDefined() was
always false, due to the workaround at the beginning of the function
that calls SocketMonitor::Steal().  This commit drops the IsDefined()
check because it was never necessary and breaks reconnect.
2014-12-14 22:49:16 +01:00
Max Kellermann
d653f35bb7 lib/nfs/Connection: fix typo in code comment 2014-12-14 22:49:09 +01:00
Max Kellermann
a543627abd lib/nfs/Connection: fix memory leak (and assertion failure)
nfs_destroy_context() will invoke all pending callbacks with
err==-EINTR.  In CancellableCallback::Callback(), this will invoke
NfsConnection::DeferClose(), which however is only designed to be
called from nfs_service().  In non-debug mode, this will leak memory
because nfs_close_async() is never called.

Workaround: before nfs_destroy_context(), invoke nfs_close_async() on
all pending file handles.
2014-12-14 16:02:47 +01:00
Max Kellermann
80f2ba7fca lib/nfs/Connection: move code to Service() 2014-12-14 15:45:10 +01:00
Max Kellermann
32bca64920 lib/nfs/Connection: add assertions 2014-12-14 15:40:29 +01:00
Max Kellermann
7fa1a84ec3 lib/nfs/Connection: move code to method InternalClose() 2014-12-14 15:38:09 +01:00
Max Kellermann
ab4bb26a0a lib/nfs/Connection: make in_service and in_event debug-only flags 2014-12-14 15:20:40 +01:00
Max Kellermann
4b8d258cff lib/nfs/Connection: fix crash while canceling a failing Open()
The method NfsConnection::CancellableCallback::Callback() will always
invoke NfsConnection::Close() on the file handle, even if the void
pointer is not a nfsfh.  This can happen if the Open() was not
successful, e.g. when the file does not exist.
2014-12-14 15:16:01 +01:00
Max Kellermann
3c29aa6271 event/Loop: read the "again" flag while holding mutex 2014-12-14 14:47:36 +01:00
Max Kellermann
51464b4317 lib/nfs/Connection: add assertions 2014-12-14 14:24:49 +01:00
Max Kellermann
2fec463542 util/HugeAllocator: disable MEM_LARGE_PAGES on Windows
MEM_LARGE_PAGES does not appear to work.  Instead, MEM_RESERVE appears
to be necessary.  Until I figure this out, this large pages are
disabled.
2014-12-12 13:20:58 +01:00
Max Kellermann
1affc641c4 input/Init: eliminate double colon from log message 2014-12-12 13:20:37 +01:00
Max Kellermann
0cfd4fff62 playlist/Print: don't skip non-existent songs in "listplaylist"
Skipping those songs silently will confuse the client, because
commands specifying the song index within a playlist
(e.g. playlistdelete) will be out of sync.

This copies spl_print()'s behavior to playlist_file_print().
2014-12-09 13:36:48 +01:00
Max Kellermann
8904127c10 configure.ac: prepare for 0.19.7 2014-12-09 13:09:03 +01:00
49 changed files with 451 additions and 121 deletions

34
NEWS

@@ -1,3 +1,28 @@
ver 0.19.8 (2015/01/14)
* input
- curl: fix bug after rewinding from end-of-file
- mms: reduce delay at the beginning of playback
* decoder
- dsdiff, dsf: allow ID3 tags larger than 4 kB
- ffmpeg: support interleaved floating point
* fix clang 3.6 warnings
* fix build failure on NetBSD
ver 0.19.7 (2014/12/17)
* input
- nfs: fix crash while canceling a failing file open operation
- nfs: fix memory leak on connection failure
- nfs: fix reconnect after mount failure
- nfs: implement mount timeout (60 seconds)
* storage
- nfs: implement I/O timeout (60 seconds)
* playlist
- embcue: fix filename suffix detection
- don't skip non-existent songs in "listplaylist"
* decoder
- ffmpeg: fix time stamp underflow
* fix memory allocator bug on Windows
ver 0.19.6 (2014/12/08)
* decoder
- ffmpeg: support FFmpeg 2.5
@@ -146,6 +171,15 @@ ver 0.19 (2014/10/10)
* install systemd unit for socket activation
* Android port
ver 0.18.22 (2014/01/14)
* fix clang 3.6 warnings
ver 0.18.21 (2014/12/17)
* playlist
- embcue: fix filename suffix detection
* decoder
- ffmpeg: fix time stamp underflow
ver 0.18.20 (2014/12/08)
* decoder
- ffmpeg: support FFmpeg 2.5

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="10"
android:versionName="0.19.6">
android:versionCode="12"
android:versionName="0.19.8">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>

@@ -23,7 +23,7 @@ if not os.path.isdir(ndk_path):
sys.exit(1)
# the path to the MPD sources
mpd_path = os.path.dirname(os.path.dirname(sys.argv[0]))
mpd_path = os.path.dirname(os.path.dirname(sys.argv[0])) or '.'
# output directories
lib_path = os.path.abspath('lib')

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

@@ -89,7 +89,7 @@ cd mpd-version</programlisting>
</para>
<programlisting>
apt-get install g++ automake autoconf \
apt-get install g++ \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
@@ -98,19 +98,21 @@ apt-get install g++ automake autoconf \
libsidplay2-dev libsidutils-dev libresid-builder-dev \
libavcodec-dev libavformat-dev \
libmp3lame-dev \
libsamplerate0-dev \
libsamplerate0-dev libsoxr-dev \
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
libzzip-dev \
libcurl4-gnutls-dev libyajl-dev \
libcurl4-gnutls-dev libyajl-dev libexpat-dev \
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
libpulse-dev libroar-dev libshout3-dev \
libmpdclient-dev \
libnfs-dev libsmbclient-dev \
libupnp-dev \
libavahi-client-dev \
libsqlite3-dev \
libsystemd-daemon-dev libwrap0-dev \
libcppunit-dev xmlto \
libboost-dev \
libglib2.0-dev
libglib2.0-dev libicu-dev
</programlisting>
<para>

@@ -20,33 +20,45 @@
#ifndef COMPILER_H
#define COMPILER_H
#define GCC_CHECK_VERSION(major, minor) \
(defined(__GNUC__) && \
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
#define GCC_MAKE_VERSION(major, minor, patchlevel) ((major) * 10000 + (minor) * 100 + patchlevel)
#ifdef __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#define GCC_VERSION GCC_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#else
#define GCC_VERSION 0
#endif
#define GCC_CHECK_VERSION(major, minor) \
(defined(__GNUC__) && GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
/**
* Are we building with gcc (not clang or any other compiler) and a
* version older than the specified one?
*/
#define GCC_OLDER_THAN(major, minor) \
(defined(__GNUC__) && !defined(__clang__) && \
GCC_VERSION < GCC_MAKE_VERSION(major, minor, 0))
#ifdef __clang__
# define CLANG_VERSION (__clang_major__ * 10000 \
+ __clang_minor__ * 100 \
+ __clang_patchlevel__)
# define CLANG_VERSION GCC_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
# if __clang_major__ < 3
# error Sorry, your clang version is too old. You need at least version 3.1.
# endif
#elif defined(__GNUC__)
# if !GCC_CHECK_VERSION(4,6)
# if GCC_OLDER_THAN(4,6)
# error Sorry, your gcc version is too old. You need at least version 4.6.
# endif
#else
# warning Untested compiler. Use at your own risk!
#endif
/**
* Are we building with the specified version of clang or newer?
*/
#define CLANG_CHECK_VERSION(major, minor) \
(defined(__clang__) && \
CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
#if GCC_CHECK_VERSION(4,0)
/* GCC 4.x */
@@ -141,7 +153,7 @@
#if defined(__cplusplus)
/* support for C++11 "override" was added in gcc 4.7 */
#if !defined(__clang__) && !GCC_CHECK_VERSION(4,7)
#if GCC_OLDER_THAN(4,7)
#define override
#define final
#endif

@@ -76,7 +76,10 @@ idle_get_names(void)
unsigned
idle_parse_name(const char *name)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(name != nullptr);
#endif
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
if (StringEqualsCaseASCII(name, idle_names[i]))

@@ -194,6 +194,12 @@ FileLog(const Domain &domain, const char *message)
domain.GetName(),
chomp_length(message), message);
#ifdef WIN32
/* force-flush the log file, because setvbuf() does not seem
to have an effect on WIN32 */
fflush(stderr);
#endif
#ifdef HAVE_GLIB
g_free(converted);
#endif

@@ -111,6 +111,9 @@ log_early_init(bool verbose)
#ifdef ANDROID
(void)verbose;
#else
/* force stderr to be line-buffered */
setvbuf(stderr, nullptr, _IOLBF, 0);
if (verbose)
SetLogThreshold(LogLevel::DEBUG);
#endif

@@ -77,7 +77,10 @@ SongFilter::Item::Item(unsigned _tag, time_t _time)
bool
SongFilter::Item::StringMatch(const char *s) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(s != nullptr);
#endif
if (fold_case) {
const std::string folded = IcuCaseFold(s);

@@ -77,7 +77,10 @@ SongLoader::LoadFile(const char *path_utf8, Error &error) const
DetachedSong *
SongLoader::LoadSong(const char *uri_utf8, Error &error) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(uri_utf8 != nullptr);
#endif
if (memcmp(uri_utf8, "file:///", 8) == 0)
/* absolute path */

@@ -43,7 +43,7 @@ public:
virtual const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(const LightSong *song) const;
void ReturnSong(const LightSong *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,

@@ -103,7 +103,7 @@ public:
virtual void Close() override;
virtual const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(const LightSong *song) const;
void ReturnSong(const LightSong *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -731,7 +731,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
{
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
if (!visit_directory && !visit_playlist && selection.recursive &&
(ServerSupportsSearchBase(connection)
@@ -757,7 +757,7 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
{
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
enum mpd_tag_type tag_type2 = Convert(tag_type);
if (tag_type2 == MPD_TAG_COUNT) {
@@ -810,7 +810,7 @@ ProxyDatabase::GetStats(const DatabaseSelection &selection,
// TODO: eliminate the const_cast
if (!const_cast<ProxyDatabase *>(this)->EnsureConnected(error))
return nullptr;
return false;
struct mpd_stats *stats2 =
mpd_run_stats(connection);

@@ -435,9 +435,12 @@ SimpleDatabase::Save(Error &error)
bool
SimpleDatabase::Mount(const char *uri, Database *db, Error &error)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(uri != nullptr);
assert(*uri != 0);
assert(db != nullptr);
#endif
assert(*uri != 0);
ScopeDatabaseLock protect;
@@ -445,13 +448,13 @@ SimpleDatabase::Mount(const char *uri, Database *db, Error &error)
if (r.uri == nullptr) {
error.Format(db_domain, DB_CONFLICT,
"Already exists: %s", uri);
return nullptr;
return false;
}
if (strchr(r.uri, '/') != nullptr) {
error.Format(db_domain, DB_NOT_FOUND,
"Parent not found: %s", uri);
return nullptr;
return false;
}
Directory *mnt = r.directory->CreateChild(r.uri);
@@ -478,7 +481,7 @@ SimpleDatabase::Mount(const char *local_uri, const char *storage_uri,
if (cache_path.IsNull()) {
error.Format(db_domain, DB_NOT_FOUND,
"No 'cache_directory' configured");
return nullptr;
return false;
}
std::string name(storage_uri);

@@ -110,9 +110,9 @@ public:
virtual bool Open(Error &error) override;
virtual void Close() override;
virtual const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(const LightSong *song) const;
const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
void ReturnSong(const LightSong *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,

@@ -85,7 +85,7 @@ public:
virtual void Close() override;
virtual const LightSong *GetSong(const char *uri_utf8,
Error &error) const override;
virtual void ReturnSong(const LightSong *song) const;
void ReturnSong(const LightSong *song) const override;
virtual bool Visit(const DatabaseSelection &selection,
VisitDirectory visit_directory,
@@ -101,7 +101,9 @@ public:
virtual bool GetStats(const DatabaseSelection &selection,
DatabaseStats &stats,
Error &error) const override;
virtual time_t GetUpdateStamp() const {return 0;}
time_t GetUpdateStamp() const override {
return 0;
}
protected:
bool Configure(const config_param &param, Error &error);

@@ -26,7 +26,10 @@
bool
DecoderPlugin::SupportsSuffix(const char *suffix) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(suffix != nullptr);
#endif
return suffixes != nullptr && string_array_contains(suffixes, suffix);
@@ -35,7 +38,10 @@ DecoderPlugin::SupportsSuffix(const char *suffix) const
bool
DecoderPlugin::SupportsMimeType(const char *mime_type) const
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(mime_type != nullptr);
#endif
return mime_types != nullptr &&
string_array_contains(mime_types, mime_type);

@@ -29,8 +29,10 @@
#include "input/InputStream.hxx"
#include "tag/TagId3.hxx"
#include "util/Error.hxx"
#include "util/Alloc.hxx"
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_ID3TAG
#include <id3tag.h>
@@ -123,22 +125,27 @@ dsdlib_tag_id3(InputStream &is,
const id3_length_t count = size - offset;
/* Check and limit id3 tag size to prevent a stack overflow */
id3_byte_t dsdid3[4096];
if (count == 0 || count > sizeof(dsdid3))
if (count < 10 || count > 256*1024)
return;
if (!decoder_read_full(nullptr, is, dsdid3, count))
return;
id3_byte_t *const id3_buf = static_cast<id3_byte_t*>(xalloc(count));
struct id3_tag *id3_tag = id3_tag_parse(dsdid3, count);
if (id3_tag == nullptr)
if (!decoder_read_full(nullptr, is, id3_buf, count)) {
free(id3_buf);
return;
}
struct id3_tag *id3_tag = id3_tag_parse(id3_buf, count);
if (id3_tag == nullptr) {
free(id3_buf);
return;
}
scan_id3_tag(id3_tag, handler, handler_ctx);
id3_tag_delete(id3_tag);
free(id3_buf);
return;
}
#endif

@@ -313,10 +313,13 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
AVFrame *frame,
uint8_t **buffer, int *buffer_size)
{
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start_time_fallback(*stream),
stream->time_base));
if (packet->pts >= 0 && packet->pts != (int64_t)AV_NOPTS_VALUE) {
auto start = start_time_fallback(*stream);
if (packet->pts >= start)
decoder_timestamp(decoder,
time_from_ffmpeg(packet->pts - start,
stream->time_base));
}
AVPacket packet2 = *packet;
@@ -371,6 +374,7 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
case AV_SAMPLE_FMT_S32P:
return SampleFormat::S32;
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
return SampleFormat::FLOAT;

@@ -179,9 +179,10 @@ EventLoop::Run()
mutex.lock();
HandleDeferred();
busy = false;
const bool _again = again;
mutex.unlock();
if (again)
if (_again)
/* re-evaluate timers because one of the
IdleMonitors may have added a new
timeout */

@@ -53,10 +53,11 @@ public:
children.emplace_back(name, filter);
}
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
private:
/**

@@ -34,10 +34,11 @@ class NormalizeFilter final : public Filter {
PcmBuffer buffer;
public:
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
};
static Filter *

@@ -112,10 +112,11 @@ public:
*/
void Update();
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
};
void

@@ -120,10 +120,11 @@ public:
*/
bool Configure(const config_param &param, Error &error);
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
};
bool

@@ -43,10 +43,11 @@ public:
pv.SetVolume(_volume);
}
virtual AudioFormat Open(AudioFormat &af, Error &error) override;
virtual void Close();
virtual ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
void Close() override;
ConstBuffer<void> FilterPCM(ConstBuffer<void> src,
Error &error) override;
};
static constexpr Domain volume_domain("pcm_volume");

@@ -103,7 +103,10 @@ static inline void FixSeparators(std::string &s)
std::string
PathToUTF8(const char *path_fs)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_fs != nullptr);
#endif
#ifdef HAVE_GLIB
if (fs_charset.empty()) {
@@ -144,7 +147,10 @@ PathToUTF8(const char *path_fs)
char *
PathFromUTF8(const char *path_utf8)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_utf8 != nullptr);
#endif
if (fs_charset.empty())
return g_strdup(path_utf8);

@@ -52,7 +52,10 @@ template<typename Traits>
typename Traits::const_pointer
GetBasePathImpl(typename Traits::const_pointer p)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
return sep != nullptr
@@ -64,7 +67,10 @@ template<typename Traits>
typename Traits::string
GetParentPathImpl(typename Traits::const_pointer p)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
if (sep == nullptr)

@@ -57,7 +57,11 @@ struct PathTraitsFS {
gcc_pure gcc_nonnull_all
static const_pointer FindLastSeparator(const_pointer p) {
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
#ifdef WIN32
const_pointer pos = p + GetLength(p);
while (p != pos && !IsSeparator(*pos))
@@ -77,7 +81,11 @@ struct PathTraitsFS {
gcc_pure gcc_nonnull_all
static bool IsAbsolute(const_pointer p) {
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
#ifdef WIN32
if (IsDrive(p) && IsSeparator(p[2]))
return true;
@@ -147,7 +155,11 @@ struct PathTraitsUTF8 {
gcc_pure gcc_nonnull_all
static const_pointer FindLastSeparator(const_pointer p) {
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
return strrchr(p, SEPARATOR);
}
@@ -160,7 +172,11 @@ struct PathTraitsUTF8 {
gcc_pure gcc_nonnull_all
static bool IsAbsolute(const_pointer p) {
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(p != nullptr);
#endif
#ifdef WIN32
if (IsDrive(p) && IsSeparator(p[2]))
return true;

@@ -160,6 +160,11 @@ AsyncInputStream::SeekDone()
assert(io_thread_inside());
assert(IsSeekPending());
/* we may have reached end-of-file previously, and the
connection may have been closed already; however after
seeking successfully, the connection must be alive again */
open = true;
seek_state = SeekState::NONE;
cond.broadcast();
}

@@ -67,7 +67,7 @@ input_stream_global_init(Error &error)
case InputPlugin::InitResult::UNAVAILABLE:
if (error.IsDefined()) {
FormatError(error,
"Input plugin '%s' is unavailable: ",
"Input plugin '%s' is unavailable",
plugin->name);
error.Clear();
}

@@ -122,7 +122,10 @@ InputStream::IsAvailable()
size_t
InputStream::LockRead(void *ptr, size_t _size, Error &error)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(ptr != nullptr);
#endif
assert(_size > 0);
const ScopeLock protect(mutex);

@@ -43,7 +43,7 @@ protected:
virtual size_t ThreadRead(void *ptr, size_t size,
Error &error) override;
virtual void Close() {
void Close() override {
mmsx_close(mms);
}
};
@@ -92,6 +92,13 @@ input_mms_open(const char *url,
size_t
MmsInputStream::ThreadRead(void *ptr, size_t read_size, Error &error)
{
/* unfortunately, mmsx_read() blocks until the whole buffer
has been filled; to avoid big latencies, limit the size of
each chunk we read to a reasonable size */
constexpr size_t MAX_CHUNK = 16384;
if (read_size > MAX_CHUNK)
read_size = MAX_CHUNK;
int nbytes = mmsx_read(nullptr, mms, (char *)ptr, read_size);
if (nbytes <= 0) {
if (nbytes < 0)

@@ -121,8 +121,11 @@ gcc_pure
int
IcuCollate(const char *a, const char *b)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(a != nullptr);
assert(b != nullptr);
#endif
#ifdef HAVE_ICU
assert(collator != nullptr);
@@ -159,7 +162,10 @@ IcuCaseFold(const char *src)
{
#ifdef HAVE_ICU
assert(collator != nullptr);
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(src != nullptr);
#endif
const auto u = UCharFromUTF8(src);
if (u.IsNull())

@@ -20,7 +20,9 @@
#include "config.h"
#include "Blocking.hxx"
#include "Connection.hxx"
#include "Domain.hxx"
#include "event/Call.hxx"
#include "util/Error.hxx"
bool
BlockingNfsOperation::Run(Error &_error)
@@ -31,7 +33,10 @@ BlockingNfsOperation::Run(Error &_error)
[this](){ connection.AddLease(*this); });
/* wait for completion */
LockWaitFinished();
if (!LockWaitFinished()) {
_error.Set(nfs_domain, 0, "Timeout");
return false;
}
/* check for error */
if (error.IsDefined()) {

@@ -35,6 +35,8 @@ class NfsConnection;
* thread, and method Run() waits for completion.
*/
class BlockingNfsOperation : protected NfsCallback, NfsLease {
static constexpr unsigned timeout_ms = 60000;
Mutex mutex;
Cond cond;
@@ -52,10 +54,13 @@ public:
bool Run(Error &error);
private:
void LockWaitFinished() {
bool LockWaitFinished() {
const ScopeLock protect(mutex);
while (!finished)
cond.wait(mutex);
if (!cond.timed_wait(mutex, timeout_ms))
return false;
return true;
}
/**

@@ -157,6 +157,12 @@ public:
return *i;
}
template<typename F>
void ForEach(F &&f) {
for (CT &i : list)
f(i);
}
};
#endif

@@ -34,11 +34,15 @@ extern "C" {
#include <poll.h> /* for POLLIN, POLLOUT */
static constexpr unsigned NFS_MOUNT_TIMEOUT = 60;
inline bool
NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
const char *path,
Error &error)
{
assert(connection.GetEventLoop().IsInside());
int result = nfs_stat_async(ctx, path, Callback, this);
if (result < 0) {
error.Format(nfs_domain, "nfs_stat_async() failed: %s",
@@ -54,6 +58,8 @@ NfsConnection::CancellableCallback::OpenDirectory(nfs_context *ctx,
const char *path,
Error &error)
{
assert(connection.GetEventLoop().IsInside());
int result = nfs_opendir_async(ctx, path, Callback, this);
if (result < 0) {
error.Format(nfs_domain, "nfs_opendir_async() failed: %s",
@@ -69,6 +75,8 @@ NfsConnection::CancellableCallback::Open(nfs_context *ctx,
const char *path, int flags,
Error &error)
{
assert(connection.GetEventLoop().IsInside());
int result = nfs_open_async(ctx, path, flags,
Callback, this);
if (result < 0) {
@@ -85,6 +93,8 @@ NfsConnection::CancellableCallback::Stat(nfs_context *ctx,
struct nfsfh *fh,
Error &error)
{
assert(connection.GetEventLoop().IsInside());
int result = nfs_fstat_async(ctx, fh, Callback, this);
if (result < 0) {
error.Format(nfs_domain, "nfs_fstat_async() failed: %s",
@@ -100,6 +110,8 @@ NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
uint64_t offset, size_t size,
Error &error)
{
assert(connection.GetEventLoop().IsInside());
int result = nfs_pread_async(ctx, fh, offset, size, Callback, this);
if (result < 0) {
error.Format(nfs_domain, "nfs_pread_async() failed: %s",
@@ -113,6 +125,7 @@ NfsConnection::CancellableCallback::Read(nfs_context *ctx, struct nfsfh *fh,
inline void
NfsConnection::CancellableCallback::CancelAndScheduleClose(struct nfsfh *fh)
{
assert(connection.GetEventLoop().IsInside());
assert(!open);
assert(close_fh == nullptr);
assert(fh != nullptr);
@@ -121,9 +134,22 @@ NfsConnection::CancellableCallback::CancelAndScheduleClose(struct nfsfh *fh)
Cancel();
}
inline void
NfsConnection::CancellableCallback::PrepareDestroyContext()
{
assert(IsCancelled());
if (close_fh != nullptr) {
connection.InternalClose(close_fh);
close_fh = nullptr;
}
}
inline void
NfsConnection::CancellableCallback::Callback(int err, void *data)
{
assert(connection.GetEventLoop().IsInside());
if (!IsCancelled()) {
assert(close_fh == nullptr);
@@ -143,8 +169,10 @@ NfsConnection::CancellableCallback::Callback(int err, void *data)
allocated file handle immediately */
assert(close_fh == nullptr);
struct nfsfh *fh = (struct nfsfh *)data;
connection.Close(fh);
if (err >= 0) {
struct nfsfh *fh = (struct nfsfh *)data;
connection.Close(fh);
}
} else if (close_fh != nullptr)
connection.DeferClose(close_fh);
@@ -209,6 +237,7 @@ NfsConnection::RemoveLease(NfsLease &lease)
bool
NfsConnection::Stat(const char *path, NfsCallback &callback, Error &error)
{
assert(GetEventLoop().IsInside());
assert(!callbacks.Contains(callback));
auto &c = callbacks.Add(callback, *this, false);
@@ -225,6 +254,7 @@ bool
NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
Error &error)
{
assert(GetEventLoop().IsInside());
assert(!callbacks.Contains(callback));
auto &c = callbacks.Add(callback, *this, true);
@@ -240,12 +270,16 @@ NfsConnection::OpenDirectory(const char *path, NfsCallback &callback,
const struct nfsdirent *
NfsConnection::ReadDirectory(struct nfsdir *dir)
{
assert(GetEventLoop().IsInside());
return nfs_readdir(context, dir);
}
void
NfsConnection::CloseDirectory(struct nfsdir *dir)
{
assert(GetEventLoop().IsInside());
return nfs_closedir(context, dir);
}
@@ -253,6 +287,7 @@ bool
NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
Error &error)
{
assert(GetEventLoop().IsInside());
assert(!callbacks.Contains(callback));
auto &c = callbacks.Add(callback, *this, true);
@@ -268,6 +303,7 @@ NfsConnection::Open(const char *path, int flags, NfsCallback &callback,
bool
NfsConnection::Stat(struct nfsfh *fh, NfsCallback &callback, Error &error)
{
assert(GetEventLoop().IsInside());
assert(!callbacks.Contains(callback));
auto &c = callbacks.Add(callback, *this, false);
@@ -284,6 +320,7 @@ bool
NfsConnection::Read(struct nfsfh *fh, uint64_t offset, size_t size,
NfsCallback &callback, Error &error)
{
assert(GetEventLoop().IsInside());
assert(!callbacks.Contains(callback));
auto &c = callbacks.Add(callback, *this, false);
@@ -307,10 +344,22 @@ DummyCallback(int, struct nfs_context *, void *, void *)
{
}
inline void
NfsConnection::InternalClose(struct nfsfh *fh)
{
assert(GetEventLoop().IsInside());
assert(context != nullptr);
assert(fh != nullptr);
nfs_close_async(context, fh, DummyCallback, nullptr);
}
void
NfsConnection::Close(struct nfsfh *fh)
{
nfs_close_async(context, fh, DummyCallback, nullptr);
assert(GetEventLoop().IsInside());
InternalClose(fh);
ScheduleSocket();
}
@@ -327,12 +376,26 @@ NfsConnection::DestroyContext()
assert(GetEventLoop().IsInside());
assert(context != nullptr);
#ifndef NDEBUG
assert(!in_destroy);
in_destroy = true;
#endif
if (!mount_finished) {
assert(TimeoutMonitor::IsActive());
TimeoutMonitor::Cancel();
}
/* cancel pending DeferredMonitor that was scheduled to notify
new leases */
DeferredMonitor::Cancel();
if (SocketMonitor::IsDefined())
SocketMonitor::Cancel();
SocketMonitor::Steal();
callbacks.ForEach([](CancellableCallback &c){
c.PrepareDestroyContext();
});
nfs_destroy_context(context);
context = nullptr;
@@ -341,8 +404,11 @@ NfsConnection::DestroyContext()
inline void
NfsConnection::DeferClose(struct nfsfh *fh)
{
assert(GetEventLoop().IsInside());
assert(in_event);
assert(in_service);
assert(context != nullptr);
assert(fh != nullptr);
deferred_close.push_front(fh);
}
@@ -350,6 +416,7 @@ NfsConnection::DeferClose(struct nfsfh *fh)
void
NfsConnection::ScheduleSocket()
{
assert(GetEventLoop().IsInside());
assert(context != nullptr);
if (!SocketMonitor::IsDefined()) {
@@ -364,9 +431,35 @@ NfsConnection::ScheduleSocket()
SocketMonitor::Schedule(libnfs_to_events(nfs_which_events(context)));
}
inline int
NfsConnection::Service(unsigned flags)
{
assert(GetEventLoop().IsInside());
assert(context != nullptr);
#ifndef NDEBUG
assert(!in_event);
in_event = true;
assert(!in_service);
in_service = true;
#endif
int result = nfs_service(context, events_to_libnfs(flags));
#ifndef NDEBUG
assert(context != nullptr);
assert(in_service);
in_service = false;
#endif
return result;
}
bool
NfsConnection::OnSocketReady(unsigned flags)
{
assert(GetEventLoop().IsInside());
assert(deferred_close.empty());
bool closed = false;
@@ -378,21 +471,10 @@ NfsConnection::OnSocketReady(unsigned flags)
re-register it each time */
SocketMonitor::Steal();
assert(!in_event);
in_event = true;
assert(!in_service);
in_service = true;
int result = nfs_service(context, events_to_libnfs(flags));
assert(context != nullptr);
assert(in_service);
in_service = false;
const int result = Service(flags);
while (!deferred_close.empty()) {
nfs_close_async(context, deferred_close.front(),
DummyCallback, nullptr);
InternalClose(deferred_close.front());
deferred_close.pop_front();
}
@@ -413,9 +495,9 @@ NfsConnection::OnSocketReady(unsigned flags)
DestroyContext();
closed = true;
} else if (SocketMonitor::IsDefined() && nfs_get_fd(context) < 0) {
} else if (nfs_get_fd(context) < 0) {
/* this happens when rpc_reconnect_requeue() is called
after the connection broke, but autoreconnet was
after the connection broke, but autoreconnect was
disabled - nfs_service() returns 0 */
Error error;
const char *msg = nfs_get_error(context);
@@ -431,8 +513,12 @@ NfsConnection::OnSocketReady(unsigned flags)
closed = true;
}
assert(context == nullptr || nfs_get_fd(context) >= 0);
#ifndef NDEBUG
assert(in_event);
in_event = false;
#endif
if (context != nullptr)
ScheduleSocket();
@@ -444,10 +530,14 @@ inline void
NfsConnection::MountCallback(int status, gcc_unused nfs_context *nfs,
gcc_unused void *data)
{
assert(GetEventLoop().IsInside());
assert(context == nfs);
mount_finished = true;
assert(TimeoutMonitor::IsActive() || in_destroy);
TimeoutMonitor::Cancel();
if (status < 0) {
postponed_mount_error.Format(nfs_domain, status,
"nfs_mount_async() failed: %s",
@@ -468,6 +558,7 @@ NfsConnection::MountCallback(int status, nfs_context *nfs, void *data,
inline bool
NfsConnection::MountInternal(Error &error)
{
assert(GetEventLoop().IsInside());
assert(context == nullptr);
context = nfs_init_context();
@@ -478,8 +569,14 @@ NfsConnection::MountInternal(Error &error)
postponed_mount_error.Clear();
mount_finished = false;
TimeoutMonitor::ScheduleSeconds(NFS_MOUNT_TIMEOUT);
#ifndef NDEBUG
in_service = false;
in_event = false;
in_destroy = false;
#endif
if (nfs_mount_async(context, server.c_str(), export_name.c_str(),
MountCallback, this) != 0) {
@@ -535,9 +632,23 @@ NfsConnection::BroadcastError(Error &&error)
BroadcastMountError(std::move(error));
}
void
NfsConnection::OnTimeout()
{
assert(GetEventLoop().IsInside());
assert(!mount_finished);
mount_finished = true;
DestroyContext();
BroadcastMountError(Error(nfs_domain, "Mount timeout"));
}
void
NfsConnection::RunDeferred()
{
assert(GetEventLoop().IsInside());
if (context == nullptr) {
Error error;
if (!MountInternal(error)) {

@@ -23,6 +23,7 @@
#include "Lease.hxx"
#include "Cancellable.hxx"
#include "event/SocketMonitor.hxx"
#include "event/TimeoutMonitor.hxx"
#include "event/DeferredMonitor.hxx"
#include "util/Error.hxx"
@@ -40,7 +41,7 @@ class NfsCallback;
/**
* An asynchronous connection to a NFS server.
*/
class NfsConnection : SocketMonitor, DeferredMonitor {
class NfsConnection : SocketMonitor, TimeoutMonitor, DeferredMonitor {
class CancellableCallback : public CancellablePointer<NfsCallback> {
NfsConnection &connection;
@@ -84,6 +85,13 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
*/
void CancelAndScheduleClose(struct nfsfh *fh);
/**
* Called by NfsConnection::DestroyContext() right
* before nfs_destroy_context(). This object is given
* a chance to prepare for the latter.
*/
void PrepareDestroyContext();
private:
static void Callback(int err, struct nfs_context *nfs,
void *data, void *private_data);
@@ -111,6 +119,7 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
Error postponed_mount_error;
#ifndef NDEBUG
/**
* True when nfs_service() is being called.
*/
@@ -122,13 +131,20 @@ class NfsConnection : SocketMonitor, DeferredMonitor {
*/
bool in_event;
/**
* True when DestroyContext() is being called.
*/
bool in_destroy;
#endif
bool mount_finished;
public:
gcc_nonnull_all
NfsConnection(EventLoop &_loop,
const char *_server, const char *_export_name)
:SocketMonitor(_loop), DeferredMonitor(_loop),
:SocketMonitor(_loop), TimeoutMonitor(_loop),
DeferredMonitor(_loop),
server(_server), export_name(_export_name),
context(nullptr) {}
@@ -184,6 +200,11 @@ protected:
private:
void DestroyContext();
/**
* Wrapper for nfs_close_async().
*/
void InternalClose(struct nfsfh *fh);
/**
* Invoke nfs_close_async() after nfs_service() returns.
*/
@@ -200,9 +221,17 @@ private:
void ScheduleSocket();
/**
* Wrapper for nfs_service().
*/
int Service(unsigned flags);
/* virtual methods from SocketMonitor */
virtual bool OnSocketReady(unsigned flags) override;
/* virtual methods from TimeoutMonitor */
void OnTimeout() final;
/* virtual methods from DeferredMonitor */
virtual void RunDeferred() override;
};

@@ -109,7 +109,7 @@ ShoutOutput::Configure(const config_param &param, Error &error)
if (!audio_format.IsFullyDefined()) {
error.Set(config_domain,
"Need full audio format specification");
return nullptr;
return false;
}
const char *host = require_block_string(param, "host");

@@ -44,7 +44,7 @@ PcmFormatConverter::Open(SampleFormat _src_format, SampleFormat _dest_format,
"PCM conversion from %s to %s is not implemented",
sample_format_to_string(_src_format),
sample_format_to_string(_dest_format));
return nullptr;
return false;
case SampleFormat::S16:
case SampleFormat::S24_P32:

@@ -43,12 +43,13 @@ playlist_provider_print(Client &client, const char *uri,
DetachedSong *song;
while ((song = e.NextSong()) != nullptr) {
if (playlist_check_translate_song(*song, base_uri.c_str(),
loader)) {
if (detail)
song_print_info(client, *song);
else
song_print_uri(client, *song);
}
loader) &&
detail)
song_print_info(client, *song);
else
/* fallback if no detail was requested or no
detail was available */
song_print_uri(client, *song);
delete song;
}

@@ -178,7 +178,7 @@ const struct playlist_plugin embcue_playlist_plugin = {
embcue_playlist_open_uri,
nullptr,
nullptr,
embcue_playlist_suffixes,
nullptr,
nullptr,
};

@@ -146,6 +146,7 @@ private:
const ScopeLock protect(mutex);
state = _state;
last_error.Clear();
last_error.Set(error);
cond.broadcast();
}
@@ -287,7 +288,7 @@ NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow,
return false;
if (!WaitConnected(error))
return nullptr;
return false;
NfsGetInfoOperation operation(*connection, path.c_str(), info);
return operation.Run(error);

@@ -182,7 +182,10 @@ TagBuilder::Complement(const Tag &other)
inline void
TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
assert(length > 0);
auto f = FixTagString(value, length);
@@ -203,7 +206,10 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
void
TagBuilder::AddItem(TagType type, const char *value, size_t length)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
if (length == 0 || ignore_tag_items[type])
return;
@@ -214,7 +220,10 @@ TagBuilder::AddItem(TagType type, const char *value, size_t length)
void
TagBuilder::AddItem(TagType type, const char *value)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(value != nullptr);
#endif
AddItem(type, value, strlen(value));
}

@@ -20,17 +20,25 @@
#ifndef MPD_THREAD_NAME_HXX
#define MPD_THREAD_NAME_HXX
#ifdef HAVE_PTHREAD_SETNAME_NP
#include <pthread.h>
#include <stdio.h>
#if defined(HAVE_PTHREAD_SETNAME_NP) && !defined(__NetBSD__)
# define HAVE_THREAD_NAME
# include <pthread.h>
# include <stdio.h>
#elif defined(HAVE_PRCTL)
#include <sys/prctl.h>
# include <sys/prctl.h>
# ifdef PR_SET_NAME
# define HAVE_THREAD_NAME
# endif
#endif
static inline void
SetThreadName(const char *name)
{
#ifdef HAVE_PTHREAD_SETNAME_NP
#if defined(HAVE_PTHREAD_SETNAME_NP) && !defined(__NetBSD__)
/* not using pthread_setname_np() on NetBSD because it
requires a non-const pointer argument, which we don't have
here */
#ifdef __APPLE__
pthread_setname_np(name);
#else
@@ -47,7 +55,7 @@ template<typename... Args>
static inline void
FormatThreadName(const char *fmt, gcc_unused Args&&... args)
{
#ifdef HAVE_PTHREAD_SETNAME_NP
#ifdef HAVE_THREAD_NAME
char buffer[16];
snprintf(buffer, sizeof(buffer), fmt, args...);
SetThreadName(buffer);

@@ -43,24 +43,30 @@ gcc_pure gcc_nonnull_all
static inline bool
StringEqualsCaseASCII(const char *a, const char *b)
{
assert(a != nullptr);
assert(b != nullptr);
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(a != nullptr);
assert(b != nullptr);
#endif
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strcasecmp(a, b) == 0;
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strcasecmp(a, b) == 0;
}
gcc_pure gcc_nonnull_all
static inline bool
StringEqualsCaseASCII(const char *a, const char *b, size_t n)
{
assert(a != nullptr);
assert(b != nullptr);
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(a != nullptr);
assert(b != nullptr);
#endif
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strncasecmp(a, b, n) == 0;
/* note: strcasecmp() depends on the locale, but for ASCII-only
strings, it's safe to use */
return strncasecmp(a, b, n) == 0;
}
#endif

@@ -70,7 +70,10 @@ gcc_malloc
static inline void *
HugeAllocate(size_t size)
{
return VirtualAlloc(nullptr, size, MEM_LARGE_PAGES, PAGE_READWRITE);
// TODO: use MEM_LARGE_PAGES
return VirtualAlloc(nullptr, size,
MEM_COMMIT|MEM_RESERVE,
PAGE_READWRITE);
}
static inline void

@@ -35,7 +35,7 @@
#include <new>
#include <utility>
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
#if GCC_OLDER_THAN(4,8)
#include <type_traits>
#endif
@@ -54,7 +54,7 @@
*/
template<class T>
class Manual {
#if !defined(__clang__) && __GNUC__ && !GCC_CHECK_VERSION(4,8)
#if GCC_OLDER_THAN(4,8)
/* no alignas() on gcc < 4.8: apply worst-case fallback */
__attribute__((aligned(8)))
#else

@@ -140,8 +140,11 @@ uri_remove_auth(const char *uri)
bool
uri_is_child(const char *parent, const char *child)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(parent != nullptr);
assert(child != nullptr);
#endif
const size_t parent_length = strlen(parent);
return memcmp(parent, child, parent_length) == 0 &&