release v0.23.8
-----BEGIN PGP SIGNATURE----- iQJBBAABCgArFiEEA5IzWngIOJSkMBxDI26KWMbbRRIFAmLIuEINHG1heEBibGFy Zy5kZQAKCRAjbopYxttFEm1JD/9j/a82cNccPLUfTptgb8ak5fAnYA65edbtGPr9 dLv1BSjMrsTpMpgJ8FT5wjQn7H5drmE2GLvCN+oZUqaSz99F5BC+Hof7bfvv/sVF opLTiZn2iAtanwtHP6ZEPPswTbdN2FgtZeFhJIGmFspghJV5hdbM7vbwNX1SIpc6 LH+WvE42ZG/w5wNajRvr6/lPYQhJc70wUqODXLzgdYu3WYmIclUAyFv7tVr067Hh uXP6b6MZV60cqh+a0xX01n5kwDo2reqmmE0IY0Le7H6xg5quE7DzCVElTOAa7R1x MZJCqY/thjvXl3JfHW5/ZwmiNrxsmx8nzGhrDyg4tb3hjbwip1iEI/OgnDyacdl4 34njeFxO40AJhienDWLAp2oSYh4pNdfjFvnfSJXeQ9HD2sIzGi692WUgzjdM1VmA 83iVRe9Bx4OTyAg1jwPOFyAYnRqhWsYFSp7GjwNBQwTRSwwBtmOxwAhWKwuspuLi YfDoF7wGYVY5lOXuDBw+rvhGRWqGKsbQzZFy0bQFoD8dbwG9huLJCumNWZCbqELF TAfU5sRcQlAjwSGncEpKOitYjdrtylYRb12p2DSedFuBWxcRGGPiCFfTVUKV8hz1 LGD1xj1g/4ClEUbfDNVwa7sAEO7o84Qojfkt/siBjhE427i11CpPGIlMCVeO2FkG fI1f3Q== =KgWM -----END PGP SIGNATURE----- Merge tag 'v0.23.8' release v0.23.8
This commit is contained in:
commit
4464310e74
20
NEWS
20
NEWS
|
@ -14,11 +14,25 @@ ver 0.24 (not yet released)
|
||||||
* switch to C++20
|
* switch to C++20
|
||||||
- GCC 10 or clang 11 (or newer) recommended
|
- GCC 10 or clang 11 (or newer) recommended
|
||||||
|
|
||||||
ver 0.23.8 (not yet released)
|
ver 0.23.8 (2022/07/09)
|
||||||
* storage
|
* storage
|
||||||
- curl: fix crash if web server does not understand WebDAV
|
- curl: fix crash if web server does not understand WebDAV
|
||||||
* output
|
* input
|
||||||
- pipewire: fix crash with PipeWire 0.3.53
|
- cdio_paranoia: fix crash if no drive was found
|
||||||
|
- cdio_paranoia: faster cancellation
|
||||||
|
- cdio_paranoia: don't scan for replay gain tags
|
||||||
|
- pipewire: fix playback of very short tracks
|
||||||
|
- pipewire: drop all buffers before manual song change
|
||||||
|
- pipewire: fix stuttering after manual song change
|
||||||
|
- snapcast: fix busy loop while paused
|
||||||
|
- snapcast: fix stuttering after resuming playback
|
||||||
|
* mixer
|
||||||
|
- better error messages
|
||||||
|
- alsa: fix setting volume before playback starts
|
||||||
|
- pipewire: fix crash bug
|
||||||
|
- pipewire: fix volume change events with PipeWire 0.3.53
|
||||||
|
- pipewire: don't force initial volume=100%
|
||||||
|
* support libfmt 9
|
||||||
|
|
||||||
ver 0.23.7 (2022/05/09)
|
ver 0.23.7 (2022/05/09)
|
||||||
* database
|
* database
|
||||||
|
|
14
doc/user.rst
14
doc/user.rst
|
@ -1095,7 +1095,19 @@ The "music directory" is where you store your music files. :program:`MPD` stores
|
||||||
|
|
||||||
Depending on the size of your music collection and the speed of the storage, this can take a while.
|
Depending on the size of your music collection and the speed of the storage, this can take a while.
|
||||||
|
|
||||||
To exclude a file from the update, create a file called :file:`.mpdignore` in its parent directory. Each line of that file may contain a list of shell wildcards. Matching files in the current directory and all subdirectories are excluded.
|
To exclude a file from the update, create a file called
|
||||||
|
:file:`.mpdignore` in its parent directory. Each line of that file
|
||||||
|
may contain a list of shell wildcards. Matching files (or
|
||||||
|
directories) in the current directory and all subdirectories are
|
||||||
|
excluded. Example::
|
||||||
|
|
||||||
|
*.opus
|
||||||
|
99*
|
||||||
|
|
||||||
|
Subject to pattern matching is the file/directory name. It is (not
|
||||||
|
yet) possible to match nested path names, e.g. something like
|
||||||
|
``foo/*.flac`` is not possible.
|
||||||
|
|
||||||
|
|
||||||
Mounting other storages into the music directory
|
Mounting other storages into the music directory
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -382,14 +382,14 @@ ffmpeg = FfmpegProject(
|
||||||
)
|
)
|
||||||
|
|
||||||
openssl = OpenSSLProject(
|
openssl = OpenSSLProject(
|
||||||
'https://www.openssl.org/source/openssl-3.0.3.tar.gz',
|
'https://www.openssl.org/source/openssl-3.0.5.tar.gz',
|
||||||
'ee0078adcef1de5f003c62c80cc96527721609c6f3bb42b7795df31f8b558c0b',
|
'aa7d8d9bef71ad6525c55ba11e5f4397889ce49c2c9349dcea6d3e4f0b024a7a',
|
||||||
'include/openssl/ossl_typ.h',
|
'include/openssl/ossl_typ.h',
|
||||||
)
|
)
|
||||||
|
|
||||||
curl = CmakeProject(
|
curl = CmakeProject(
|
||||||
'https://curl.se/download/curl-7.83.1.tar.xz',
|
'https://curl.se/download/curl-7.84.0.tar.xz',
|
||||||
'2cb9c2356e7263a1272fd1435ef7cdebf2cd21400ec287b068396deb705c22c4',
|
'2d118b43f547bfe5bae806d8d47b4e596ea5b25a6c1f080aef49fbcd817c5db8',
|
||||||
'lib/libcurl.a',
|
'lib/libcurl.a',
|
||||||
[
|
[
|
||||||
'-DBUILD_CURL_EXE=OFF',
|
'-DBUILD_CURL_EXE=OFF',
|
||||||
|
|
|
@ -45,7 +45,10 @@ void
|
||||||
LogFmt(LogLevel level, const Domain &domain,
|
LogFmt(LogLevel level, const Domain &domain,
|
||||||
const S &format_str, Args&&... args) noexcept
|
const S &format_str, Args&&... args) noexcept
|
||||||
{
|
{
|
||||||
#if FMT_VERSION >= 70000
|
#if FMT_VERSION >= 90000
|
||||||
|
return LogVFmt(level, domain, format_str,
|
||||||
|
fmt::make_format_args(args...));
|
||||||
|
#elif FMT_VERSION >= 70000
|
||||||
return LogVFmt(level, domain, fmt::to_string_view(format_str),
|
return LogVFmt(level, domain, fmt::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str,
|
fmt::make_args_checked<Args...>(format_str,
|
||||||
args...));
|
args...));
|
||||||
|
|
|
@ -82,7 +82,10 @@ public:
|
||||||
|
|
||||||
template<typename S, typename... Args>
|
template<typename S, typename... Args>
|
||||||
bool Fmt(const S &format_str, Args&&... args) noexcept {
|
bool Fmt(const S &format_str, Args&&... args) noexcept {
|
||||||
#if FMT_VERSION >= 70000
|
#if FMT_VERSION >= 90000
|
||||||
|
return VFmt(format_str,
|
||||||
|
fmt::make_format_args(args...));
|
||||||
|
#elif FMT_VERSION >= 70000
|
||||||
return VFmt(fmt::to_string_view(format_str),
|
return VFmt(fmt::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str,
|
fmt::make_args_checked<Args...>(format_str,
|
||||||
args...));
|
args...));
|
||||||
|
@ -109,7 +112,10 @@ public:
|
||||||
template<typename S, typename... Args>
|
template<typename S, typename... Args>
|
||||||
void FmtError(enum ack code,
|
void FmtError(enum ack code,
|
||||||
const S &format_str, Args&&... args) noexcept {
|
const S &format_str, Args&&... args) noexcept {
|
||||||
#if FMT_VERSION >= 70000
|
#if FMT_VERSION >= 90000
|
||||||
|
return VFmtError(code, format_str,
|
||||||
|
fmt::make_format_args(args...));
|
||||||
|
#elif FMT_VERSION >= 70000
|
||||||
return VFmtError(code, fmt::to_string_view(format_str),
|
return VFmtError(code, fmt::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str,
|
fmt::make_args_checked<Args...>(format_str,
|
||||||
args...));
|
args...));
|
||||||
|
|
|
@ -332,15 +332,11 @@ handle_getvol(Client &client, Request, Response &r)
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandResult
|
CommandResult
|
||||||
handle_setvol(Client &client, Request args, Response &r)
|
handle_setvol(Client &client, Request args, Response &)
|
||||||
{
|
{
|
||||||
unsigned level = args.ParseUnsigned(0, 100);
|
unsigned level = args.ParseUnsigned(0, 100);
|
||||||
|
|
||||||
if (!volume_level_change(client.GetPartition().outputs, level)) {
|
volume_level_change(client.GetPartition().outputs, level);
|
||||||
r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
|
|
||||||
return CommandResult::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,11 +359,8 @@ handle_volume(Client &client, Request args, Response &r)
|
||||||
else if (new_volume > 100)
|
else if (new_volume > 100)
|
||||||
new_volume = 100;
|
new_volume = 100;
|
||||||
|
|
||||||
if (new_volume != old_volume &&
|
if (new_volume != old_volume)
|
||||||
!volume_level_change(outputs, new_volume)) {
|
volume_level_change(outputs, new_volume);
|
||||||
r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
|
|
||||||
return CommandResult::ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CommandResult::OK;
|
return CommandResult::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,6 +257,12 @@ public:
|
||||||
return HasFailed();
|
return HasFailed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[gnu::pure]]
|
||||||
|
bool LockIsReplayGainEnabled() const noexcept {
|
||||||
|
const std::scoped_lock<Mutex> protect(mutex);
|
||||||
|
return replay_gain_mode != ReplayGainMode::OFF;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transition this obejct from DecoderState::START to
|
* Transition this obejct from DecoderState::START to
|
||||||
* DecoderState::DECODE.
|
* DecoderState::DECODE.
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/ScopeExit.hxx"
|
#include "util/ScopeExit.hxx"
|
||||||
|
#include "util/StringCompare.hxx"
|
||||||
#include "thread/Name.hxx"
|
#include "thread/Name.hxx"
|
||||||
#include "tag/ApeReplayGain.hxx"
|
#include "tag/ApeReplayGain.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
|
@ -261,12 +262,16 @@ LoadReplayGain(DecoderClient &client, InputStream &is)
|
||||||
static void
|
static void
|
||||||
MaybeLoadReplayGain(DecoderBridge &bridge, InputStream &is)
|
MaybeLoadReplayGain(DecoderBridge &bridge, InputStream &is)
|
||||||
{
|
{
|
||||||
{
|
if (!bridge.dc.LockIsReplayGainEnabled())
|
||||||
const std::scoped_lock<Mutex> protect(bridge.dc.mutex);
|
/* ReplayGain is disabled */
|
||||||
if (bridge.dc.replay_gain_mode == ReplayGainMode::OFF)
|
return;
|
||||||
/* ReplayGain is disabled */
|
|
||||||
return;
|
if (is.HasMimeType() &&
|
||||||
}
|
StringStartsWith(is.GetMimeType(), "audio/x-mpd-"))
|
||||||
|
/* skip for (virtual) files (e.g. from the
|
||||||
|
cdio_paranoia input plugin) which cannot possibly
|
||||||
|
contain tags */
|
||||||
|
return;
|
||||||
|
|
||||||
LoadReplayGain(bridge, is);
|
LoadReplayGain(bridge, is);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,12 @@
|
||||||
#include "util/RuntimeError.hxx"
|
#include "util/RuntimeError.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
#include "util/ByteOrder.hxx"
|
#include "util/ByteOrder.hxx"
|
||||||
|
#include "util/ScopeExit.hxx"
|
||||||
#include "fs/AllocatedPath.hxx"
|
#include "fs/AllocatedPath.hxx"
|
||||||
#include "Log.hxx"
|
#include "Log.hxx"
|
||||||
#include "config/Block.hxx"
|
#include "config/Block.hxx"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
@ -48,21 +50,19 @@ class CdioParanoiaInputStream final : public InputStream {
|
||||||
CdIo_t *const cdio;
|
CdIo_t *const cdio;
|
||||||
CdromParanoia para;
|
CdromParanoia para;
|
||||||
|
|
||||||
const lsn_t lsn_from, lsn_to;
|
const lsn_t lsn_from;
|
||||||
int lsn_relofs;
|
|
||||||
|
|
||||||
char buffer[CDIO_CD_FRAMESIZE_RAW];
|
char buffer[CDIO_CD_FRAMESIZE_RAW];
|
||||||
int buffer_lsn;
|
lsn_t buffer_lsn;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex,
|
CdioParanoiaInputStream(const char *_uri, Mutex &_mutex,
|
||||||
cdrom_drive_t *_drv, CdIo_t *_cdio,
|
cdrom_drive_t *_drv, CdIo_t *_cdio,
|
||||||
bool reverse_endian,
|
bool reverse_endian,
|
||||||
lsn_t _lsn_from, lsn_t _lsn_to)
|
lsn_t _lsn_from, lsn_t lsn_to)
|
||||||
:InputStream(_uri, _mutex),
|
:InputStream(_uri, _mutex),
|
||||||
drv(_drv), cdio(_cdio), para(drv),
|
drv(_drv), cdio(_cdio), para(drv),
|
||||||
lsn_from(_lsn_from), lsn_to(_lsn_to),
|
lsn_from(_lsn_from),
|
||||||
lsn_relofs(0),
|
|
||||||
buffer_lsn(-1)
|
buffer_lsn(-1)
|
||||||
{
|
{
|
||||||
/* Set reading mode for full paranoia, but allow
|
/* Set reading mode for full paranoia, but allow
|
||||||
|
@ -173,9 +173,12 @@ cdio_detect_device()
|
||||||
if (devices == nullptr)
|
if (devices == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
AllocatedPath path = AllocatedPath::FromFS(devices[0]);
|
AtScopeExit(devices) { cdio_free_device_list(devices); };
|
||||||
cdio_free_device_list(devices);
|
|
||||||
return path;
|
if (devices[0] == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return AllocatedPath::FromFS(devices[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static InputStreamPtr
|
static InputStreamPtr
|
||||||
|
@ -271,81 +274,70 @@ CdioParanoiaInputStream::Seek(std::unique_lock<Mutex> &,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* calculate current LSN */
|
/* calculate current LSN */
|
||||||
lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
const lsn_t lsn_relofs = new_offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
offset = new_offset;
|
|
||||||
|
|
||||||
{
|
if (lsn_relofs != buffer_lsn) {
|
||||||
const ScopeUnlock unlock(mutex);
|
const ScopeUnlock unlock(mutex);
|
||||||
para.Seek(lsn_from + lsn_relofs);
|
para.Seek(lsn_from + lsn_relofs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
offset = new_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
CdioParanoiaInputStream::Read(std::unique_lock<Mutex> &,
|
||||||
void *ptr, size_t length)
|
void *ptr, size_t length)
|
||||||
{
|
{
|
||||||
size_t nbytes = 0;
|
/* end of track ? */
|
||||||
char *wptr = (char *) ptr;
|
if (IsEOF())
|
||||||
|
return 0;
|
||||||
|
|
||||||
while (length > 0) {
|
//current sector was changed ?
|
||||||
/* end of track ? */
|
const int16_t *rbuf;
|
||||||
if (lsn_from + lsn_relofs > lsn_to)
|
|
||||||
break;
|
|
||||||
|
|
||||||
//current sector was changed ?
|
const lsn_t lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
|
||||||
const int16_t *rbuf;
|
const std::size_t diff = offset % CDIO_CD_FRAMESIZE_RAW;
|
||||||
if (lsn_relofs != buffer_lsn) {
|
|
||||||
const ScopeUnlock unlock(mutex);
|
|
||||||
|
|
||||||
try {
|
if (lsn_relofs != buffer_lsn) {
|
||||||
rbuf = para.Read().data();
|
const ScopeUnlock unlock(mutex);
|
||||||
} catch (...) {
|
|
||||||
char *s_err = cdio_cddap_errors(drv);
|
|
||||||
if (s_err) {
|
|
||||||
FmtError(cdio_domain,
|
|
||||||
"paranoia_read: {}", s_err);
|
|
||||||
cdio_cddap_free_messages(s_err);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw;
|
try {
|
||||||
|
rbuf = para.Read().data();
|
||||||
|
} catch (...) {
|
||||||
|
char *s_err = cdio_cddap_errors(drv);
|
||||||
|
if (s_err) {
|
||||||
|
FmtError(cdio_domain,
|
||||||
|
"paranoia_read: {}", s_err);
|
||||||
|
cdio_cddap_free_messages(s_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
//store current buffer
|
throw;
|
||||||
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
|
||||||
buffer_lsn = lsn_relofs;
|
|
||||||
} else {
|
|
||||||
//use cached sector
|
|
||||||
rbuf = (const int16_t *)buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//correct offset
|
//store current buffer
|
||||||
const int diff = offset - lsn_relofs * CDIO_CD_FRAMESIZE_RAW;
|
memcpy(buffer, rbuf, CDIO_CD_FRAMESIZE_RAW);
|
||||||
|
buffer_lsn = lsn_relofs;
|
||||||
assert(diff >= 0 && diff < CDIO_CD_FRAMESIZE_RAW);
|
} else {
|
||||||
|
//use cached sector
|
||||||
const size_t maxwrite = CDIO_CD_FRAMESIZE_RAW - diff; //# of bytes pending in current buffer
|
rbuf = (const int16_t *)buffer;
|
||||||
const size_t len = (length < maxwrite? length : maxwrite);
|
|
||||||
|
|
||||||
//skip diff bytes from this lsn
|
|
||||||
memcpy(wptr, ((const char *)rbuf) + diff, len);
|
|
||||||
//update pointer
|
|
||||||
wptr += len;
|
|
||||||
nbytes += len;
|
|
||||||
|
|
||||||
//update offset
|
|
||||||
offset += len;
|
|
||||||
lsn_relofs = offset / CDIO_CD_FRAMESIZE_RAW;
|
|
||||||
//update length
|
|
||||||
length -= len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const size_t maxwrite = CDIO_CD_FRAMESIZE_RAW - diff; //# of bytes pending in current buffer
|
||||||
|
const std::size_t nbytes = std::min(length, maxwrite);
|
||||||
|
|
||||||
|
//skip diff bytes from this lsn
|
||||||
|
memcpy(ptr, ((const char *)rbuf) + diff, nbytes);
|
||||||
|
|
||||||
|
//update offset
|
||||||
|
offset += nbytes;
|
||||||
|
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CdioParanoiaInputStream::IsEOF() const noexcept
|
CdioParanoiaInputStream::IsEOF() const noexcept
|
||||||
{
|
{
|
||||||
return lsn_from + lsn_relofs > lsn_to;
|
return offset >= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr const char *cdio_paranoia_prefixes[] = {
|
static constexpr const char *cdio_paranoia_prefixes[] = {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
--- curl-7.75.0.orig/CMakeLists.txt 2021-02-02 09:26:24.000000000 +0100
|
Index: curl-7.84.0/CMakeLists.txt
|
||||||
+++ curl-7.75.0/CMakeLists.txt 2021-03-25 20:17:25.445684029 +0100
|
===================================================================
|
||||||
@@ -1453,7 +1453,7 @@
|
--- curl-7.84.0.orig/CMakeLists.txt
|
||||||
|
+++ curl-7.84.0/CMakeLists.txt
|
||||||
|
@@ -1536,7 +1536,7 @@ set(includedir "\${prefix}/
|
||||||
set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
|
||||||
set(LIBCURL_LIBS "")
|
set(LIBCURL_LIBS "")
|
||||||
set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
|
set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
|
@ -8,4 +10,4 @@
|
||||||
+foreach(_lib ${CURL_LIBS})
|
+foreach(_lib ${CURL_LIBS})
|
||||||
if(TARGET "${_lib}")
|
if(TARGET "${_lib}")
|
||||||
set(_libname "${_lib}")
|
set(_libname "${_lib}")
|
||||||
get_target_property(_libtype "${_libname}" TYPE)
|
get_target_property(_imported "${_libname}" IMPORTED)
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
Index: curl-7.71.1/lib/url.c
|
Index: curl-7.84.0/lib/url.c
|
||||||
===================================================================
|
===================================================================
|
||||||
--- curl-7.71.1.orig/lib/url.c
|
--- curl-7.84.0.orig/lib/url.c
|
||||||
+++ curl-7.71.1/lib/url.c
|
+++ curl-7.84.0/lib/url.c
|
||||||
@@ -2871,6 +2871,7 @@
|
@@ -3003,6 +3003,7 @@ static CURLcode override_login(struct Cu
|
||||||
}
|
|
||||||
|
|
||||||
|
#ifndef CURL_DISABLE_NETRC
|
||||||
conn->bits.netrc = FALSE;
|
conn->bits.netrc = FALSE;
|
||||||
+#ifndef __BIONIC__
|
+#ifndef __BIONIC__
|
||||||
if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
|
if(data->set.use_netrc && !data->set.str[STRING_USERNAME]) {
|
||||||
bool netrc_user_changed = FALSE;
|
bool netrc_user_changed = FALSE;
|
||||||
bool netrc_passwd_changed = FALSE;
|
bool netrc_passwd_changed = FALSE;
|
||||||
@@ -2895,6 +2896,7 @@
|
@@ -3079,6 +3080,7 @@ static CURLcode override_login(struct Cu
|
||||||
conn->bits.user_passwd = TRUE; /* enable user+password */
|
return CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+#endif
|
+#endif
|
||||||
|
|
||||||
/* for updated strings, we update them in the URL */
|
return CURLE_OK;
|
||||||
if(*userp) {
|
}
|
||||||
|
|
|
@ -73,42 +73,77 @@ MultipleOutputs::GetVolume() const noexcept
|
||||||
return total / ok;
|
return total / ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
enum class SetVolumeResult {
|
||||||
output_mixer_set_volume(AudioOutputControl &ao, unsigned volume) noexcept
|
NO_MIXER,
|
||||||
|
DISABLED,
|
||||||
|
ERROR,
|
||||||
|
OK,
|
||||||
|
};
|
||||||
|
|
||||||
|
static SetVolumeResult
|
||||||
|
output_mixer_set_volume(AudioOutputControl &ao, unsigned volume)
|
||||||
{
|
{
|
||||||
assert(volume <= 100);
|
assert(volume <= 100);
|
||||||
|
|
||||||
auto *mixer = ao.GetMixer();
|
auto *mixer = ao.GetMixer();
|
||||||
if (mixer == nullptr)
|
if (mixer == nullptr)
|
||||||
return false;
|
return SetVolumeResult::NO_MIXER;
|
||||||
|
|
||||||
/* software mixers are always updated, even if they are
|
/* software mixers are always updated, even if they are
|
||||||
disabled */
|
disabled */
|
||||||
if (!ao.IsReallyEnabled() && !mixer->IsPlugin(software_mixer_plugin))
|
if (!mixer->IsPlugin(software_mixer_plugin) &&
|
||||||
return false;
|
/* "global" mixers can be used even if the output hasn't
|
||||||
|
been used yet */
|
||||||
|
!(mixer->IsGlobal() ? ao.IsEnabled() : ao.IsReallyEnabled()))
|
||||||
|
return SetVolumeResult::DISABLED;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mixer_set_volume(mixer, volume);
|
mixer_set_volume(mixer, volume);
|
||||||
return true;
|
return SetVolumeResult::OK;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
FmtError(mixer_domain,
|
FmtError(mixer_domain,
|
||||||
"Failed to set mixer for '{}': {}",
|
"Failed to set mixer for '{}': {}",
|
||||||
ao.GetName(), std::current_exception());
|
ao.GetName(), std::current_exception());
|
||||||
return false;
|
std::throw_with_nested(std::runtime_error(fmt::format("Failed to set mixer for '{}'",
|
||||||
|
ao.GetName())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
MultipleOutputs::SetVolume(unsigned volume) noexcept
|
MultipleOutputs::SetVolume(unsigned volume)
|
||||||
{
|
{
|
||||||
assert(volume <= 100);
|
assert(volume <= 100);
|
||||||
|
|
||||||
bool success = false;
|
SetVolumeResult result = SetVolumeResult::NO_MIXER;
|
||||||
for (const auto &ao : outputs)
|
std::exception_ptr error;
|
||||||
success = output_mixer_set_volume(*ao, volume)
|
|
||||||
|| success;
|
|
||||||
|
|
||||||
return success;
|
for (const auto &ao : outputs) {
|
||||||
|
try {
|
||||||
|
auto r = output_mixer_set_volume(*ao, volume);
|
||||||
|
if (r > result)
|
||||||
|
result = r;
|
||||||
|
} catch (...) {
|
||||||
|
/* remember the first error */
|
||||||
|
if (!error) {
|
||||||
|
error = std::current_exception();
|
||||||
|
result = SetVolumeResult::ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (result) {
|
||||||
|
case SetVolumeResult::NO_MIXER:
|
||||||
|
throw std::runtime_error{"No mixer"};
|
||||||
|
|
||||||
|
case SetVolumeResult::DISABLED:
|
||||||
|
throw std::runtime_error{"All outputs are disabled"};
|
||||||
|
|
||||||
|
case SetVolumeResult::ERROR:
|
||||||
|
std::rethrow_exception(error);
|
||||||
|
|
||||||
|
case SetVolumeResult::OK:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
|
@ -60,9 +60,9 @@ mixer_open(Mixer *mixer)
|
||||||
try {
|
try {
|
||||||
mixer->Open();
|
mixer->Open();
|
||||||
mixer->open = true;
|
mixer->open = true;
|
||||||
mixer->failed = false;
|
mixer->failure = {};
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
mixer->failed = true;
|
mixer->failure = std::current_exception();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,7 @@ mixer_close_internal(Mixer *mixer)
|
||||||
|
|
||||||
mixer->Close();
|
mixer->Close();
|
||||||
mixer->open = false;
|
mixer->open = false;
|
||||||
|
mixer->failure = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -95,20 +96,6 @@ mixer_auto_close(Mixer *mixer)
|
||||||
mixer_close(mixer);
|
mixer_close(mixer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Close the mixer due to failure. The mutex must be locked before
|
|
||||||
* calling this function.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
mixer_failed(Mixer *mixer)
|
|
||||||
{
|
|
||||||
assert(mixer->open);
|
|
||||||
|
|
||||||
mixer_close_internal(mixer);
|
|
||||||
|
|
||||||
mixer->failed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
mixer_get_volume(Mixer *mixer)
|
mixer_get_volume(Mixer *mixer)
|
||||||
{
|
{
|
||||||
|
@ -116,7 +103,7 @@ mixer_get_volume(Mixer *mixer)
|
||||||
|
|
||||||
assert(mixer != nullptr);
|
assert(mixer != nullptr);
|
||||||
|
|
||||||
if (mixer->plugin.global && !mixer->failed)
|
if (mixer->plugin.global && !mixer->failure)
|
||||||
mixer_open(mixer);
|
mixer_open(mixer);
|
||||||
|
|
||||||
const std::scoped_lock<Mutex> protect(mixer->mutex);
|
const std::scoped_lock<Mutex> protect(mixer->mutex);
|
||||||
|
@ -125,7 +112,8 @@ mixer_get_volume(Mixer *mixer)
|
||||||
try {
|
try {
|
||||||
volume = mixer->GetVolume();
|
volume = mixer->GetVolume();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
mixer_failed(mixer);
|
mixer_close_internal(mixer);
|
||||||
|
mixer->failure = std::current_exception();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
@ -140,11 +128,13 @@ mixer_set_volume(Mixer *mixer, unsigned volume)
|
||||||
assert(mixer != nullptr);
|
assert(mixer != nullptr);
|
||||||
assert(volume <= 100);
|
assert(volume <= 100);
|
||||||
|
|
||||||
if (mixer->plugin.global && !mixer->failed)
|
if (mixer->plugin.global && !mixer->failure)
|
||||||
mixer_open(mixer);
|
mixer_open(mixer);
|
||||||
|
|
||||||
const std::scoped_lock<Mutex> protect(mixer->mutex);
|
const std::scoped_lock<Mutex> protect(mixer->mutex);
|
||||||
|
|
||||||
if (mixer->open)
|
if (mixer->open)
|
||||||
mixer->SetVolume(volume);
|
mixer->SetVolume(volume);
|
||||||
|
else if (mixer->failure)
|
||||||
|
std::rethrow_exception(mixer->failure);
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
#include "util/Compiler.h"
|
#include "util/Compiler.h"
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
class MixerListener;
|
class MixerListener;
|
||||||
|
|
||||||
class Mixer {
|
class Mixer {
|
||||||
|
@ -39,17 +41,17 @@ public:
|
||||||
*/
|
*/
|
||||||
Mutex mutex;
|
Mutex mutex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains error details if this mixer has failed. If set,
|
||||||
|
* it should not be reopened automatically.
|
||||||
|
*/
|
||||||
|
std::exception_ptr failure;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the mixer device currently open?
|
* Is the mixer device currently open?
|
||||||
*/
|
*/
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this mixer failed, and should not be reopened
|
|
||||||
* automatically?
|
|
||||||
*/
|
|
||||||
bool failed = false;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Mixer(const MixerPlugin &_plugin,
|
explicit Mixer(const MixerPlugin &_plugin,
|
||||||
MixerListener &_listener) noexcept
|
MixerListener &_listener) noexcept
|
||||||
|
@ -63,6 +65,10 @@ public:
|
||||||
return &plugin == &other;
|
return &plugin == &other;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsGlobal() const noexcept {
|
||||||
|
return plugin.global;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open mixer device
|
* Open mixer device
|
||||||
*
|
*
|
||||||
|
|
|
@ -71,16 +71,16 @@ software_volume_change(MultipleOutputs &outputs, unsigned volume)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static void
|
||||||
hardware_volume_change(MultipleOutputs &outputs, unsigned volume)
|
hardware_volume_change(MultipleOutputs &outputs, unsigned volume)
|
||||||
{
|
{
|
||||||
/* reset the cache */
|
/* reset the cache */
|
||||||
last_hardware_volume = -1;
|
last_hardware_volume = -1;
|
||||||
|
|
||||||
return outputs.SetVolume(volume);
|
outputs.SetVolume(volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
void
|
||||||
volume_level_change(MultipleOutputs &outputs, unsigned volume)
|
volume_level_change(MultipleOutputs &outputs, unsigned volume)
|
||||||
{
|
{
|
||||||
assert(volume <= 100);
|
assert(volume <= 100);
|
||||||
|
@ -89,7 +89,7 @@ volume_level_change(MultipleOutputs &outputs, unsigned volume)
|
||||||
|
|
||||||
idle_add(IDLE_MIXER);
|
idle_add(IDLE_MIXER);
|
||||||
|
|
||||||
return hardware_volume_change(outputs, volume);
|
hardware_volume_change(outputs, volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -30,7 +30,10 @@ InvalidateHardwareVolume() noexcept;
|
||||||
int
|
int
|
||||||
volume_level_get(const MultipleOutputs &outputs) noexcept;
|
volume_level_get(const MultipleOutputs &outputs) noexcept;
|
||||||
|
|
||||||
bool
|
/**
|
||||||
|
* Throws on error.
|
||||||
|
*/
|
||||||
|
void
|
||||||
volume_level_change(MultipleOutputs &outputs, unsigned volume);
|
volume_level_change(MultipleOutputs &outputs, unsigned volume);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -141,10 +141,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* Sets the volume on all available mixers.
|
* Sets the volume on all available mixers.
|
||||||
*
|
*
|
||||||
|
* Throws on error.
|
||||||
|
*
|
||||||
* @param volume the volume (range 0..100)
|
* @param volume the volume (range 0..100)
|
||||||
* @return true on success, false on failure
|
|
||||||
*/
|
*/
|
||||||
bool SetVolume(unsigned volume) noexcept;
|
void SetVolume(unsigned volume);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Similar to GetVolume(), but gets the volume only for
|
* Similar to GetVolume(), but gets the volume only for
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "../Error.hxx"
|
#include "../Error.hxx"
|
||||||
#include "mixer/plugins/PipeWireMixerPlugin.hxx"
|
#include "mixer/plugins/PipeWireMixerPlugin.hxx"
|
||||||
#include "pcm/Silence.hxx"
|
#include "pcm/Silence.hxx"
|
||||||
|
#include "lib/fmt/ExceptionFormatter.hxx"
|
||||||
#include "system/Error.hxx"
|
#include "system/Error.hxx"
|
||||||
#include "util/BitReverse.hxx"
|
#include "util/BitReverse.hxx"
|
||||||
#include "util/Domain.hxx"
|
#include "util/Domain.hxx"
|
||||||
|
@ -55,6 +56,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <numeric>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -84,7 +86,14 @@ class PipeWireOutput final : AudioOutput {
|
||||||
|
|
||||||
uint32_t target_id = PW_ID_ANY;
|
uint32_t target_id = PW_ID_ANY;
|
||||||
|
|
||||||
float volume = 1.0;
|
/**
|
||||||
|
* The current volume level (0.0 .. 1.0).
|
||||||
|
*
|
||||||
|
* This get initialized to -1 which means "unknown", so
|
||||||
|
* restore_volume will not attempt to override PipeWire's
|
||||||
|
* initial volume level.
|
||||||
|
*/
|
||||||
|
float volume = -1;
|
||||||
|
|
||||||
PipeWireMixer *mixer = nullptr;
|
PipeWireMixer *mixer = nullptr;
|
||||||
unsigned channels;
|
unsigned channels;
|
||||||
|
@ -216,27 +225,34 @@ private:
|
||||||
o.Drained();
|
o.Drained();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlInfo(const struct pw_stream_control *control) noexcept {
|
void OnChannelVolumes(const struct pw_stream_control &control) noexcept {
|
||||||
float sum = 0;
|
if (control.n_values < 1)
|
||||||
unsigned c;
|
return;
|
||||||
for (c = 0; c < control->n_values; c++)
|
|
||||||
sum += control->values[c];
|
|
||||||
|
|
||||||
sum /= control->n_values;
|
float sum = std::accumulate(control.values,
|
||||||
|
control.values + control.n_values,
|
||||||
|
0.0f);
|
||||||
|
volume = std::cbrt(sum / control.n_values);
|
||||||
|
|
||||||
if (mixer != nullptr)
|
if (mixer != nullptr)
|
||||||
pipewire_mixer_on_change(*mixer, std::cbrt(sum));
|
pipewire_mixer_on_change(*mixer, volume);
|
||||||
|
|
||||||
pw_thread_loop_signal(thread_loop, false);
|
pw_thread_loop_signal(thread_loop, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ControlInfo(void *data,
|
void ControlInfo([[maybe_unused]] uint32_t id,
|
||||||
[[maybe_unused]] uint32_t id,
|
const struct pw_stream_control &control) noexcept {
|
||||||
|
switch (id) {
|
||||||
|
case SPA_PROP_channelVolumes:
|
||||||
|
OnChannelVolumes(control);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ControlInfo(void *data, uint32_t id,
|
||||||
const struct pw_stream_control *control) noexcept {
|
const struct pw_stream_control *control) noexcept {
|
||||||
auto &o = *(PipeWireOutput *)data;
|
auto &o = *(PipeWireOutput *)data;
|
||||||
if (control->name != nullptr &&
|
o.ControlInfo(id, *control);
|
||||||
StringIsEqual(control->name, "Channel Volumes"))
|
|
||||||
o.ControlInfo(control);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
|
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
|
||||||
|
@ -308,22 +324,38 @@ PipeWireOutput::PipeWireOutput(const ConfigBlock &block)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws on error.
|
||||||
|
*
|
||||||
|
* @param volume a volume level between 0.0 and 1.0
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
SetVolume(struct pw_stream &stream, unsigned channels, float volume)
|
||||||
|
{
|
||||||
|
float value[MAX_CHANNELS];
|
||||||
|
std::fill_n(value, channels, volume * volume * volume);
|
||||||
|
|
||||||
|
if (pw_stream_set_control(&stream,
|
||||||
|
SPA_PROP_channelVolumes, channels, value,
|
||||||
|
0) != 0)
|
||||||
|
throw std::runtime_error("pw_stream_set_control() failed");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
PipeWireOutput::SetVolume(float _volume)
|
PipeWireOutput::SetVolume(float _volume)
|
||||||
{
|
{
|
||||||
|
if (thread_loop == nullptr) {
|
||||||
|
/* the mixer is open (because it is a "global" mixer),
|
||||||
|
but Enable() on this output has not yet been
|
||||||
|
called */
|
||||||
|
volume = _volume;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const PipeWire::ThreadLoopLock lock(thread_loop);
|
const PipeWire::ThreadLoopLock lock(thread_loop);
|
||||||
|
|
||||||
float newvol = _volume*_volume*_volume;
|
if (stream != nullptr && !restore_volume)
|
||||||
|
::SetVolume(*stream, channels, _volume);
|
||||||
if (stream != nullptr && !restore_volume) {
|
|
||||||
float vol[MAX_CHANNELS];
|
|
||||||
std::fill_n(vol, channels, newvol);
|
|
||||||
|
|
||||||
if (pw_stream_set_control(stream,
|
|
||||||
SPA_PROP_channelVolumes, channels, vol,
|
|
||||||
0) != 0)
|
|
||||||
throw std::runtime_error("pw_stream_set_control() failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
volume = _volume;
|
volume = _volume;
|
||||||
}
|
}
|
||||||
|
@ -639,7 +671,16 @@ PipeWireOutput::ParamChanged([[maybe_unused]] uint32_t id,
|
||||||
{
|
{
|
||||||
if (restore_volume) {
|
if (restore_volume) {
|
||||||
restore_volume = false;
|
restore_volume = false;
|
||||||
SetVolume(volume);
|
|
||||||
|
if (volume >= 0) {
|
||||||
|
try {
|
||||||
|
::SetVolume(*stream, channels, volume);
|
||||||
|
} catch (...) {
|
||||||
|
FmtError(pipewire_output_domain,
|
||||||
|
FMT_STRING("Failed to restore volume: {}"),
|
||||||
|
std::current_exception());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
|
#if defined(ENABLE_DSD) && defined(SPA_AUDIO_DSD_FLAG_NONE)
|
||||||
|
@ -824,6 +865,17 @@ PipeWireOutput::Drain()
|
||||||
{
|
{
|
||||||
const PipeWire::ThreadLoopLock lock(thread_loop);
|
const PipeWire::ThreadLoopLock lock(thread_loop);
|
||||||
|
|
||||||
|
if (drained)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!active) {
|
||||||
|
/* there is data in the ring_buffer, but the stream is
|
||||||
|
not yet active; activate it now to ensure it is
|
||||||
|
played before this method returns */
|
||||||
|
active = true;
|
||||||
|
pw_stream_set_active(stream, true);
|
||||||
|
}
|
||||||
|
|
||||||
drain_requested = true;
|
drain_requested = true;
|
||||||
AtScopeExit(this) { drain_requested = false; };
|
AtScopeExit(this) { drain_requested = false; };
|
||||||
|
|
||||||
|
@ -839,7 +891,24 @@ PipeWireOutput::Cancel() noexcept
|
||||||
const PipeWire::ThreadLoopLock lock(thread_loop);
|
const PipeWire::ThreadLoopLock lock(thread_loop);
|
||||||
interrupted = false;
|
interrupted = false;
|
||||||
|
|
||||||
|
if (drained)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* clear MPD's ring buffer */
|
||||||
ring_buffer->reset();
|
ring_buffer->reset();
|
||||||
|
|
||||||
|
/* clear libpipewire's buffer */
|
||||||
|
pw_stream_flush(stream, false);
|
||||||
|
drained = true;
|
||||||
|
|
||||||
|
/* pause the PipeWire stream so libpipewire ceases invoking
|
||||||
|
the "process" callback (we have no data until our Play()
|
||||||
|
method gets called again); the stream will be resume by
|
||||||
|
Play() after the ring_buffer has been refilled */
|
||||||
|
if (active) {
|
||||||
|
active = false;
|
||||||
|
pw_stream_set_active(stream, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -215,9 +215,8 @@ SnapcastOutput::RemoveClient(SnapcastClient &client) noexcept
|
||||||
std::chrono::steady_clock::duration
|
std::chrono::steady_clock::duration
|
||||||
SnapcastOutput::Delay() const noexcept
|
SnapcastOutput::Delay() const noexcept
|
||||||
{
|
{
|
||||||
if (!LockHasClients() && pause) {
|
if (pause) {
|
||||||
/* if there's no client and this output is paused,
|
/* Pause() will not do anything, it will not fill
|
||||||
then Pause() will not do anything, it will not fill
|
|
||||||
the buffer and it will not update the timer;
|
the buffer and it will not update the timer;
|
||||||
therefore, we reset the timer here */
|
therefore, we reset the timer here */
|
||||||
timer->Reset();
|
timer->Reset();
|
||||||
|
|
|
@ -3,10 +3,10 @@ directory = fmt-8.1.1
|
||||||
source_url = https://github.com/fmtlib/fmt/archive/8.1.1.tar.gz
|
source_url = https://github.com/fmtlib/fmt/archive/8.1.1.tar.gz
|
||||||
source_filename = fmt-8.1.1.tar.gz
|
source_filename = fmt-8.1.1.tar.gz
|
||||||
source_hash = 3d794d3cf67633b34b2771eb9f073bde87e846e0d395d254df7b211ef1ec7346
|
source_hash = 3d794d3cf67633b34b2771eb9f073bde87e846e0d395d254df7b211ef1ec7346
|
||||||
patch_filename = fmt_8.1.1-1_patch.zip
|
patch_filename = fmt_8.1.1-2_patch.zip
|
||||||
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_8.1.1-1/get_patch
|
patch_url = https://wrapdb.mesonbuild.com/v2/fmt_8.1.1-2/get_patch
|
||||||
patch_hash = 6035a67c7a8c90bed74c293c7265c769f47a69816125f7566bccb8e2543cee5e
|
patch_hash = cd001046281330a8862591780a9ea71a1fa594edd0d015deb24e44680c9ea33b
|
||||||
|
wrapdb_version = 8.1.1-2
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
fmt = fmt_dep
|
fmt = fmt_dep
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,10 @@ directory = libvorbis-1.3.7
|
||||||
source_url = https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz
|
source_url = https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.tar.xz
|
||||||
source_filename = libvorbis-1.3.7.tar.xz
|
source_filename = libvorbis-1.3.7.tar.xz
|
||||||
source_hash = b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b
|
source_hash = b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b
|
||||||
patch_filename = vorbis_1.3.7-2_patch.zip
|
patch_filename = vorbis_1.3.7-3_patch.zip
|
||||||
patch_url = https://wrapdb.mesonbuild.com/v2/vorbis_1.3.7-2/get_patch
|
patch_url = https://wrapdb.mesonbuild.com/v2/vorbis_1.3.7-3/get_patch
|
||||||
patch_hash = fe302576cbf8408754b332b539ea1b83f0f96fa9aae50a5d1fea911713d5f21c
|
patch_hash = 6cb90a61ede8c64d3e8e379b96dcc800c9dd69e925122b3d73d8f59a563c3afa
|
||||||
|
wrapdb_version = 1.3.7-3
|
||||||
|
|
||||||
[provide]
|
[provide]
|
||||||
vorbis = vorbis_dep
|
vorbis = vorbis_dep
|
||||||
|
|
Loading…
Reference in New Issue