Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
10168b8
increment version number to 0.24.10
MaxKellermann Mar 16, 2026
a63a400
lib/zlib/patches: remove zlib_static_suffix for the Windows build
MaxKellermann Mar 16, 2026
b54634f
upnp: allow 1.14.30
PPN-SD Mar 17, 2026
fda4057
Merge branch 'allow_1.14.30' of github.com:PPN-SD/MPD into v0.24.x
MaxKellermann Mar 18, 2026
8e0eb9e
python/build/libs.py: update FFmpeg to 8.1
MaxKellermann Mar 18, 2026
14f502a
input/curl: fix comment typo
MaxKellermann Mar 19, 2026
6a4ecd0
input/curl: allocate user:password buffer dynamically
MaxKellermann Mar 19, 2026
cca273d
input/curl: check for pending seek in OnEnd()
MaxKellermann Mar 19, 2026
38c59e1
input/curl: remove unnecessary nullptr check for curl_version_info()
MaxKellermann Mar 19, 2026
b313451
input/curl: coding style, missing spaces after comma
MaxKellermann Mar 19, 2026
bab9428
player/Thread: update comment, remove GLib types
MaxKellermann Mar 19, 2026
6b131e2
player/Thread: fix comment typo
MaxKellermann Mar 19, 2026
ea035af
player/Thread: merge redundant std::current_exception() calls
MaxKellermann Mar 19, 2026
9acdc3c
player/Thread: remove no-op assignment
MaxKellermann Mar 19, 2026
c836377
player/Thread: fix comment indent
MaxKellermann Mar 19, 2026
676d40c
player/Thread: add `inline`
MaxKellermann Mar 19, 2026
65cd9e1
decoder/Control: remove unused method LockCheckRethrowError()
MaxKellermann Mar 19, 2026
beb0f14
decoder/Control: refactor CheckRethrowError() to return the error
MaxKellermann Mar 19, 2026
497b74e
player/Thread: call GetElapsedTime() only once
MaxKellermann Mar 19, 2026
ffa2fa1
player/Thread: rewrite C-style cast to static_cast<>
MaxKellermann Mar 19, 2026
cb72bc5
Merge branch 'v0.24.x'
MaxKellermann Mar 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ ver 0.25 (not yet released)
* switch to C++23
* require Meson 1.2

ver 0.24.10 (not yet released)
* database
- upnp: allow building with libupnp 1.14.30 which has fixed the API breakage
* Windows
- work around build failure due to zlib bug

ver 0.24.9 (2026/03/11)
* input
- curl: fix build failure after CURL 8.19 API change
Expand Down
7 changes: 3 additions & 4 deletions python/build/libs.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'-DZLIB_BUILD_TESTING=OFF',
'-DZLIB_BUILD_SHARED=OFF',
],
patches='src/lib/zlib/patches',
)

libmodplug = AutotoolsProject(
Expand Down Expand Up @@ -82,8 +83,8 @@
)

ffmpeg = FfmpegProject(
'http://ffmpeg.org/releases/ffmpeg-8.0.1.tar.xz',
'05ee0b03119b45c0bdb4df654b96802e909e0a752f72e4fe3794f487229e5a41',
'http://ffmpeg.org/releases/ffmpeg-8.1.tar.xz',
'b072aed6871998cce9b36e7774033105ca29e33632be5b6347f3206898e0756a',
'lib/libavcodec.a',
[
'--disable-shared', '--enable-static',
Expand Down Expand Up @@ -514,7 +515,6 @@
'--disable-decoder=vp9_qsv',
'--disable-decoder=vp9_rkmpp',
'--disable-decoder=vp9_v4l2m2m',
'--disable-decoder=vp9_vucid',
'--disable-decoder=vplayer',
'--disable-decoder=vqa',
'--disable-decoder=webvtt',
Expand Down Expand Up @@ -554,7 +554,6 @@
'--disable-bsf=mjpeg2jpeg',
'--disable-bsf=opus_metadata',
'--disable-bsf=pgs_frame_merge',
'--disable-bsf=prores',
'--disable-bsf=text2movsub',
'--disable-bsf=vp9_metadata',
'--disable-bsf=vp9_raw_reorder',
Expand Down
18 changes: 5 additions & 13 deletions src/decoder/Control.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -261,25 +261,17 @@ public:
bool _seekable, SignedSongTime _duration) noexcept;

/**
* Checks whether an error has occurred, and if so, rethrows
* Checks whether an error has occurred, and if so, returns
* it.
*
* Caller must lock the object.
*/
void CheckRethrowError() const {
std::exception_ptr GetError() const noexcept {
assert(command == DecoderCommand::NONE);
assert(state != DecoderState::ERROR || error);
assert(state == DecoderState::ERROR);
assert(error);

if (state == DecoderState::ERROR)
std::rethrow_exception(error);
}

/**
* Like CheckRethrowError(), but locks and unlocks the object.
*/
void LockCheckRethrowError() const {
const std::scoped_lock protect{mutex};
CheckRethrowError();
return error;
}

/**
Expand Down
26 changes: 13 additions & 13 deletions src/input/plugins/CurlInputPlugin.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static const size_t CURL_RESUME_AT = 384 * 1024;

class CurlInputStream final : public AsyncInputStream, CurlResponseHandler {
/* some buffers which were passed to libcurl, which we have
too free */
to free */
CurlSlist request_headers;

CurlRequest *request = nullptr;
Expand Down Expand Up @@ -348,7 +348,11 @@ void
CurlInputStream::OnEnd()
{
const std::scoped_lock protect{mutex};
InvokeOnAvailable();

if (IsSeekPending())
SeekDone();
else
InvokeOnAvailable();

AsyncInputStream::SetClosed();
}
Expand Down Expand Up @@ -384,12 +388,9 @@ input_curl_init(EventLoop &event_loop, const ConfigBlock &block)
}

const auto version_info = curl_version_info(CURLVERSION_FIRST);
if (version_info != nullptr) {
FmtDebug(curl_domain, "version {}", version_info->version);
if (version_info->features & CURL_VERSION_SSL)
FmtDebug(curl_domain, "with {}",
version_info->ssl_version);
}
FmtDebug(curl_domain, "version {}", version_info->version);
if (version_info->features & CURL_VERSION_SSL)
FmtDebug(curl_domain, "with {}", version_info->ssl_version);

http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");

Expand Down Expand Up @@ -420,11 +421,11 @@ input_curl_init(EventLoop &event_loop, const ConfigBlock &block)

low_speed_time = block.GetBlockValue("low_speed_time", default_low_speed_time);

tcp_keepalive = block.GetBlockValue("tcp_keepalive",default_tcp_keepalive);
tcp_keepalive = block.GetBlockValue("tcp_keepalive", default_tcp_keepalive);

tcp_keepidle = block.GetBlockValue("tcp_keepidle",default_tcp_keepidle);
tcp_keepidle = block.GetBlockValue("tcp_keepidle", default_tcp_keepidle);

tcp_keepintvl = block.GetBlockValue("tcp_keepintvl",default_tcp_keepintvl);
tcp_keepintvl = block.GetBlockValue("tcp_keepintvl", default_tcp_keepintvl);
}

static void
Expand Down Expand Up @@ -509,8 +510,7 @@ CreateEasy(const char *url, struct curl_slist *headers)

if (proxy_user != nullptr && proxy_password != nullptr)
easy.SetOption(CURLOPT_PROXYUSERPWD,
FmtBuffer<1024>("{}:{}", proxy_user,
proxy_password).c_str());
fmt::format("{}:{}"sv, proxy_user, proxy_password).c_str());

if (cacert != nullptr)
easy.SetOption(CURLOPT_CAINFO, cacert);
Expand Down
10 changes: 8 additions & 2 deletions src/lib/upnp/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ endif
if upnp_option == 'auto'
upnp_dep = dependency('libupnp', version: '>= 1.8', required: false)

if upnp_dep.found() and upnp_dep.version().version_compare('>= 1.14.26')
if upnp_dep.found() and (
( upnp_dep.version().version_compare('>= 1.14.26') and upnp_dep.version().version_compare('< 1.14.30') )
or upnp_dep.version().version_compare('>= 1.18.0')
)
warning('Your libupnp version is known to be broken, see https://github.com/pupnp/pupnp/issues/528 - disabling')
upnp_dep = dependency('', required: false)
endif
Expand All @@ -25,7 +28,10 @@ if upnp_option == 'auto'
elif upnp_option == 'pupnp'
upnp_dep = dependency('libupnp', version: '>= 1.8', required: true)

if upnp_dep.found() and upnp_dep.version().version_compare('>= 1.14.26')
if upnp_dep.found() and (
( upnp_dep.version().version_compare('>= 1.14.26') and upnp_dep.version().version_compare('< 1.14.30') )
or upnp_dep.version().version_compare('>= 1.18.0')
)
error('Your libupnp version is known to be broken, see https://github.com/pupnp/pupnp/issues/528')
endif

Expand Down
12 changes: 12 additions & 0 deletions src/lib/zlib/patches/no_static_suffix
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Index: zlib-1.3.2/CMakeLists.txt
===================================================================
--- zlib-1.3.2.orig/CMakeLists.txt
+++ zlib-1.3.2/CMakeLists.txt
@@ -150,7 +150,6 @@ set(ZLIB_SRCS
zutil.c)

if(WIN32)
- set(zlib_static_suffix "s")
set(CMAKE_DEBUG_POSTFIX "d")
endif(WIN32)

1 change: 1 addition & 0 deletions src/lib/zlib/patches/series
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
no_static_suffix
37 changes: 19 additions & 18 deletions src/player/Thread.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* thread and sends it commands.
*
* The player thread itself does not do any I/O. It synchronizes with
* other threads via #GMutex and #GCond objects, and passes
* other threads via #Mutex and #Cond objects, and passes
* #MusicChunk instances around in #MusicPipe objects.
*/

Expand Down Expand Up @@ -404,13 +404,11 @@ Player::StopDecoder(std::unique_lock<Mutex> &lock) noexcept
decoder_starting = false;
}

bool
inline bool
Player::ForwardDecoderError() noexcept
{
try {
dc.CheckRethrowError();
} catch (...) {
pc.SetError(PlayerError::DECODER, std::current_exception());
if (dc.HasFailed()) {
pc.SetError(PlayerError::DECODER, dc.GetError());
return false;
}

Expand Down Expand Up @@ -550,15 +548,16 @@ Player::OpenOutput() noexcept
const ScopeUnlock unlock(pc.mutex);
pc.outputs.Open(play_audio_format);
} catch (...) {
LogError(std::current_exception());
auto error = std::current_exception();
LogError(error);

output_open = false;

/* pause: the user may resume playback as soon as an
audio output becomes available */
paused = true;

pc.SetOutputError(std::current_exception());
pc.SetOutputError(std::move(error));

return false;
}
Expand All @@ -585,7 +584,7 @@ Player::CheckDecoderStartup(std::unique_lock<Mutex> &lock) noexcept

if (output_open &&
!pc.WaitOutputConsumed(lock, 1))
/* the output devices havn't finished playing
/* the output devices haven't finished playing
all chunks yet - wait for that */
return true;

Expand Down Expand Up @@ -837,9 +836,11 @@ Player::ProcessCommand(std::unique_lock<Mutex> &lock) noexcept
pc.outputs.CheckPipe();
}

pc.elapsed_time = !pc.outputs.GetElapsedTime().IsNegative()
? SongTime(pc.outputs.GetElapsedTime())
: elapsed_time;
if (const auto outputs_time = pc.outputs.GetElapsedTime();
!outputs_time.IsNegative())
pc.elapsed_time = static_cast<SongTime>(outputs_time);
else
pc.elapsed_time = elapsed_time;

pc.CommandFinished();
break;
Expand All @@ -858,16 +859,15 @@ Player::CheckCrossFade() noexcept
if (pc.border_pause) {
/* no cross-fading if MPD is going to pause at the end
of the current song */
xfade_state = CrossFadeState::UNKNOWN;
return;
}

if (!IsDecoderAtNextSong() || dc.IsStarting() || dc.pipe->IsEmpty())
/* we need information about the next song before we
can decide */
/* the "pipe.empty" check is here so we wait for all
(ReplayGain/MixRamp) metadata to appear, which some
decoders parse only after reporting readiness */
(ReplayGain/MixRamp) metadata to appear, which some
decoders parse only after reporting readiness */
return;

if (!pc.cross_fade.CanCrossFade(pc.total_time, dc.total_time,
Expand Down Expand Up @@ -986,7 +986,7 @@ Player::PlayNextChunk() noexcept
std::move(other_chunk->tag));

if (pc.cross_fade.mixramp_delay <= FloatDuration::zero()) {
chunk->mix_ratio = ((float)cross_fade_position)
chunk->mix_ratio = static_cast<float>(cross_fade_position)
/ cross_fade_chunks;
} else {
chunk->mix_ratio = -1;
Expand Down Expand Up @@ -1042,15 +1042,16 @@ Player::PlayNextChunk() noexcept
pc.PlayChunk(*song, std::move(chunk),
play_audio_format);
} catch (...) {
LogError(std::current_exception());
auto error = std::current_exception();
LogError(error);

chunk.reset();

/* pause: the user may resume playback as soon as an
audio output becomes available */
paused = true;

pc.LockSetOutputError(std::current_exception());
pc.LockSetOutputError(std::move(error));

return false;
}
Expand Down
Loading