Merge tag 'v0.23.17'
release v0.23.17
This commit is contained in:
7
NEWS
7
NEWS
@@ -70,11 +70,16 @@ ver 0.24 (not yet released)
|
|||||||
* documentation: switch to sphinx-rtd-theme
|
* documentation: switch to sphinx-rtd-theme
|
||||||
* require Meson 1.0
|
* 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
|
* storage
|
||||||
- nfs: require libnfs 4.0 or later
|
- nfs: require libnfs 4.0 or later
|
||||||
* database
|
* database
|
||||||
- inotify: trigger update after symlink was created
|
- inotify: trigger update after symlink was created
|
||||||
|
* decoder
|
||||||
|
- ffmpeg: prefer over sndfile and audiofile for its DTS-WAV support
|
||||||
* support libfmt 11.1
|
* support libfmt 11.1
|
||||||
|
|
||||||
ver 0.23.16 (2024/12/03)
|
ver 0.23.16 (2024/12/03)
|
||||||
|
@@ -156,6 +156,9 @@ fails, no more commands are executed and the appropriate
|
|||||||
``list_OK`` is returned for each
|
``list_OK`` is returned for each
|
||||||
successful command executed in the command list.
|
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
|
Ranges
|
||||||
======
|
======
|
||||||
|
|
||||||
|
@@ -36,6 +36,13 @@ Client::ProcessCommandList(bool list_ok,
|
|||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
|
static bool
|
||||||
|
IsAsyncCommmand(const char *line) noexcept
|
||||||
|
{
|
||||||
|
return StringIsEqual(line, "idle") || StringIsEqual(line, "noidle");
|
||||||
|
}
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
Client::ProcessLine(char *line) noexcept
|
Client::ProcessLine(char *line) noexcept
|
||||||
{
|
{
|
||||||
@@ -51,6 +58,13 @@ Client::ProcessLine(char *line) noexcept
|
|||||||
return CommandResult::CLOSE;
|
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 (StringIsEqual(line, "noidle")) {
|
||||||
if (idle_waiting) {
|
if (idle_waiting) {
|
||||||
/* send empty idle response and leave idle mode */
|
/* send empty idle response and leave idle mode */
|
||||||
|
@@ -197,7 +197,19 @@ read_stream_art(Response &r, const std::string_view art_directory,
|
|||||||
if (buffer_size > 0) {
|
if (buffer_size > 0) {
|
||||||
std::unique_lock lock{is->mutex};
|
std::unique_lock lock{is->mutex};
|
||||||
is->Seek(lock, offset);
|
is->Seek(lock, offset);
|
||||||
|
|
||||||
|
const bool was_ready = is->IsReady();
|
||||||
|
|
||||||
read_size = is->Read(lock, {buffer.get(), buffer_size});
|
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);
|
r.Fmt("size: {}\n", art_file_size);
|
||||||
|
@@ -57,12 +57,6 @@ constinit const struct DecoderPlugin *const decoder_plugins[] = {
|
|||||||
#ifdef ENABLE_OPUS
|
#ifdef ENABLE_OPUS
|
||||||
&opus_decoder_plugin,
|
&opus_decoder_plugin,
|
||||||
#endif
|
#endif
|
||||||
#ifdef ENABLE_SNDFILE
|
|
||||||
&sndfile_decoder_plugin,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_AUDIOFILE
|
|
||||||
&audiofile_decoder_plugin,
|
|
||||||
#endif
|
|
||||||
#ifdef ENABLE_DSD
|
#ifdef ENABLE_DSD
|
||||||
&dsdiff_decoder_plugin,
|
&dsdiff_decoder_plugin,
|
||||||
&dsf_decoder_plugin,
|
&dsf_decoder_plugin,
|
||||||
@@ -103,6 +97,19 @@ constinit const struct DecoderPlugin *const decoder_plugins[] = {
|
|||||||
#ifdef ENABLE_FFMPEG
|
#ifdef ENABLE_FFMPEG
|
||||||
&ffmpeg_decoder_plugin,
|
&ffmpeg_decoder_plugin,
|
||||||
#endif
|
#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,
|
&pcm_decoder_plugin,
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
@@ -171,9 +171,12 @@ AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
|||||||
Check();
|
Check();
|
||||||
|
|
||||||
r = buffer.Read();
|
r = buffer.Read();
|
||||||
if (!r.empty() || IsEOF())
|
if (!r.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (IsEOF())
|
||||||
|
return 0;
|
||||||
|
|
||||||
caller_cond.wait(lock);
|
caller_cond.wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +184,12 @@ AsyncInputStream::Read(std::unique_lock<Mutex> &lock,
|
|||||||
memcpy(dest.data(), r.data(), nbytes);
|
memcpy(dest.data(), r.data(), nbytes);
|
||||||
buffer.Consume(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;
|
offset += (offset_type)nbytes;
|
||||||
|
|
||||||
if (paused && buffer.GetSize() < resume_at)
|
if (paused && buffer.GetSize() < resume_at)
|
||||||
|
@@ -169,6 +169,14 @@ ThreadInputStream::Read(std::unique_lock<Mutex> &lock,
|
|||||||
size_t nbytes = std::min(dest.size(), r.size());
|
size_t nbytes = std::min(dest.size(), r.size());
|
||||||
memcpy(dest.data(), r.data(), nbytes);
|
memcpy(dest.data(), r.data(), nbytes);
|
||||||
buffer.Consume(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();
|
wake_cond.notify_one();
|
||||||
offset += nbytes;
|
offset += nbytes;
|
||||||
return nbytes;
|
return nbytes;
|
||||||
|
Reference in New Issue
Block a user