release v0.20.19
-----BEGIN PGP SIGNATURE----- iQJEBAABCgAuFiEEA5IzWngIOJSkMBxDI26KWMbbRRIFAlriEvAQHG1heEBtdXNp Y3BkLm9yZwAKCRAjbopYxttFEnEpD/4+yH4ydc9l1/j5AD08jFyUUe6YSnC8gLsG DRrSOU1BQltYAPhlRGxA/HlKxboaT7v5qcXBdIV+HwKs6149j8qxip8g8PYoUBmB mn6YckjEPCLpLe4WSvfGdm5a1aI7nMC76wHBvTPCAMTZk9FAmUED4DqgNYmWycOd MpXZbzZdvb2Ti4dQARrK8AbMjTD44LXDOhBgWYnZLpo1ovYhnGvTPAElCQN23tbT VMcJPYe86lzgs1vWwgURzkn7Y3CaSMF3G+aKw/oLEK3giZmE0y7Kov9Ycy4IC6+3 aXuEP9drMIltAyZ2hmeH6JFigbgQbDhwuAu1biYLLukwa0oEOEFTP1+yxAVbi/vx 58rD6uWJeFbqPna6146TAYVi8QeymJWfhFWxkcol2u7etrIxXpX//qo8Mv+AiLor wOrTerKgRFYmtSH14wIoSfKsn2wmsXOhDE38h621PAzqvQXDzrBLMo4HMJ4y+G+q Y6LZWatweL6I2qMsOKWvECOJNxQJrkDFOLq8Mj+O4v6iiLQWhiul1hi2g8EOcRMI SkdWTakla3LbmuUN1dKQJwoojNevnP5yPXI15rM6JMZkXJcWxi4mvnzoAFnBTmov 57GxpShueo2yy9yrFgS7hBuRsBXzYxze/xY0LSYSO4SjCjNCnWXse6O9pI7JqFbI m5JJW96Nqg== =1wwq -----END PGP SIGNATURE----- Merge tag 'v0.20.19' release v0.20.19
This commit is contained in:
commit
43a43c1e2b
9
NEWS
9
NEWS
|
@ -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 @@
|
||||||
<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(
|
||||||
)
|
)
|
||||||
|
|
||||||
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(
|
||||||
)
|
)
|
||||||
|
|
||||||
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 @@
|
||||||
#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)
|
||||||
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
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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 (tag.empty())
|
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 (!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,
|
||||||
|
|
||||||
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 {
|
||||||
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()
|
||||||
{
|
{
|
||||||
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
|
||||||
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 */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue