summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--android/AndroidManifest.xml4
-rw-r--r--python/build/libs.py8
-rw-r--r--src/db/plugins/ProxyDatabasePlugin.cxx79
-rw-r--r--src/decoder/DecoderControl.hxx5
-rw-r--r--src/lib/ffmpeg/Init.cxx3
-rw-r--r--src/player/Thread.cxx2
7 files changed, 90 insertions, 20 deletions
diff --git a/NEWS b/NEWS
index 9dcde8cfc..1297825a0 100644
--- a/NEWS
+++ b/NEWS
@@ -31,11 +31,18 @@ ver 0.21 (not yet released)
- opus: support for sending metadata using ogg stream chaining
* require GCC 5.0
-ver 0.20.19 (not yet released)
+ver 0.20.19 (2018/04/26)
* protocol
- 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
+ - ffmpeg: fix av_register_all() deprecation warning (FFmpeg 4.0)
+* player
+ - fix spurious "Not seekable" error when switching radio streams
* macOS: fix crash bug
ver 0.20.18 (2018/02/24)
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"/>
diff --git a/python/build/libs.py b/python/build/libs.py
index 1c99a37cb..c11be6188 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',
@@ -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',
diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx
index 8a896c9e6..a33e02ca8 100644
--- a/src/db/plugins/ProxyDatabasePlugin.cxx
+++ b/src/db/plugins/ProxyDatabasePlugin.cxx
@@ -34,6 +34,7 @@
#include "tag/Builder.hxx"
#include "tag/Tag.hxx"
#include "tag/Mask.hxx"
+#include "tag/ParseName.hxx"
#include "util/ScopeExit.hxx"
#include "util/RuntimeError.hxx"
#include "protocol/Ack.hxx"
@@ -335,6 +336,35 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection)
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,
const ConfigBlock &block)
:Database(proxy_db_plugin),
@@ -700,7 +730,7 @@ static void
SearchSongs(struct mpd_connection *connection,
const DatabaseSelection &selection,
VisitSong visit_song)
-{
+try {
assert(selection.recursive);
assert(visit_song);
@@ -727,6 +757,11 @@ SearchSongs(struct mpd_connection *connection,
if (!mpd_response_finish(connection))
ThrowError(connection);
+} catch (...) {
+ if (connection != nullptr)
+ mpd_search_cancel(connection);
+
+ throw;
}
/**
@@ -774,9 +809,9 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
void
ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
TagType tag_type,
- gcc_unused TagMask group_mask,
+ TagMask group_mask,
VisitTag visit_tag) const
-{
+try {
// TODO: eliminate the const_cast
const_cast<ProxyDatabase *>(this)->EnsureConnected();
@@ -785,32 +820,47 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
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 (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
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.empty()) {
try {
- visit_tag(tag.Commit());
+ visit_tag(builder.Commit());
} catch (...) {
mpd_response_finish(connection);
throw;
@@ -819,6 +869,11 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
if (!mpd_response_finish(connection))
ThrowError(connection);
+} catch (...) {
+ if (connection != nullptr)
+ mpd_search_cancel(connection);
+
+ throw;
}
DatabaseStats
diff --git a/src/decoder/DecoderControl.hxx b/src/decoder/DecoderControl.hxx
index a30ebe722..1d792520d 100644
--- a/src/decoder/DecoderControl.hxx
+++ b/src/decoder/DecoderControl.hxx
@@ -304,6 +304,11 @@ struct DecoderControl {
gcc_pure
bool IsCurrentSong(const DetachedSong &_song) const noexcept;
+ gcc_pure
+ bool IsSeekableCurrentSong(const DetachedSong &_song) const noexcept {
+ return seekable && IsCurrentSong(_song);
+ }
+
private:
/**
* Wait for the command to be finished by the decoder thread.
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
}
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 2ffa5d933..c599b1725 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -577,7 +577,7 @@ Player::SeekDecoder() noexcept
pc.outputs.Cancel();
}
- if (!dc.IsCurrentSong(*pc.next_song)) {
+ if (!dc.IsSeekableCurrentSong(*pc.next_song)) {
/* the decoder is already decoding the "next" song -
stop it and start the previous song again */