Commit 43a43c1e authored by Max Kellermann's avatar Max Kellermann

Merge tag 'v0.20.19'

release v0.20.19
parents e08598e7 7b94f0e3
...@@ -31,11 +31,18 @@ ver 0.21 (not yet released) ...@@ -31,11 +31,18 @@ ver 0.21 (not yet released)
- opus: support for sending metadata using ogg stream chaining - opus: support for sending metadata using ogg stream chaining
* require GCC 5.0 * require GCC 5.0
ver 0.20.19 (not yet released) ver 0.20.19 (2018/04/26)
* protocol * protocol
- validate absolute seek time, reject negative values - validate absolute seek time, reject negative values
* database
- proxy: fix "search already in progress" errors
- proxy: implement "list ... group"
* input * input
- mms: fix lockup bug and a crash bug - mms: fix lockup bug and a crash bug
* decoder
- ffmpeg: fix av_register_all() deprecation warning (FFmpeg 4.0)
* player
- fix spurious "Not seekable" error when switching radio streams
* macOS: fix crash bug * macOS: fix crash bug
ver 0.20.18 (2018/02/24) ver 0.20.18 (2018/02/24)
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd" package="org.musicpd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="17" android:versionCode="18"
android:versionName="0.20.18"> android:versionName="0.20.19">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/>
......
...@@ -17,8 +17,8 @@ libogg = AutotoolsProject( ...@@ -17,8 +17,8 @@ libogg = AutotoolsProject(
) )
libvorbis = AutotoolsProject( libvorbis = AutotoolsProject(
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz', 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.xz',
'28cb28097c07a735d6af56e598e1c90f', 'af00bb5a784e7c9e69f56823de4637c350643deedaf333d0fa86ecdba6fcb415',
'lib/libvorbis.a', 'lib/libvorbis.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
...@@ -105,8 +105,8 @@ liblame = AutotoolsProject( ...@@ -105,8 +105,8 @@ liblame = AutotoolsProject(
) )
ffmpeg = FfmpegProject( ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-3.4.2.tar.xz', 'http://ffmpeg.org/releases/ffmpeg-4.0.tar.xz',
'2b92e9578ef8b3e49eeab229e69305f5f4cbc1fdaa22e927fc7fca18acccd740', 'ed945daf40b124e77a685893cc025d086f638bc703183460aff49508edb3a43f',
'lib/libavcodec.a', 'lib/libavcodec.a',
[ [
'--disable-shared', '--enable-static', '--disable-shared', '--enable-static',
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "tag/Builder.hxx" #include "tag/Builder.hxx"
#include "tag/Tag.hxx" #include "tag/Tag.hxx"
#include "tag/Mask.hxx" #include "tag/Mask.hxx"
#include "tag/ParseName.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "protocol/Ack.hxx" #include "protocol/Ack.hxx"
...@@ -335,6 +336,35 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection) ...@@ -335,6 +336,35 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection)
return true; return true;
} }
static bool
SendGroupMask(mpd_connection *connection, TagMask mask)
{
#if LIBMPDCLIENT_CHECK_VERSION(2,12,0)
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) {
const auto tag_type = TagType(i);
if (!mask.Test(tag_type))
continue;
const auto tag = Convert(tag_type);
if (tag == MPD_TAG_COUNT)
throw std::runtime_error("Unsupported tag");
if (!mpd_search_add_group_tag(connection, tag))
return false;
}
return true;
#else
(void)connection;
(void)mask;
if (mask.TestAny())
throw std::runtime_error("Grouping requires libmpdclient 2.12");
return true;
#endif
}
ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener, ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener,
const ConfigBlock &block) const ConfigBlock &block)
:Database(proxy_db_plugin), :Database(proxy_db_plugin),
...@@ -700,7 +730,7 @@ static void ...@@ -700,7 +730,7 @@ static void
SearchSongs(struct mpd_connection *connection, SearchSongs(struct mpd_connection *connection,
const DatabaseSelection &selection, const DatabaseSelection &selection,
VisitSong visit_song) VisitSong visit_song)
{ try {
assert(selection.recursive); assert(selection.recursive);
assert(visit_song); assert(visit_song);
...@@ -727,6 +757,11 @@ SearchSongs(struct mpd_connection *connection, ...@@ -727,6 +757,11 @@ SearchSongs(struct mpd_connection *connection,
if (!mpd_response_finish(connection)) if (!mpd_response_finish(connection))
ThrowError(connection); ThrowError(connection);
} catch (...) {
if (connection != nullptr)
mpd_search_cancel(connection);
throw;
} }
/** /**
...@@ -774,9 +809,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection, ...@@ -774,9 +809,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
void void
ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
TagType tag_type, TagType tag_type,
gcc_unused TagMask group_mask, TagMask group_mask,
VisitTag visit_tag) const VisitTag visit_tag) const
{ try {
// TODO: eliminate the const_cast // TODO: eliminate the const_cast
const_cast<ProxyDatabase *>(this)->EnsureConnected(); const_cast<ProxyDatabase *>(this)->EnsureConnected();
...@@ -785,32 +820,47 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ...@@ -785,32 +820,47 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
throw std::runtime_error("Unsupported tag"); throw std::runtime_error("Unsupported tag");
if (!mpd_search_db_tags(connection, tag_type2) || if (!mpd_search_db_tags(connection, tag_type2) ||
!SendConstraints(connection, selection)) !SendConstraints(connection, selection) ||
!SendGroupMask(connection, group_mask))
ThrowError(connection); ThrowError(connection);
// TODO: use group_mask
if (!mpd_search_commit(connection)) if (!mpd_search_commit(connection))
ThrowError(connection); ThrowError(connection);
while (auto *pair = mpd_recv_pair_tag(connection, tag_type2)) { TagBuilder builder;
while (auto *pair = mpd_recv_pair(connection)) {
AtScopeExit(this, pair) { AtScopeExit(this, pair) {
mpd_return_pair(connection, pair); mpd_return_pair(connection, pair);
}; };
TagBuilder tag; const auto current_type = tag_name_parse_i(pair->name);
tag.AddItem(tag_type, pair->value); if (current_type == TAG_NUM_OF_ITEM_TYPES)
continue;
if (current_type == tag_type && !builder.empty()) {
try {
visit_tag(builder.Commit());
} catch (...) {
mpd_response_finish(connection);
throw;
}
}
builder.AddItem(current_type, pair->value);
if (tag.empty()) if (!builder.HasType(current_type))
/* if no tag item has been added, then the /* if no tag item has been added, then the
given value was not acceptable given value was not acceptable
(e.g. empty); forcefully insert an empty (e.g. empty); forcefully insert an empty
tag in this case, as the caller expects the tag in this case, as the caller expects the
given tag type to be present */ given tag type to be present */
tag.AddEmptyItem(tag_type); builder.AddEmptyItem(current_type);
}
if (!builder.empty()) {
try { try {
visit_tag(tag.Commit()); visit_tag(builder.Commit());
} catch (...) { } catch (...) {
mpd_response_finish(connection); mpd_response_finish(connection);
throw; throw;
...@@ -819,6 +869,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, ...@@ -819,6 +869,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
if (!mpd_response_finish(connection)) if (!mpd_response_finish(connection))
ThrowError(connection); ThrowError(connection);
} catch (...) {
if (connection != nullptr)
mpd_search_cancel(connection);
throw;
} }
DatabaseStats DatabaseStats
......
...@@ -304,6 +304,11 @@ struct DecoderControl { ...@@ -304,6 +304,11 @@ struct DecoderControl {
gcc_pure gcc_pure
bool IsCurrentSong(const DetachedSong &_song) const noexcept; bool IsCurrentSong(const DetachedSong &_song) const noexcept;
gcc_pure
bool IsSeekableCurrentSong(const DetachedSong &_song) const noexcept {
return seekable && IsCurrentSong(_song);
}
private: private:
/** /**
* Wait for the command to be finished by the decoder thread. * Wait for the command to be finished by the decoder thread.
......
...@@ -33,6 +33,9 @@ FfmpegInit() ...@@ -33,6 +33,9 @@ FfmpegInit()
{ {
av_log_set_callback(FfmpegLogCallback); av_log_set_callback(FfmpegLogCallback);
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100)
/* deprecated as of FFmpeg 4.0 */
av_register_all(); av_register_all();
#endif
} }
...@@ -577,7 +577,7 @@ Player::SeekDecoder() noexcept ...@@ -577,7 +577,7 @@ Player::SeekDecoder() noexcept
pc.outputs.Cancel(); pc.outputs.Cancel();
} }
if (!dc.IsCurrentSong(*pc.next_song)) { if (!dc.IsSeekableCurrentSong(*pc.next_song)) {
/* the decoder is already decoding the "next" song - /* the decoder is already decoding the "next" song -
stop it and start the previous song again */ stop it and start the previous song again */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment