From 44b200240f1f4b8394dd2e58fec72da3d3ec448f Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Wed, 25 Apr 2018 21:19:26 +0200 Subject: [PATCH 1/8] player/Thread: never reuse decoder when switching radio streams When switching to another song manually, the player checks if the decoder is already decoding that song; if so, it will attempt to reuse it by seeking it to the new position. That however fails if the decoder is not seekable (e.g. a radio stream) which leaves the user unable to switch to that song with the bogus error message "Not seekable". --- NEWS | 2 ++ src/decoder/DecoderControl.hxx | 9 +++++++-- src/player/Thread.cxx | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index f422b2239..c27ab3d35 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ ver 0.20.19 (not yet released) - validate absolute seek time, reject negative values * input - mms: fix lockup bug and a crash bug +* player + - fix spurious "Not seekable" error when switching radio streams * macOS: fix crash bug ver 0.20.18 (2018/02/24) diff --git a/src/decoder/DecoderControl.hxx b/src/decoder/DecoderControl.hxx index dfd8232e6..920982e80 100644 --- a/src/decoder/DecoderControl.hxx +++ b/src/decoder/DecoderControl.hxx @@ -308,9 +308,14 @@ struct DecoderControl { bool IsCurrentSong(const DetachedSong &_song) const noexcept; gcc_pure - bool LockIsCurrentSong(const DetachedSong &_song) const noexcept { + bool IsSeekableCurrentSong(const DetachedSong &_song) const noexcept { + return seekable && IsCurrentSong(_song); + } + + gcc_pure + bool LockIsSeeakbleCurrentSong(const DetachedSong &_song) const noexcept { const std::lock_guard<Mutex> protect(mutex); - return IsCurrentSong(_song); + return IsSeekableCurrentSong(_song); } private: diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx index 58883307d..651117088 100644 --- a/src/player/Thread.cxx +++ b/src/player/Thread.cxx @@ -584,7 +584,7 @@ Player::SeekDecoder() const SongTime start_time = pc.next_song->GetStartTime(); - if (!dc.LockIsCurrentSong(*pc.next_song)) { + if (!dc.LockIsSeeakbleCurrentSong(*pc.next_song)) { /* the decoder is already decoding the "next" song - stop it and start the previous song again */ From 1e54297be8322546b0b9c651989ce7fdc5ea2ce2 Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Wed, 25 Apr 2018 21:35:33 +0200 Subject: [PATCH 2/8] lib/ffmpeg/Init: fix av_register_all() deprecation warning av_register_all() was deprecated in FFmpeg/FFmpeg@0694d8702421e7aff1340038559c438b61bb30dd --- NEWS | 2 ++ src/lib/ffmpeg/Init.cxx | 3 +++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index c27ab3d35..11a77af8d 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ ver 0.20.19 (not yet released) - validate absolute seek time, reject negative values * input - 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 diff --git a/src/lib/ffmpeg/Init.cxx b/src/lib/ffmpeg/Init.cxx index 7f11a72d4..9a7872618 100644 --- a/src/lib/ffmpeg/Init.cxx +++ b/src/lib/ffmpeg/Init.cxx @@ -33,6 +33,9 @@ FfmpegInit() { av_log_set_callback(FfmpegLogCallback); +#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 9, 100) + /* deprecated as of FFmpeg 4.0 */ av_register_all(); +#endif } From d40e9de2d2b82063853bebb87afce4e2199afa6e Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:14:26 +0200 Subject: [PATCH 3/8] python/build/libs.py: upgrade libvorbis to 1.3.6 --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index 1c99a37cb..c51465c31 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -17,8 +17,8 @@ libogg = AutotoolsProject( ) libvorbis = AutotoolsProject( - 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz', - '28cb28097c07a735d6af56e598e1c90f', + 'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.6.tar.xz', + 'af00bb5a784e7c9e69f56823de4637c350643deedaf333d0fa86ecdba6fcb415', 'lib/libvorbis.a', [ '--disable-shared', '--enable-static', From 5c4169e64e8b6b86ebc7ca2de260e075fdf27f5f Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:16:16 +0200 Subject: [PATCH 4/8] python/build/libs.py: upgrade FFmpeg to 4.0 --- python/build/libs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/build/libs.py b/python/build/libs.py index c51465c31..c11be6188 100644 --- a/python/build/libs.py +++ b/python/build/libs.py @@ -105,8 +105,8 @@ liblame = AutotoolsProject( ) ffmpeg = FfmpegProject( - 'http://ffmpeg.org/releases/ffmpeg-3.4.2.tar.xz', - '2b92e9578ef8b3e49eeab229e69305f5f4cbc1fdaa22e927fc7fca18acccd740', + 'http://ffmpeg.org/releases/ffmpeg-4.0.tar.xz', + 'ed945daf40b124e77a685893cc025d086f638bc703183460aff49508edb3a43f', 'lib/libavcodec.a', [ '--disable-shared', '--enable-static', From 388768b3a65c8b9264070090480c948663d746e8 Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:38:57 +0200 Subject: [PATCH 5/8] db/proxy: call mpd_search_cancel() after search error Fixes "search already in progress" errors. --- NEWS | 2 ++ src/db/plugins/ProxyDatabasePlugin.cxx | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 11a77af8d..50210f28e 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ ver 0.20.19 (not yet released) * protocol - validate absolute seek time, reject negative values +* database + - proxy: fix "search already in progress" errors * input - mms: fix lockup bug and a crash bug * decoder diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx index 13f174024..9b5da1dd9 100644 --- a/src/db/plugins/ProxyDatabasePlugin.cxx +++ b/src/db/plugins/ProxyDatabasePlugin.cxx @@ -682,7 +682,7 @@ static void SearchSongs(struct mpd_connection *connection, const DatabaseSelection &selection, VisitSong visit_song) -{ +try { assert(selection.recursive); assert(visit_song); @@ -709,6 +709,11 @@ SearchSongs(struct mpd_connection *connection, if (!mpd_response_finish(connection)) ThrowError(connection); +} catch (...) { + if (connection != nullptr) + mpd_search_cancel(connection); + + throw; } /** @@ -758,7 +763,7 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, TagType tag_type, gcc_unused tag_mask_t group_mask, VisitTag visit_tag) const -{ +try { // TODO: eliminate the const_cast const_cast<ProxyDatabase *>(this)->EnsureConnected(); @@ -801,6 +806,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, if (!mpd_response_finish(connection)) ThrowError(connection); +} catch (...) { + if (connection != nullptr) + mpd_search_cancel(connection); + + throw; } DatabaseStats From ac395429c39b846d48144e4311246abd8059a3a8 Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:28:47 +0200 Subject: [PATCH 6/8] db/proxy: implement the group_mask parameter in VisitUniqueTags() Closes #258 --- NEWS | 1 + src/db/plugins/ProxyDatabasePlugin.cxx | 63 ++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 50210f28e..29b121cef 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ ver 0.20.19 (not yet released) - validate absolute seek time, reject negative values * database - proxy: fix "search already in progress" errors + - proxy: implement "list ... group" * input - mms: fix lockup bug and a crash bug * decoder diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx index 9b5da1dd9..c2bc33c6c 100644 --- a/src/db/plugins/ProxyDatabasePlugin.cxx +++ b/src/db/plugins/ProxyDatabasePlugin.cxx @@ -325,6 +325,34 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection) return true; } +static bool +SendGroupMask(mpd_connection *connection, tag_mask_t mask) +{ +#if LIBMPDCLIENT_CHECK_VERSION(2,12,0) + for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) { + if ((mask & (tag_mask_t(1) << i)) == 0) + continue; + + const auto tag = Convert(TagType(i)); + 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 != 0) + throw std::runtime_error("Grouping requires libmpdclient 2.12"); + + return true; +#endif +} + ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener, const ConfigBlock &block) :Database(proxy_db_plugin), @@ -761,7 +789,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection, void ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection, TagType tag_type, - gcc_unused tag_mask_t group_mask, + tag_mask_t group_mask, VisitTag visit_tag) const try { // TODO: eliminate the const_cast @@ -772,32 +800,47 @@ try { throw std::runtime_error("Unsupported tag"); if (!mpd_search_db_tags(connection, tag_type2) || - !SendConstraints(connection, selection)) + !SendConstraints(connection, selection) || + !SendGroupMask(connection, group_mask)) ThrowError(connection); - // TODO: use group_mask - if (!mpd_search_commit(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) { mpd_return_pair(connection, pair); }; - TagBuilder tag; - tag.AddItem(tag_type, pair->value); + const auto current_type = tag_name_parse_i(pair->name); + if (current_type == TAG_NUM_OF_ITEM_TYPES) + continue; - if (tag.IsEmpty()) + if (current_type == tag_type && !builder.IsEmpty()) { + try { + visit_tag(builder.Commit()); + } catch (...) { + mpd_response_finish(connection); + throw; + } + } + + builder.AddItem(current_type, pair->value); + + if (!builder.HasType(current_type)) /* if no tag item has been added, then the given value was not acceptable (e.g. empty); forcefully insert an empty tag in this case, as the caller expects the given tag type to be present */ - tag.AddEmptyItem(tag_type); + builder.AddEmptyItem(current_type); + } + if (!builder.IsEmpty()) { try { - visit_tag(tag.Commit()); + visit_tag(builder.Commit()); } catch (...) { mpd_response_finish(connection); throw; From 504e8d564aff6ecf9608a35c6aa08b55e0eab676 Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:56:39 +0200 Subject: [PATCH 7/8] android/AndroidManifest.xml: increment version number to 0.20.19 --- android/AndroidManifest.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index afa8c8475..16f96a9cf 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.musicpd" android:installLocation="auto" - android:versionCode="17" - android:versionName="0.20.18"> + android:versionCode="18" + android:versionName="0.20.19"> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/> From 7b94f0e36ba9ab4ee50ce1984dbd2007475106f5 Mon Sep 17 00:00:00 2001 From: Max Kellermann <max@musicpd.org> Date: Thu, 26 Apr 2018 19:57:04 +0200 Subject: [PATCH 8/8] release v0.20.19 --- NEWS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 29b121cef..132758bc2 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -ver 0.20.19 (not yet released) +ver 0.20.19 (2018/04/26) * protocol - validate absolute seek time, reject negative values * database