Merge tag 'v0.23.17'

release v0.23.17
This commit is contained in:
Max Kellermann
2025-01-29 17:18:28 +01:00
7 changed files with 66 additions and 8 deletions

7
NEWS
View File

@@ -70,11 +70,16 @@ ver 0.24 (not yet released)
* documentation: switch to sphinx-rtd-theme
* require Meson 1.0
ver 0.23.17 (not yet released)
ver 0.23.17 (2025/01/29)
* protocol
- "albumart" tries to send larger chunks if available
- explicitly disallow "idle" and "noidle" in command lists
* storage
- nfs: require libnfs 4.0 or later
* database
- inotify: trigger update after symlink was created
* decoder
- ffmpeg: prefer over sndfile and audiofile for its DTS-WAV support
* support libfmt 11.1
ver 0.23.16 (2024/12/03)

View File

@@ -156,6 +156,9 @@ fails, no more commands are executed and the appropriate
``list_OK`` is returned for each
successful command executed in the command list.
Only synchronous commands can be used in command lists. Commands that
suspend execution (``idle`` and ``noidle``) are not allowed.
Ranges
======

View File

@@ -36,6 +36,13 @@ Client::ProcessCommandList(bool list_ok,
return CommandResult::OK;
}
[[gnu::pure]]
static bool
IsAsyncCommmand(const char *line) noexcept
{
return StringIsEqual(line, "idle") || StringIsEqual(line, "noidle");
}
CommandResult
Client::ProcessLine(char *line) noexcept
{
@@ -51,6 +58,13 @@ Client::ProcessLine(char *line) noexcept
return CommandResult::CLOSE;
}
if (cmd_list.IsActive() && IsAsyncCommmand(line)) {
FmtWarning(client_domain,
"[{}] not possible in comand list: \"{}\"",
num, line);
return CommandResult::CLOSE;
}
if (StringIsEqual(line, "noidle")) {
if (idle_waiting) {
/* send empty idle response and leave idle mode */

View File

@@ -197,7 +197,19 @@ read_stream_art(Response &r, const std::string_view art_directory,
if (buffer_size > 0) {
std::unique_lock lock{is->mutex};
is->Seek(lock, offset);
const bool was_ready = is->IsReady();
read_size = is->Read(lock, {buffer.get(), buffer_size});
if (was_ready && read_size < buffer_size / 2)
/* the InputStream was ready before, but we
got only very little data; probably just
some data left in the buffer without doing
any I/O; let's wait for the next low-level
read to complete to get more data for the
client */
read_size += is->Read(lock, {buffer.get() + read_size, buffer_size - read_size});
}
r.Fmt("size: {}\n", art_file_size);

View File

@@ -57,12 +57,6 @@ constinit const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef ENABLE_OPUS
&opus_decoder_plugin,
#endif
#ifdef ENABLE_SNDFILE
&sndfile_decoder_plugin,
#endif
#ifdef ENABLE_AUDIOFILE
&audiofile_decoder_plugin,
#endif
#ifdef ENABLE_DSD
&dsdiff_decoder_plugin,
&dsf_decoder_plugin,
@@ -103,6 +97,19 @@ constinit const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef ENABLE_FFMPEG
&ffmpeg_decoder_plugin,
#endif
/* these WAV-decoding plugins are below ffmpeg_decoder_plugin
to give FFmpeg a chance to decode DTS-WAV files which is
technically DTS Coherent Acoustics (DCA) stream wrapped in
fake 16-bit stereo samples; neither libsndfile nor
libaudiofile detect this, but FFmpeg does */
#ifdef ENABLE_SNDFILE
&sndfile_decoder_plugin,
#endif
#ifdef ENABLE_AUDIOFILE
&audiofile_decoder_plugin,
#endif
&pcm_decoder_plugin,
nullptr
};

View File

@@ -171,9 +171,12 @@ AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
Check();
r = buffer.Read();
if (!r.empty() || IsEOF())
if (!r.empty())
break;
if (IsEOF())
return 0;
caller_cond.wait(lock);
}
@@ -181,6 +184,12 @@ AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
memcpy(dest.data(), r.data(), nbytes);
buffer.Consume(nbytes);
if (buffer.empty())
/* when the buffer becomes empty, reset its head and
tail so the next write can fill the whole buffer
and not just the part after the tail */
buffer.Clear();
offset += (offset_type)nbytes;
if (paused && buffer.GetSize() < resume_at)

View File

@@ -169,6 +169,14 @@ ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
size_t nbytes = std::min(dest.size(), r.size());
memcpy(dest.data(), r.data(), nbytes);
buffer.Consume(nbytes);
if (buffer.empty())
/* when the buffer becomes empty,
reset its head and tail so the next
write can fill the whole buffer and
not just the part after the tail */
buffer.Clear();
wake_cond.notify_one();
offset += nbytes;
return nbytes;