summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-06-10 22:58:14 +0200
committerMax Kellermann <max@musicpd.org>2020-06-10 22:58:41 +0200
commitc6a7f6dabc3509bf0a11dc6eafa89aaa8125b86c (patch)
treef324bb6643c65fc0e7d73a349f969c6e46a3b747
parent96a273bf3ba60fdfb4faadfb716ebd0e57b346a7 (diff)
parent24741c5d065e1f0b575f4ba5472ce8066e5e141d (diff)
Merge tag 'v0.21.24'
release v0.21.24
-rw-r--r--NEWS9
-rwxr-xr-xandroid/build.py1
-rw-r--r--doc/protocol.rst3
-rw-r--r--python/build/libs.py12
-rw-r--r--src/decoder/Bridge.cxx8
-rw-r--r--src/decoder/Bridge.hxx6
-rw-r--r--src/decoder/Control.cxx2
-rw-r--r--src/decoder/Control.hxx9
-rw-r--r--src/decoder/DecoderPlugin.hxx2
-rw-r--r--src/decoder/Thread.cxx1
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx45
-rw-r--r--src/lib/curl/Request.cxx2
-rw-r--r--src/pcm/AudioFormat.hxx4
-rw-r--r--src/player/Thread.cxx17
-rw-r--r--src/util/StringFormat.hxx2
-rwxr-xr-xwin32/build.py1
16 files changed, 88 insertions, 36 deletions
diff --git a/NEWS b/NEWS
index 07af565e0..6c8309ee6 100644
--- a/NEWS
+++ b/NEWS
@@ -40,7 +40,7 @@ ver 0.22 (not yet released)
* switch to C++17
- GCC 7 or clang 4 (or newer) recommended
-ver 0.21.24 (not yet released)
+ver 0.21.24 (2020/06/10)
* protocol
- "tagtypes" requires no permissions
* database
@@ -49,11 +49,14 @@ ver 0.21.24 (not yet released)
- modplug: fix Windows build failure
- wildmidi: attempt to detect WildMidi using pkg-config
- wildmidi: fix Windows build failure
+* player
+ - don't restart current song if seeking beyond end
* Android
- - enable the decoder plugins ModPlug and WildMidi
+ - enable the decoder plugins GME, ModPlug and WildMidi
- fix build failure with Android NDK r21
* Windows
- - enable the decoder plugins ModPlug and WildMidi
+ - fix stream playback
+ - enable the decoder plugins GME, ModPlug and WildMidi
- work around Meson bug breaking the Windows build with GCC 10
* fix unit test failure
diff --git a/android/build.py b/android/build.py
index 8716fc1a9..5bee46304 100755
--- a/android/build.py
+++ b/android/build.py
@@ -170,6 +170,7 @@ thirdparty_libs = [
libid3tag,
libmodplug,
wildmidi,
+ gme,
ffmpeg,
curl,
libexpat,
diff --git a/doc/protocol.rst b/doc/protocol.rst
index 9d0c170b9..30406e598 100644
--- a/doc/protocol.rst
+++ b/doc/protocol.rst
@@ -485,7 +485,8 @@ Querying :program:`MPD`'s status
- ``songs``: number of songs
- ``uptime``: daemon uptime in seconds
- ``db_playtime``: sum of all song times in the database in seconds
- - ``db_update``: last db update in UNIX time
+ - ``db_update``: last db update in UNIX time (seconds since
+ 1970-01-01 UTC)
- ``playtime``: time length of music played
Playback options
diff --git a/python/build/libs.py b/python/build/libs.py
index c7b2250cd..e211a0107 100644
--- a/python/build/libs.py
+++ b/python/build/libs.py
@@ -135,6 +135,18 @@ wildmidi = CmakeProject(
version='0.4.3',
)
+gme = CmakeProject(
+ 'https://bitbucket.org/mpyne/game-music-emu/downloads/game-music-emu-0.6.3.tar.xz',
+ 'aba34e53ef0ec6a34b58b84e28bf8cfbccee6585cebca25333604c35db3e051d',
+ 'lib/libgme.a',
+ [
+ '-DBUILD_SHARED_LIBS=OFF',
+ '-DENABLE_UBSAN=OFF',
+ '-DZLIB_INCLUDE_DIR=OFF',
+ '-DSDL2_DIR=OFF',
+ ],
+)
+
ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-4.2.3.tar.xz',
'9df6c90aed1337634c1fb026fb01c154c29c82a64ea71291ff2da9aacb9aad31',
diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx
index 58e0641f2..a10ad634f 100644
--- a/src/decoder/Bridge.cxx
+++ b/src/decoder/Bridge.cxx
@@ -38,15 +38,19 @@
#include <cassert>
#include <cmath>
+#include <stdexcept>
#include <string.h>
DecoderBridge::DecoderBridge(DecoderControl &_dc, bool _initial_seek_pending,
+ bool _initial_seek_essential,
std::unique_ptr<Tag> _tag) noexcept
:dc(_dc),
initial_seek_pending(_initial_seek_pending),
+ initial_seek_essential(_initial_seek_essential),
song_tag(std::move(_tag)) {}
+
DecoderBridge::~DecoderBridge() noexcept
{
/* caller must flush the chunk */
@@ -364,6 +368,10 @@ DecoderBridge::SeekError() noexcept
/* d'oh, we can't seek to the sub-song start position,
what now? - no idea, ignoring the problem for now. */
initial_seek_running = false;
+
+ if (initial_seek_essential)
+ error = std::make_exception_ptr(std::runtime_error("Decoder failed to seek"));
+
return;
}
diff --git a/src/decoder/Bridge.hxx b/src/decoder/Bridge.hxx
index cd3600f97..012801def 100644
--- a/src/decoder/Bridge.hxx
+++ b/src/decoder/Bridge.hxx
@@ -65,6 +65,11 @@ private:
bool initial_seek_pending;
/**
+ * Are initial seek failures fatal?
+ */
+ const bool initial_seek_essential;
+
+ /**
* Is the initial seek currently running? During this time,
* the decoder command is SEEK. This flag is set by
* decoder_get_virtual_command(), when the virtual SEEK
@@ -112,6 +117,7 @@ private:
public:
DecoderBridge(DecoderControl &_dc, bool _initial_seek_pending,
+ bool _initial_seek_essential,
std::unique_ptr<Tag> _tag) noexcept;
~DecoderBridge() noexcept;
diff --git a/src/decoder/Control.cxx b/src/decoder/Control.cxx
index e6a0df714..50ba4f0d3 100644
--- a/src/decoder/Control.cxx
+++ b/src/decoder/Control.cxx
@@ -80,6 +80,7 @@ void
DecoderControl::Start(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> _song,
SongTime _start_time, SongTime _end_time,
+ bool _initial_seek_essential,
MusicBuffer &_buffer,
std::shared_ptr<MusicPipe> _pipe) noexcept
{
@@ -89,6 +90,7 @@ DecoderControl::Start(std::unique_lock<Mutex> &lock,
song = std::move(_song);
start_time = _start_time;
end_time = _end_time;
+ initial_seek_essential = _initial_seek_essential;
buffer = &_buffer;
pipe = std::move(_pipe);
diff --git a/src/decoder/Control.hxx b/src/decoder/Control.hxx
index 432ee4a4a..7bdf1809f 100644
--- a/src/decoder/Control.hxx
+++ b/src/decoder/Control.hxx
@@ -112,6 +112,12 @@ private:
public:
bool seek_error;
bool seekable;
+
+ /**
+ * @see #DecoderBridge::initial_seek_essential
+ */
+ bool initial_seek_essential;
+
SongTime seek_time;
private:
@@ -383,12 +389,15 @@ public:
* owned and freed by the decoder
* @param start_time see #DecoderControl
* @param end_time see #DecoderControl
+ * @param initial_seek_essential see
+ * #DecoderBridge::initial_seek_essential
* @param pipe the pipe which receives the decoded chunks (owned by
* the caller)
*/
void Start(std::unique_lock<Mutex> &lock,
std::unique_ptr<DetachedSong> song,
SongTime start_time, SongTime end_time,
+ bool initial_seek_essential,
MusicBuffer &buffer,
std::shared_ptr<MusicPipe> pipe) noexcept;
diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx
index 610a4e97f..61f959c79 100644
--- a/src/decoder/DecoderPlugin.hxx
+++ b/src/decoder/DecoderPlugin.hxx
@@ -22,7 +22,7 @@
#include "util/Compiler.h"
-#include <forward_list>
+#include <forward_list> // IWYU pragma: export
struct ConfigBlock;
class InputStream;
diff --git a/src/decoder/Thread.cxx b/src/decoder/Thread.cxx
index 4fd208edb..9167cd421 100644
--- a/src/decoder/Thread.cxx
+++ b/src/decoder/Thread.cxx
@@ -422,6 +422,7 @@ decoder_run_song(DecoderControl &dc,
dc.start_time = dc.seek_time;
DecoderBridge bridge(dc, dc.start_time.IsPositive(),
+ dc.initial_seek_essential,
/* pass the song tag only if it's
authoritative, i.e. if it's a local
file - tags on "stream" songs are just
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index 1d253937d..fed55a7a9 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -27,11 +27,11 @@
#include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
+#include "fs/NarrowPath.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
#include "util/StringView.hxx"
-#include "util/UriExtract.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
@@ -40,7 +40,6 @@
#include <cassert>
#include <stdlib.h>
-#include <string.h>
#define SUBTUNE_PREFIX "tune_"
@@ -83,11 +82,10 @@ gcc_pure
static unsigned
ParseSubtuneName(const char *base) noexcept
{
- if (memcmp(base, SUBTUNE_PREFIX, sizeof(SUBTUNE_PREFIX) - 1) != 0)
+ base = StringAfterPrefix(base, SUBTUNE_PREFIX);
+ if (base == nullptr)
return 0;
- base += sizeof(SUBTUNE_PREFIX) - 1;
-
char *endptr;
auto track = strtoul(base, &endptr, 10);
if (endptr == base || *endptr != '.')
@@ -106,41 +104,46 @@ ParseContainerPath(Path path_fs)
const Path base = path_fs.GetBase();
unsigned track;
if (base.IsNull() ||
- (track = ParseSubtuneName(base.c_str())) < 1)
+ (track = ParseSubtuneName(NarrowPath(base))) < 1)
return { AllocatedPath(path_fs), 0 };
return { path_fs.GetDirectoryName(), track - 1 };
}
+static AllocatedPath
+ReplaceSuffix(Path src,
+ const PathTraitsFS::const_pointer new_suffix) noexcept
+{
+ const auto *old_suffix = src.GetSuffix();
+ if (old_suffix == nullptr)
+ return nullptr;
+
+ PathTraitsFS::string s(src.c_str(), old_suffix);
+ s += new_suffix;
+ return AllocatedPath::FromFS(std::move(s));
+}
+
static Music_Emu*
LoadGmeAndM3u(const GmeContainerPath& container) {
- const char *path = container.path.c_str();
- const char *suffix = uri_get_suffix(path);
-
Music_Emu *emu;
const char *gme_err =
- gme_open_file(path, &emu, GME_SAMPLE_RATE);
+ gme_open_file(NarrowPath(container.path), &emu, GME_SAMPLE_RATE);
if (gme_err != nullptr) {
LogWarning(gme_domain, gme_err);
return nullptr;
}
- if(suffix == nullptr) {
- return emu;
- }
-
- std::string m3u_path(path,suffix);
- m3u_path += "m3u";
-
+ const auto m3u_path = ReplaceSuffix(container.path,
+ PATH_LITERAL("m3u"));
/*
* Some GME formats lose metadata if you attempt to
* load a non-existant M3U file, so check that one
* exists before loading.
*/
- if(FileExists(Path::FromFS(m3u_path.c_str()))) {
- gme_load_m3u(emu,m3u_path.c_str());
- }
+ if (!m3u_path.IsNull() && FileExists(m3u_path))
+ gme_load_m3u(emu, NarrowPath(m3u_path));
+
return emu;
}
@@ -320,7 +323,7 @@ gme_container_scan(Path path_fs)
if (num_songs < 2)
return list;
- const char *subtune_suffix = uri_get_suffix(path_fs.c_str());
+ const auto *subtune_suffix = path_fs.GetSuffix();
TagBuilder tag_builder;
diff --git a/src/lib/curl/Request.cxx b/src/lib/curl/Request.cxx
index 7189864c7..2253c5a4f 100644
--- a/src/lib/curl/Request.cxx
+++ b/src/lib/curl/Request.cxx
@@ -57,7 +57,7 @@ CurlRequest::CurlRequest(CurlGlobal &_global,
easy.SetUserAgent("Music Player Daemon " VERSION);
easy.SetHeaderFunction(_HeaderFunction, this);
easy.SetWriteFunction(WriteFunction, this);
-#ifndef ANDROID
+#if !defined(ANDROID) && !defined(_WIN32)
easy.SetOption(CURLOPT_NETRC, 1L);
#endif
easy.SetErrorBuffer(error_buffer);
diff --git a/src/pcm/AudioFormat.hxx b/src/pcm/AudioFormat.hxx
index 7d931a002..237853df1 100644
--- a/src/pcm/AudioFormat.hxx
+++ b/src/pcm/AudioFormat.hxx
@@ -20,8 +20,8 @@
#ifndef MPD_AUDIO_FORMAT_HXX
#define MPD_AUDIO_FORMAT_HXX
-#include "pcm/SampleFormat.hxx"
-#include "pcm/ChannelDefs.hxx"
+#include "pcm/SampleFormat.hxx" // IWYU pragma: export
+#include "pcm/ChannelDefs.hxx" // IWYU pragma: export
#include "util/Compiler.h"
#include <cstddef>
diff --git a/src/player/Thread.cxx b/src/player/Thread.cxx
index 704eee05e..e53c5832a 100644
--- a/src/player/Thread.cxx
+++ b/src/player/Thread.cxx
@@ -224,7 +224,8 @@ private:
* Caller must lock the mutex.
*/
void StartDecoder(std::unique_lock<Mutex> &lock,
- std::shared_ptr<MusicPipe> pipe) noexcept;
+ std::shared_ptr<MusicPipe> pipe,
+ bool initial_seek_essential) noexcept;
/**
* The decoder has acknowledged the "START" command (see
@@ -367,7 +368,8 @@ public:
void
Player::StartDecoder(std::unique_lock<Mutex> &lock,
- std::shared_ptr<MusicPipe> _pipe) noexcept
+ std::shared_ptr<MusicPipe> _pipe,
+ bool initial_seek_essential) noexcept
{
assert(queued || pc.command == PlayerCommand::SEEK);
assert(pc.next_song != nullptr);
@@ -379,6 +381,7 @@ Player::StartDecoder(std::unique_lock<Mutex> &lock,
dc.Start(lock, std::make_unique<DetachedSong>(*pc.next_song),
start_time, pc.next_song->GetEndTime(),
+ initial_seek_essential,
buffer, std::move(_pipe));
}
@@ -636,7 +639,7 @@ Player::SeekDecoder(std::unique_lock<Mutex> &lock) noexcept
pipe->Clear();
/* re-start the decoder */
- StartDecoder(lock, pipe);
+ StartDecoder(lock, pipe, true);
ActivateDecoder();
pc.seeking = true;
@@ -714,7 +717,8 @@ Player::ProcessCommand(std::unique_lock<Mutex> &lock) noexcept
pc.CommandFinished();
if (dc.IsIdle())
- StartDecoder(lock, std::make_shared<MusicPipe>());
+ StartDecoder(lock, std::make_shared<MusicPipe>(),
+ false);
break;
@@ -985,7 +989,7 @@ Player::Run() noexcept
std::unique_lock<Mutex> lock(pc.mutex);
- StartDecoder(lock, pipe);
+ StartDecoder(lock, pipe, true);
ActivateDecoder();
pc.state = PlayerState::PLAY;
@@ -1025,7 +1029,8 @@ Player::Run() noexcept
assert(dc.pipe == nullptr || dc.pipe == pipe);
- StartDecoder(lock, std::make_shared<MusicPipe>());
+ StartDecoder(lock, std::make_shared<MusicPipe>(),
+ false);
}
if (/* no cross-fading if MPD is going to pause at the
diff --git a/src/util/StringFormat.hxx b/src/util/StringFormat.hxx
index 723591c69..c761e8806 100644
--- a/src/util/StringFormat.hxx
+++ b/src/util/StringFormat.hxx
@@ -30,7 +30,7 @@
#ifndef STRING_FORMAT_HXX
#define STRING_FORMAT_HXX
-#include "StringBuffer.hxx"
+#include "StringBuffer.hxx" // IWYU pragma: export
#include <stdio.h>
diff --git a/win32/build.py b/win32/build.py
index 9e1b6e9e4..fb636ded5 100755
--- a/win32/build.py
+++ b/win32/build.py
@@ -98,6 +98,7 @@ thirdparty_libs = [
liblame,
libmodplug,
wildmidi,
+ gme,
ffmpeg,
curl,
libexpat,