release v0.20.4

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEA5IzWngIOJSkMBxDI26KWMbbRRIFAliSTDkQHG1heEBtdXNp
 Y3BkLm9yZwAKCRAjbopYxttFEsIQD/4iNkylzLp8mID2aFT690MFzv4TRXi2XS7v
 r3Rlx3hpGyDdzeXZeFc5zxsc9Ei8OfLcdFC/Umj9LjQanXakOxwsdhagrW9cadNX
 YLxkyVcREXalmzUvoWeRnya1LjoTdYA8llvG2tAJosXVr0o/GHZi56aHcrYnW2a6
 XD8kEk5k9beuEcBLk1rdZCTGPbVLwCFvMcpZ7j5Hd4kDGQjjw2aoEaPWchJdhLQh
 p+GRSU+A8hyTo9zy+aNO3cKvq6zqVxDLlHnIqh8XPWQoLPyWuD7ETvwERKmdmiPZ
 bSo0MR7azTlhkWbNZxjPHgZuacJDlwKvXPg1ofjn8VVcaVe5ONeX+1WP0ozUYqyU
 fmhLxMHKuwZcKo6do/jNhAVp//VBWhSwJHPA8kjBTuZHHc0HvgyTxlAgvzlrSswe
 dxc8vnvzgJfUKz5k7mf3amVg6Cu1CmNi59CkyL0NL+8N0inyMfdeQuQEYgbPoI6X
 jIRwACfXpMX75VtiDaNpnFLBjL5emE6u2bDoU2c5ezgpthaWjb0PqSmoLBBF8TNm
 k0ecXlIwCjT3pDcqmFdqgG3AJiYLTgX0rETC8PInl6toLzr2oVMVlijU3YK5PjMl
 nTvgs8TwprTWImgcBnidqRMb39p3AKs12pHfZ4Y5Iu82Bm60acZQMkv6sQh43Wyc
 +W2+T3D2IA==
 =b2Fz
 -----END PGP SIGNATURE-----

Merge tag 'v0.20.4'

release v0.20.4
This commit is contained in:
Max Kellermann 2017-02-01 22:05:33 +01:00
commit df4af2b550
11 changed files with 58 additions and 42 deletions

8
NEWS
View File

@ -1,5 +1,13 @@
ver 0.21 (not yet released) ver 0.21 (not yet released)
ver 0.20.4 (2017/02/01)
* input
- nfs: fix freeze after reconnect
* output
- sndio: work around a libroar C++ incompatibility
* workaround for GCC 4.9 "constexpr" bug
* fix FreeBSD build failure
ver 0.20.3 (2017/01/25) ver 0.20.3 (2017/01/25)
* protocol * protocol
- "playlistadd" creates new playlist if it does not exist, as documented - "playlistadd" creates new playlist if it does not exist, as documented

View File

@ -19,8 +19,8 @@ libvorbis = AutotoolsProject(
) )
opus = AutotoolsProject( opus = AutotoolsProject(
'http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz', 'http://downloads.xiph.org/releases/opus/opus-1.1.4.tar.gz',
'32bbb6b557fe1b6066adc0ae1f08b629', '9122b6b380081dd2665189f97bfd777f04f92dc3ab6698eea1dbb27ad59d8692',
'lib/libopus.a', 'lib/libopus.a',
['--disable-shared', '--enable-static'], ['--disable-shared', '--enable-static'],
) )

View File

@ -62,7 +62,7 @@ Print(Response &r, TagType group, const TagCountMap &m)
} }
} }
static bool static void
stats_visitor_song(SearchStats &stats, const LightSong &song) stats_visitor_song(SearchStats &stats, const LightSong &song)
{ {
stats.n_songs++; stats.n_songs++;
@ -70,8 +70,6 @@ stats_visitor_song(SearchStats &stats, const LightSong &song)
const auto duration = song.GetDuration(); const auto duration = song.GetDuration();
if (!duration.IsNegative()) if (!duration.IsNegative())
stats.total_duration += duration; stats.total_duration += duration;
return true;
} }
static bool static bool
@ -94,7 +92,7 @@ CollectGroupCounts(TagCountMap &map, TagType group, const Tag &tag)
return found; return found;
} }
static bool static void
GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song) GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
{ {
assert(song.tag != nullptr); assert(song.tag != nullptr);
@ -103,8 +101,6 @@ GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST) if (!CollectGroupCounts(map, group, tag) && group == TAG_ALBUM_ARTIST)
/* fall back to "Artist" if no "AlbumArtist" was found */ /* fall back to "Artist" if no "AlbumArtist" was found */
CollectGroupCounts(map, TAG_ARTIST, tag); CollectGroupCounts(map, TAG_ARTIST, tag);
return true;
} }
void void

View File

@ -27,13 +27,12 @@
#include <functional> #include <functional>
static bool static void
AddSong(const Storage &storage, const char *playlist_path_utf8, AddSong(const Storage &storage, const char *playlist_path_utf8,
const LightSong &song) const LightSong &song)
{ {
spl_append_song(playlist_path_utf8, spl_append_song(playlist_path_utf8,
DatabaseDetachSong(storage, song)); DatabaseDetachSong(storage, song));
return true;
} }
void void

View File

@ -49,16 +49,14 @@ PrintDirectoryURI(Response &r, bool base, const LightDirectory &directory)
ApplyBaseFlag(directory.GetPath(), base)); ApplyBaseFlag(directory.GetPath(), base));
} }
static bool static void
PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory) PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
{ {
if (!directory.IsRoot()) if (!directory.IsRoot())
PrintDirectoryURI(r, base, directory); PrintDirectoryURI(r, base, directory);
return true;
} }
static bool static void
PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory) PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
{ {
if (!directory.IsRoot()) { if (!directory.IsRoot()) {
@ -67,8 +65,6 @@ PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
if (directory.mtime > 0) if (directory.mtime > 0)
time_print(r, "Last-Modified", directory.mtime); time_print(r, "Last-Modified", directory.mtime);
} }
return true;
} }
static void static void
@ -96,7 +92,7 @@ print_playlist_in_directory(Response &r, bool base,
directory->GetPath(), name_utf8); directory->GetPath(), name_utf8);
} }
static bool static void
PrintSongBrief(Response &r, Partition &partition, PrintSongBrief(Response &r, Partition &partition,
bool base, const LightSong &song) bool base, const LightSong &song)
{ {
@ -106,11 +102,9 @@ PrintSongBrief(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */ /* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
song.directory, song.uri); song.directory, song.uri);
return true;
} }
static bool static void
PrintSongFull(Response &r, Partition &partition, PrintSongFull(Response &r, Partition &partition,
bool base, const LightSong &song) bool base, const LightSong &song)
{ {
@ -120,21 +114,18 @@ PrintSongFull(Response &r, Partition &partition,
/* this song file has an embedded CUE sheet */ /* this song file has an embedded CUE sheet */
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
song.directory, song.uri); song.directory, song.uri);
return true;
} }
static bool static void
PrintPlaylistBrief(Response &r, bool base, PrintPlaylistBrief(Response &r, bool base,
const PlaylistInfo &playlist, const PlaylistInfo &playlist,
const LightDirectory &directory) const LightDirectory &directory)
{ {
print_playlist_in_directory(r, base, print_playlist_in_directory(r, base,
&directory, playlist.name.c_str()); &directory, playlist.name.c_str());
return true;
} }
static bool static void
PrintPlaylistFull(Response &r, bool base, PrintPlaylistFull(Response &r, bool base,
const PlaylistInfo &playlist, const PlaylistInfo &playlist,
const LightDirectory &directory) const LightDirectory &directory)
@ -144,8 +135,6 @@ PrintPlaylistFull(Response &r, bool base,
if (playlist.mtime > 0) if (playlist.mtime > 0)
time_print(r, "Last-Modified", playlist.mtime); time_print(r, "Last-Modified", playlist.mtime);
return true;
} }
void void
@ -191,15 +180,13 @@ db_selection_print(Response &r, Partition &partition,
0, std::numeric_limits<int>::max()); 0, std::numeric_limits<int>::max());
} }
static bool static void
PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song) PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
{ {
song_print_uri(r, partition, song); song_print_uri(r, partition, song);
return true;
} }
static bool static void
PrintUniqueTag(Response &r, TagType tag_type, PrintUniqueTag(Response &r, TagType tag_type,
const Tag &tag) const Tag &tag)
{ {
@ -211,8 +198,6 @@ PrintUniqueTag(Response &r, TagType tag_type,
if (item.type != tag_type) if (item.type != tag_type)
r.Format("%s: %s\n", r.Format("%s: %s\n",
tag_item_names[item.type], item.value); tag_item_names[item.type], item.value);
return true;
} }
void void

View File

@ -27,14 +27,13 @@
#include <functional> #include <functional>
static bool static void
AddToQueue(Partition &partition, const LightSong &song) AddToQueue(Partition &partition, const LightSong &song)
{ {
const Storage &storage = *partition.instance.storage; const Storage &storage = *partition.instance.storage;
partition.playlist.AppendSong(partition.pc, partition.playlist.AppendSong(partition.pc,
DatabaseDetachSong(storage, DatabaseDetachSong(storage,
song)); song));
return true;
} }
void void

View File

@ -67,15 +67,13 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
} }
} }
static bool static void
StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums, StatsVisitSong(DatabaseStats &stats, StringSet &artists, StringSet &albums,
const LightSong &song) const LightSong &song)
{ {
++stats.song_count; ++stats.song_count;
StatsVisitTag(stats, artists, albums, *song.tag); StatsVisitTag(stats, artists, albums, *song.tag);
return true;
} }
DatabaseStats DatabaseStats

View File

@ -396,6 +396,17 @@ NfsConnection::ScheduleSocket()
assert(GetEventLoop().IsInside()); assert(GetEventLoop().IsInside());
assert(context != nullptr); assert(context != nullptr);
const int which_events = nfs_which_events(context);
if (which_events == POLLOUT && SocketMonitor::IsDefined())
/* kludge: if libnfs asks only for POLLOUT, it means
that it is currently waiting for the connect() to
finish - rpc_reconnect_requeue() may have been
called from inside nfs_service(); we must now
unregister the old socket and register the new one
instead */
SocketMonitor::Steal();
if (!SocketMonitor::IsDefined()) { if (!SocketMonitor::IsDefined()) {
int _fd = nfs_get_fd(context); int _fd = nfs_get_fd(context);
if (_fd < 0) if (_fd < 0)
@ -405,7 +416,8 @@ NfsConnection::ScheduleSocket()
SocketMonitor::Open(_fd); SocketMonitor::Open(_fd);
} }
SocketMonitor::Schedule(libnfs_to_events(nfs_which_events(context))); SocketMonitor::Schedule(libnfs_to_events(which_events)
| SocketMonitor::HANGUP);
} }
inline int inline int
@ -442,10 +454,14 @@ NfsConnection::OnSocketReady(unsigned flags)
bool closed = false; bool closed = false;
const bool was_mounted = mount_finished; const bool was_mounted = mount_finished;
if (!mount_finished) if (!mount_finished || (flags & SocketMonitor::HANGUP) != 0)
/* until the mount is finished, the NFS client may use /* until the mount is finished, the NFS client may use
various sockets, therefore we unregister and various sockets, therefore we unregister and
re-register it each time */ re-register it each time */
/* also re-register the socket if we got a HANGUP,
which is a sure sign that libnfs will close the
socket, which can lead to a race condition if
epoll_ctl() is called later */
SocketMonitor::Steal(); SocketMonitor::Steal();
const int result = Service(flags); const int result = Service(flags);

View File

@ -24,8 +24,16 @@
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
/* work around a C++ incompatibility if the sndio API is emulated by
libroar: libroar's "struct roar_service_stream" has a member named
"new", which is an illegal identifier in C++ */
#define new new_
#include <sndio.h> #include <sndio.h>
/* undo the libroar workaround */
#undef new
#include <stdexcept> #include <stdexcept>
#ifndef SIO_DEVANY #ifndef SIO_DEVANY

View File

@ -64,7 +64,10 @@ enum class SampleFormat : uint8_t {
/** /**
* Checks whether the sample format is valid. * Checks whether the sample format is valid.
*/ */
static constexpr inline bool #if !GCC_OLDER_THAN(5,0)
constexpr
#endif
static inline bool
audio_valid_sample_format(SampleFormat format) audio_valid_sample_format(SampleFormat format)
{ {
switch (format) { switch (format) {
@ -83,7 +86,10 @@ audio_valid_sample_format(SampleFormat format)
return false; return false;
} }
static constexpr inline unsigned #if !GCC_OLDER_THAN(5,0)
constexpr
#endif
static inline unsigned
sample_format_size(SampleFormat format) sample_format_size(SampleFormat format)
{ {
switch (format) { switch (format) {

View File

@ -36,6 +36,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <new> #include <new>
#include <cstdlib>
/** /**
* Allocate and construct a variable-size object. That is useful for * Allocate and construct a variable-size object. That is useful for