mirror of
https://github.com/love2d/megasource.git
synced 2026-08-19 12:14:41 +02:00
update OpenAL-Soft to 1.24.3.
This commit is contained in:
@@ -23,25 +23,31 @@
|
||||
#include "pipewire.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <bitset>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <list>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
#include "albit.h"
|
||||
#include "alc/alconfig.h"
|
||||
#include "alc/backends/base.h"
|
||||
#include "almalloc.h"
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "core/devformat.h"
|
||||
@@ -49,6 +55,8 @@
|
||||
#include "core/helpers.h"
|
||||
#include "core/logging.h"
|
||||
#include "dynload.h"
|
||||
#include "fmt/core.h"
|
||||
#include "fmt/ranges.h"
|
||||
#include "opthelpers.h"
|
||||
#include "ringbuffer.h"
|
||||
|
||||
@@ -72,6 +80,7 @@ _Pragma("GCC diagnostic ignored \"-Weverything\"")
|
||||
#include "spa/buffer/buffer.h"
|
||||
#include "spa/param/audio/format-utils.h"
|
||||
#include "spa/param/audio/raw.h"
|
||||
#include "spa/param/format.h"
|
||||
#include "spa/param/param.h"
|
||||
#include "spa/pod/builder.h"
|
||||
#include "spa/utils/json.h"
|
||||
@@ -126,6 +135,9 @@ _Pragma("GCC diagnostic pop")
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T> [[nodiscard]] constexpr
|
||||
auto as_const_ptr(T *ptr) noexcept -> std::add_const_t<T>* { return ptr; }
|
||||
|
||||
struct PodDynamicBuilder {
|
||||
private:
|
||||
std::vector<std::byte> mStorage;
|
||||
@@ -137,7 +149,7 @@ private:
|
||||
mStorage.resize(size);
|
||||
}
|
||||
catch(...) {
|
||||
ERR("Failed to resize POD storage\n");
|
||||
ERR("Failed to resize POD storage");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mPod.data = mStorage.data();
|
||||
@@ -146,7 +158,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
PodDynamicBuilder(uint32_t initSize=0) : mStorage(initSize)
|
||||
explicit PodDynamicBuilder(uint32_t initSize=1024) : mStorage(initSize)
|
||||
, mPod{make_pod_builder(mStorage.data(), initSize)}
|
||||
{
|
||||
static constexpr auto callbacks{[]
|
||||
@@ -183,12 +195,13 @@ bool check_version(const char *version)
|
||||
* future.
|
||||
*/
|
||||
int major{0}, minor{0}, revision{0};
|
||||
/* NOLINTNEXTLINE(cert-err34-c,cppcoreguidelines-pro-type-vararg) */
|
||||
int ret{sscanf(version, "%d.%d.%d", &major, &minor, &revision)};
|
||||
return ret == 3 && (major > PW_MAJOR || (major == PW_MAJOR && minor > PW_MINOR)
|
||||
|| (major == PW_MAJOR && minor == PW_MINOR && revision >= PW_MICRO));
|
||||
}
|
||||
|
||||
#ifdef HAVE_DYNLOAD
|
||||
#if HAVE_DYNLOAD
|
||||
#define PWIRE_FUNCS(MAGIC) \
|
||||
MAGIC(pw_context_connect) \
|
||||
MAGIC(pw_context_destroy) \
|
||||
@@ -245,7 +258,7 @@ bool pwire_load()
|
||||
pwire_handle = LoadLib(pwire_library);
|
||||
if(!pwire_handle)
|
||||
{
|
||||
WARN("Failed to load %s\n", pwire_library);
|
||||
WARN("Failed to load {}", pwire_library);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -259,7 +272,7 @@ bool pwire_load()
|
||||
|
||||
if(!missing_funcs.empty())
|
||||
{
|
||||
WARN("Missing expected functions:%s\n", missing_funcs.c_str());
|
||||
WARN("Missing expected functions:{}", missing_funcs);
|
||||
CloseLib(pwire_handle);
|
||||
pwire_handle = nullptr;
|
||||
return false;
|
||||
@@ -405,9 +418,10 @@ struct PwStreamDeleter {
|
||||
};
|
||||
using PwStreamPtr = std::unique_ptr<pw_stream,PwStreamDeleter>;
|
||||
|
||||
/* Enums for bitflags... again... *sigh* */
|
||||
/* NOLINTBEGIN(*EnumCastOutOfRange) Enums for bitflags... again... *sigh* */
|
||||
constexpr pw_stream_flags operator|(pw_stream_flags lhs, pw_stream_flags rhs) noexcept
|
||||
{ return static_cast<pw_stream_flags>(lhs | al::to_underlying(rhs)); }
|
||||
/* NOLINTEND(*EnumCastOutOfRange) */
|
||||
|
||||
constexpr pw_stream_flags& operator|=(pw_stream_flags &lhs, pw_stream_flags rhs) noexcept
|
||||
{ lhs = lhs | rhs; return lhs; }
|
||||
@@ -491,7 +505,7 @@ struct NodeProxy {
|
||||
|
||||
uint32_t mId{};
|
||||
|
||||
PwNodePtr mNode{};
|
||||
PwNodePtr mNode;
|
||||
spa_hook mListener{};
|
||||
|
||||
NodeProxy(uint32_t id, PwNodePtr node)
|
||||
@@ -526,7 +540,7 @@ struct MetadataProxy {
|
||||
|
||||
uint32_t mId{};
|
||||
|
||||
PwMetadataPtr mMetadata{};
|
||||
PwMetadataPtr mMetadata;
|
||||
spa_hook mListener{};
|
||||
|
||||
MetadataProxy(uint32_t id, PwMetadataPtr mdata)
|
||||
@@ -547,10 +561,10 @@ struct MetadataProxy {
|
||||
* to objects being added to or removed from the registry.
|
||||
*/
|
||||
struct EventManager {
|
||||
ThreadMainloop mLoop{};
|
||||
PwContextPtr mContext{};
|
||||
PwCorePtr mCore{};
|
||||
PwRegistryPtr mRegistry{};
|
||||
ThreadMainloop mLoop;
|
||||
PwContextPtr mContext;
|
||||
PwCorePtr mCore;
|
||||
PwRegistryPtr mRegistry;
|
||||
spa_hook mRegistryListener{};
|
||||
spa_hook mCoreListener{};
|
||||
|
||||
@@ -579,8 +593,8 @@ struct EventManager {
|
||||
auto lock() const { return mLoop.lock(); }
|
||||
auto unlock() const { return mLoop.unlock(); }
|
||||
|
||||
[[nodiscard]] inline
|
||||
bool initIsDone(std::memory_order m=std::memory_order_seq_cst) const noexcept
|
||||
[[nodiscard]]
|
||||
auto initIsDone(std::memory_order m=std::memory_order_seq_cst) const noexcept -> bool
|
||||
{ return mInitDone.load(m); }
|
||||
|
||||
/**
|
||||
@@ -753,7 +767,7 @@ void DeviceNode::Remove(uint32_t id)
|
||||
{
|
||||
if(n.mId != id)
|
||||
return false;
|
||||
TRACE("Removing device \"%s\"\n", n.mDevName.c_str());
|
||||
TRACE("Removing device \"{}\"", n.mDevName);
|
||||
if(gEventHandler.initIsDone(std::memory_order_relaxed))
|
||||
{
|
||||
const std::string msg{"Device removed: "+n.mName};
|
||||
@@ -822,7 +836,7 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
|
||||
const uint podType{get_pod_type(value)};
|
||||
if(podType != SPA_TYPE_Int)
|
||||
{
|
||||
WARN(" Unhandled sample rate POD type: %u\n", podType);
|
||||
WARN(" Unhandled sample rate POD type: {}", podType);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -830,13 +844,13 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
|
||||
{
|
||||
if(nvals != 3)
|
||||
{
|
||||
WARN(" Unexpected SPA_CHOICE_Range count: %u\n", nvals);
|
||||
WARN(" Unexpected SPA_CHOICE_Range count: {}", nvals);
|
||||
return;
|
||||
}
|
||||
auto srates = get_pod_body<int32_t,3>(value);
|
||||
|
||||
/* [0] is the default, [1] is the min, and [2] is the max. */
|
||||
TRACE(" sample rate: %d (range: %d -> %d)\n", srates[0], srates[1], srates[2]);
|
||||
TRACE(" sample rate: {}, range: {}", srates[0], srates.subspan<1>());
|
||||
if(!mSampleRate || force_update)
|
||||
mSampleRate = static_cast<uint>(std::clamp<int>(srates[0], MinOutputRate,
|
||||
MaxOutputRate));
|
||||
@@ -847,19 +861,13 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
|
||||
{
|
||||
if(nvals == 0)
|
||||
{
|
||||
WARN(" Unexpected SPA_CHOICE_Enum count: %u\n", nvals);
|
||||
WARN(" Unexpected SPA_CHOICE_Enum count: {}", nvals);
|
||||
return;
|
||||
}
|
||||
auto srates = get_pod_body<int32_t>(value, nvals);
|
||||
|
||||
/* [0] is the default, [1...size()-1] are available selections. */
|
||||
std::string others{(srates.size() > 1) ? std::to_string(srates[1]) : std::string{}};
|
||||
for(size_t i{2};i < srates.size();++i)
|
||||
{
|
||||
others += ", ";
|
||||
others += std::to_string(srates[i]);
|
||||
}
|
||||
TRACE(" sample rate: %d (%s)\n", srates[0], others.c_str());
|
||||
TRACE(" sample rate: {}, list: {}", srates[0], srates.subspan(1));
|
||||
/* Pick the first rate listed that's within the allowed range (default
|
||||
* rate if possible).
|
||||
*/
|
||||
@@ -879,19 +887,19 @@ void DeviceNode::parseSampleRate(const spa_pod *value, bool force_update) noexce
|
||||
{
|
||||
if(nvals != 1)
|
||||
{
|
||||
WARN(" Unexpected SPA_CHOICE_None count: %u\n", nvals);
|
||||
WARN(" Unexpected SPA_CHOICE_None count: {}", nvals);
|
||||
return;
|
||||
}
|
||||
auto srates = get_pod_body<int32_t,1>(value);
|
||||
|
||||
TRACE(" sample rate: %d\n", srates[0]);
|
||||
TRACE(" sample rate: {}", srates[0]);
|
||||
if(!mSampleRate || force_update)
|
||||
mSampleRate = static_cast<uint>(std::clamp<int>(srates[0], MinOutputRate,
|
||||
MaxOutputRate));
|
||||
return;
|
||||
}
|
||||
|
||||
WARN(" Unhandled sample rate choice type: %u\n", choiceType);
|
||||
WARN(" Unhandled sample rate choice type: {}", choiceType);
|
||||
}
|
||||
|
||||
void DeviceNode::parsePositions(const spa_pod *value, bool force_update) noexcept
|
||||
@@ -901,7 +909,7 @@ void DeviceNode::parsePositions(const spa_pod *value, bool force_update) noexcep
|
||||
|
||||
if(choiceType != SPA_CHOICE_None || choiceCount != 1)
|
||||
{
|
||||
ERR(" Unexpected positions choice: type=%u, count=%u\n", choiceType, choiceCount);
|
||||
ERR(" Unexpected positions choice: type={}, count={}", choiceType, choiceCount);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -932,7 +940,7 @@ void DeviceNode::parsePositions(const spa_pod *value, bool force_update) noexcep
|
||||
else
|
||||
mChannels = DevFmtMono;
|
||||
}
|
||||
TRACE(" %zu position%s for %s%s\n", chanmap.size(), (chanmap.size()==1)?"":"s",
|
||||
TRACE(" {} position{} for {}{}", chanmap.size(), (chanmap.size()==1)?"":"s",
|
||||
DevFmtChannelsString(mChannels), mIs51Rear?"(rear)":"");
|
||||
}
|
||||
|
||||
@@ -944,7 +952,7 @@ void DeviceNode::parseChannelCount(const spa_pod *value, bool force_update) noex
|
||||
|
||||
if(choiceType != SPA_CHOICE_None || choiceCount != 1)
|
||||
{
|
||||
ERR(" Unexpected positions choice: type=%u, count=%u\n", choiceType, choiceCount);
|
||||
ERR(" Unexpected positions choice: type={}, count={}", choiceType, choiceCount);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -960,7 +968,7 @@ void DeviceNode::parseChannelCount(const spa_pod *value, bool force_update) noex
|
||||
else if(*chancount >= 1)
|
||||
mChannels = DevFmtMono;
|
||||
}
|
||||
TRACE(" %d channel%s for %s\n", *chancount, (*chancount==1)?"":"s",
|
||||
TRACE(" {} channel{} for {}", *chancount, (*chancount==1)?"":"s",
|
||||
DevFmtChannelsString(mChannels));
|
||||
}
|
||||
|
||||
@@ -999,7 +1007,7 @@ void NodeProxy::infoCallback(void*, const pw_node_info *info) noexcept
|
||||
ntype = NodeType::Duplex;
|
||||
else
|
||||
{
|
||||
TRACE("Dropping device node %u which became type \"%s\"\n", info->id, media_class);
|
||||
TRACE("Dropping device node {} which became type \"{}\"", info->id, media_class);
|
||||
DeviceNode::Remove(info->id);
|
||||
return;
|
||||
}
|
||||
@@ -1018,20 +1026,23 @@ void NodeProxy::infoCallback(void*, const pw_node_info *info) noexcept
|
||||
serial_id = std::strtoull(serial_str, &serial_end, 0);
|
||||
if(*serial_end != '\0' || errno == ERANGE)
|
||||
{
|
||||
ERR("Unexpected object serial: %s\n", serial_str);
|
||||
ERR("Unexpected object serial: {}", serial_str);
|
||||
serial_id = info->id;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string name;
|
||||
if(nodeName && *nodeName) name = nodeName;
|
||||
else name = "PipeWire node #"+std::to_string(info->id);
|
||||
auto name = std::invoke([nodeName,info]() -> std::string
|
||||
{
|
||||
if(nodeName && *nodeName)
|
||||
return std::string{nodeName};
|
||||
return fmt::format("PipeWire node #{}", info->id);
|
||||
});
|
||||
|
||||
const char *form_factor{spa_dict_lookup(info->props, PW_KEY_DEVICE_FORM_FACTOR)};
|
||||
TRACE("Got %s device \"%s\"%s%s%s\n", AsString(ntype), devName ? devName : "(nil)",
|
||||
TRACE("Got {} device \"{}\"{}{}{}", AsString(ntype), devName ? devName : "(nil)",
|
||||
form_factor?" (":"", form_factor?form_factor:"", form_factor?")":"");
|
||||
TRACE(" \"%s\" = ID %" PRIu64 "\n", name.c_str(), serial_id);
|
||||
TRACE(" \"{}\" = ID {}", name, serial_id);
|
||||
|
||||
DeviceNode &node = DeviceNode::Add(info->id);
|
||||
node.mSerial = serial_id;
|
||||
@@ -1081,8 +1092,9 @@ void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_po
|
||||
DeviceNode *node{DeviceNode::Find(mId)};
|
||||
if(!node) UNLIKELY return;
|
||||
|
||||
TRACE("Device ID %" PRIu64 " %s format:\n", node->mSerial,
|
||||
(id == SPA_PARAM_EnumFormat) ? "enumerable" : "current");
|
||||
TRACE("Device ID {} {} format{}:", node->mSerial,
|
||||
(id == SPA_PARAM_EnumFormat) ? "available" : "current",
|
||||
(id == SPA_PARAM_EnumFormat) ? "s" : "");
|
||||
|
||||
const bool force_update{id == SPA_PARAM_Format};
|
||||
if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_rate)})
|
||||
@@ -1115,14 +1127,14 @@ auto MetadataProxy::propertyCallback(void*, uint32_t id, const char *key, const
|
||||
|
||||
if(!type)
|
||||
{
|
||||
TRACE("Default %s device cleared\n", isCapture ? "capture" : "playback");
|
||||
TRACE("Default {} device cleared", isCapture ? "capture" : "playback");
|
||||
if(!isCapture) DefaultSinkDevice.clear();
|
||||
else DefaultSourceDevice.clear();
|
||||
return 0;
|
||||
}
|
||||
if("Spa:String:JSON"sv != type)
|
||||
{
|
||||
ERR("Unexpected %s property type: %s\n", key, type);
|
||||
ERR("Unexpected {} property type: {}", key, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1153,8 +1165,8 @@ auto MetadataProxy::propertyCallback(void*, uint32_t id, const char *key, const
|
||||
auto propValue = get_json_string(&std::get<1>(it));
|
||||
if(!propValue) break;
|
||||
|
||||
TRACE("Got default %s device \"%s\"\n", isCapture ? "capture" : "playback",
|
||||
propValue->c_str());
|
||||
TRACE("Got default {} device \"{}\"", isCapture ? "capture" : "playback",
|
||||
*propValue);
|
||||
if(!isCapture && DefaultSinkDevice != *propValue)
|
||||
{
|
||||
if(gEventHandler.mInitDone.load(std::memory_order_relaxed))
|
||||
@@ -1196,28 +1208,28 @@ bool EventManager::init()
|
||||
mLoop = ThreadMainloop::Create("PWEventThread");
|
||||
if(!mLoop)
|
||||
{
|
||||
ERR("Failed to create PipeWire event thread loop (errno: %d)\n", errno);
|
||||
ERR("Failed to create PipeWire event thread loop (errno: {})", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mContext = mLoop.newContext();
|
||||
if(!mContext)
|
||||
{
|
||||
ERR("Failed to create PipeWire event context (errno: %d)\n", errno);
|
||||
ERR("Failed to create PipeWire event context (errno: {})", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
|
||||
if(!mCore)
|
||||
{
|
||||
ERR("Failed to connect PipeWire event context (errno: %d)\n", errno);
|
||||
ERR("Failed to connect PipeWire event context (errno: {})", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
mRegistry = PwRegistryPtr{pw_core_get_registry(mCore.get(), PW_VERSION_REGISTRY, 0)};
|
||||
if(!mRegistry)
|
||||
{
|
||||
ERR("Failed to get PipeWire event registry (errno: %d)\n", errno);
|
||||
ERR("Failed to get PipeWire event registry (errno: {})", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1234,7 +1246,7 @@ bool EventManager::init()
|
||||
|
||||
if(int res{mLoop.start()})
|
||||
{
|
||||
ERR("Failed to start PipeWire event thread loop (res: %d)\n", res);
|
||||
ERR("Failed to start PipeWire event thread loop (res: {})", res);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1272,7 +1284,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t
|
||||
if(!isGood)
|
||||
{
|
||||
if(!al::contains(className, "/Video"sv) && !al::starts_with(className, "Stream/"sv))
|
||||
TRACE("Ignoring node class %s\n", media_class);
|
||||
TRACE("Ignoring node class {}", media_class);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1281,7 +1293,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t
|
||||
version, 0))};
|
||||
if(!node)
|
||||
{
|
||||
ERR("Failed to create node proxy object (errno: %d)\n", errno);
|
||||
ERR("Failed to create node proxy object (errno: {})", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1304,13 +1316,13 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t
|
||||
|
||||
if("default"sv != data_class)
|
||||
{
|
||||
TRACE("Ignoring metadata \"%s\"\n", data_class);
|
||||
TRACE("Ignoring metadata \"{}\"", data_class);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mDefaultMetadata)
|
||||
{
|
||||
ERR("Duplicate default metadata\n");
|
||||
ERR("Duplicate default metadata");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1318,7 +1330,7 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t
|
||||
type, version, 0))};
|
||||
if(!mdata)
|
||||
{
|
||||
ERR("Failed to create metadata proxy object (errno: %d)\n", errno);
|
||||
ERR("Failed to create metadata proxy object (errno: {})", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1375,7 +1387,7 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u
|
||||
case DevFmtFloat: info.format = SPA_AUDIO_FORMAT_F32; break;
|
||||
}
|
||||
|
||||
info.rate = device->Frequency;
|
||||
info.rate = device->mSampleRate;
|
||||
|
||||
al::span<const spa_audio_channel> map{};
|
||||
switch(device->FmtChans)
|
||||
@@ -1391,6 +1403,7 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u
|
||||
case DevFmtX71: map = X71Map; break;
|
||||
case DevFmtX714: map = X714Map; break;
|
||||
case DevFmtX3D71: map = X71Map; break;
|
||||
case DevFmtX7144:
|
||||
case DevFmtAmbi3D:
|
||||
info.flags |= SPA_AUDIO_FLAG_UNPOSITIONED;
|
||||
info.channels = device->channelsFromFmt();
|
||||
@@ -1424,7 +1437,7 @@ class PipeWirePlayback final : public BackendBase {
|
||||
PwStreamPtr mStream;
|
||||
spa_hook mStreamListener{};
|
||||
spa_io_rate_match *mRateMatch{};
|
||||
std::vector<float*> mChannelPtrs;
|
||||
std::vector<void*> mChannelPtrs;
|
||||
|
||||
static constexpr pw_stream_events CreateEvents()
|
||||
{
|
||||
@@ -1440,7 +1453,7 @@ class PipeWirePlayback final : public BackendBase {
|
||||
}
|
||||
|
||||
public:
|
||||
PipeWirePlayback(DeviceBase *device) noexcept : BackendBase{device} { }
|
||||
explicit PipeWirePlayback(DeviceBase *device) noexcept : BackendBase{device} { }
|
||||
~PipeWirePlayback() final
|
||||
{
|
||||
/* Stop the mainloop so the stream can be properly destroyed. */
|
||||
@@ -1484,7 +1497,7 @@ void PipeWirePlayback::outputCallback() noexcept
|
||||
uint length{mRateMatch ? mRateMatch->size : 0u};
|
||||
#endif
|
||||
/* If no length is specified, use the device's update size as a fallback. */
|
||||
if(!length) UNLIKELY length = mDevice->UpdateSize;
|
||||
if(!length) UNLIKELY length = mDevice->mUpdateSize;
|
||||
|
||||
/* For planar formats, each datas[] seems to contain one channel, so store
|
||||
* the pointers in an array. Limit the render length in case the available
|
||||
@@ -1495,7 +1508,7 @@ void PipeWirePlayback::outputCallback() noexcept
|
||||
for(const auto &data : datas)
|
||||
{
|
||||
length = std::min(length, data.maxsize/uint{sizeof(float)});
|
||||
*chanptr_end = static_cast<float*>(data.data);
|
||||
*chanptr_end = data.data;
|
||||
++chanptr_end;
|
||||
|
||||
data.chunk->offset = 0;
|
||||
@@ -1552,7 +1565,7 @@ void PipeWirePlayback::open(std::string_view name)
|
||||
auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name);
|
||||
if(match == devlist.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
|
||||
"Device name \"{}\" not found", name};
|
||||
|
||||
targetid = match->mSerial;
|
||||
devname = match->mName;
|
||||
@@ -1560,15 +1573,15 @@ void PipeWirePlayback::open(std::string_view name)
|
||||
|
||||
if(!mLoop)
|
||||
{
|
||||
const uint count{OpenCount.fetch_add(1, std::memory_order_relaxed)};
|
||||
const std::string thread_name{"ALSoftP" + std::to_string(count)};
|
||||
const auto count = OpenCount.fetch_add(1u, std::memory_order_relaxed);
|
||||
const auto thread_name = fmt::format("ALSoftP{}", count);
|
||||
mLoop = ThreadMainloop::Create(thread_name.c_str());
|
||||
if(!mLoop)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire mainloop (errno: %d)", errno};
|
||||
"Failed to create PipeWire mainloop (errno: {})", errno};
|
||||
if(int res{mLoop.start()})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to start PipeWire mainloop (res: %d)", res};
|
||||
"Failed to start PipeWire mainloop (res: {})", res};
|
||||
}
|
||||
MainloopUniqueLock mlock{mLoop};
|
||||
if(!mContext)
|
||||
@@ -1577,14 +1590,14 @@ void PipeWirePlayback::open(std::string_view name)
|
||||
mContext = mLoop.newContext(cprops);
|
||||
if(!mContext)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire event context (errno: %d)\n", errno};
|
||||
"Failed to create PipeWire event context (errno: {})\n", errno};
|
||||
}
|
||||
if(!mCore)
|
||||
{
|
||||
mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
|
||||
if(!mCore)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to connect PipeWire event context (errno: %d)\n", errno};
|
||||
"Failed to connect PipeWire event context (errno: {})\n", errno};
|
||||
}
|
||||
mlock.unlock();
|
||||
|
||||
@@ -1592,9 +1605,9 @@ void PipeWirePlayback::open(std::string_view name)
|
||||
|
||||
mTargetId = targetid;
|
||||
if(!devname.empty())
|
||||
mDevice->DeviceName = std::move(devname);
|
||||
mDeviceName = std::move(devname);
|
||||
else
|
||||
mDevice->DeviceName = "PipeWire Output"sv;
|
||||
mDeviceName = "PipeWire Output"sv;
|
||||
}
|
||||
|
||||
bool PipeWirePlayback::reset()
|
||||
@@ -1626,13 +1639,13 @@ bool PipeWirePlayback::reset()
|
||||
if(!mDevice->Flags.test(FrequencyRequest) && match->mSampleRate > 0)
|
||||
{
|
||||
/* Scale the update size if the sample rate changes. */
|
||||
const double scale{static_cast<double>(match->mSampleRate) / mDevice->Frequency};
|
||||
const double updatesize{std::round(mDevice->UpdateSize * scale)};
|
||||
const double buffersize{std::round(mDevice->BufferSize * scale)};
|
||||
const double scale{static_cast<double>(match->mSampleRate) / mDevice->mSampleRate};
|
||||
const double updatesize{std::round(mDevice->mUpdateSize * scale)};
|
||||
const double buffersize{std::round(mDevice->mBufferSize * scale)};
|
||||
|
||||
mDevice->Frequency = match->mSampleRate;
|
||||
mDevice->UpdateSize = static_cast<uint>(std::clamp(updatesize, 64.0, 8192.0));
|
||||
mDevice->BufferSize = static_cast<uint>(std::max(buffersize, 128.0));
|
||||
mDevice->mSampleRate = match->mSampleRate;
|
||||
mDevice->mUpdateSize = static_cast<uint>(std::clamp(updatesize, 64.0, 8192.0));
|
||||
mDevice->mBufferSize = static_cast<uint>(std::max(buffersize, 128.0));
|
||||
}
|
||||
if(!mDevice->Flags.test(ChannelsRequest) && match->mChannels != InvalidChannelConfig)
|
||||
mDevice->FmtChans = match->mChannels;
|
||||
@@ -1644,12 +1657,10 @@ bool PipeWirePlayback::reset()
|
||||
/* Force planar 32-bit float output for playback. This is what PipeWire
|
||||
* handles internally, and it's easier for us too.
|
||||
*/
|
||||
spa_audio_info_raw info{make_spa_info(mDevice, is51rear, ForceF32Planar)};
|
||||
auto info = spa_audio_info_raw{make_spa_info(mDevice, is51rear, ForceF32Planar)};
|
||||
|
||||
static constexpr uint32_t pod_buffer_size{1024};
|
||||
PodDynamicBuilder b(pod_buffer_size);
|
||||
|
||||
const spa_pod *params{spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info)};
|
||||
auto b = PodDynamicBuilder{};
|
||||
auto params = as_const_ptr(spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info));
|
||||
if(!params)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to set PipeWire audio format parameters"};
|
||||
@@ -1658,7 +1669,7 @@ bool PipeWirePlayback::reset()
|
||||
* be useful?
|
||||
*/
|
||||
auto&& binary = GetProcBinary();
|
||||
const char *appname{binary.fname.length() ? binary.fname.c_str() : "OpenAL Soft"};
|
||||
const char *appname{!binary.fname.empty() ? binary.fname.c_str() : "OpenAL Soft"};
|
||||
pw_properties *props{pw_properties_new(PW_KEY_NODE_NAME, appname,
|
||||
PW_KEY_NODE_DESCRIPTION, appname,
|
||||
PW_KEY_MEDIA_TYPE, "Audio",
|
||||
@@ -1668,11 +1679,11 @@ bool PipeWirePlayback::reset()
|
||||
nullptr)};
|
||||
if(!props)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire stream properties (errno: %d)", errno};
|
||||
"Failed to create PipeWire stream properties (errno: {})", errno};
|
||||
|
||||
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", mDevice->UpdateSize,
|
||||
mDevice->Frequency);
|
||||
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->Frequency);
|
||||
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", mDevice->mUpdateSize,
|
||||
mDevice->mSampleRate);
|
||||
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->mSampleRate);
|
||||
#ifdef PW_KEY_TARGET_OBJECT
|
||||
pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, mTargetId);
|
||||
#else
|
||||
@@ -1684,17 +1695,17 @@ bool PipeWirePlayback::reset()
|
||||
mStream = PwStreamPtr{pw_stream_new(mCore.get(), "Playback Stream", props)};
|
||||
if(!mStream)
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Failed to create PipeWire stream (errno: %d)", errno};
|
||||
"Failed to create PipeWire stream (errno: {})", errno};
|
||||
static constexpr pw_stream_events streamEvents{CreateEvents()};
|
||||
pw_stream_add_listener(mStream.get(), &mStreamListener, &streamEvents, this);
|
||||
|
||||
pw_stream_flags flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
|
||||
| PW_STREAM_FLAG_MAP_BUFFERS};
|
||||
if(GetConfigValueBool(mDevice->DeviceName, "pipewire", "rt-mix", false))
|
||||
if(GetConfigValueBool(mDevice->mDeviceName, "pipewire", "rt-mix", false))
|
||||
flags |= PW_STREAM_FLAG_RT_PROCESS;
|
||||
if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_OUTPUT, PwIdAny, flags, ¶ms, 1)})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Error connecting PipeWire stream (res: %d)", res};
|
||||
"Error connecting PipeWire stream (res: {})", res};
|
||||
|
||||
/* Wait for the stream to become paused (ready to start streaming). */
|
||||
plock.wait([stream=mStream.get()]()
|
||||
@@ -1703,12 +1714,12 @@ bool PipeWirePlayback::reset()
|
||||
pw_stream_state state{pw_stream_get_state(stream, &error)};
|
||||
if(state == PW_STREAM_STATE_ERROR)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Error connecting PipeWire stream: \"%s\"", error};
|
||||
"Error connecting PipeWire stream: \"{}\"", error};
|
||||
return state == PW_STREAM_STATE_PAUSED;
|
||||
});
|
||||
|
||||
/* TODO: Update mDevice->UpdateSize with the stream's quantum, and
|
||||
* mDevice->BufferSize with the total known buffering delay from the head
|
||||
/* TODO: Update mDevice->mUpdateSize with the stream's quantum, and
|
||||
* mDevice->mBufferSize with the total known buffering delay from the head
|
||||
* of this playback stream to the tail of the device output.
|
||||
*
|
||||
* This info is apparently not available until after the stream starts.
|
||||
@@ -1727,7 +1738,7 @@ void PipeWirePlayback::start()
|
||||
MainloopUniqueLock plock{mLoop};
|
||||
if(int res{pw_stream_set_active(mStream.get(), true)})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to start PipeWire stream (res: %d)", res};
|
||||
"Failed to start PipeWire stream (res: {})", res};
|
||||
|
||||
/* Wait for the stream to start playing (would be nice to not, but we need
|
||||
* the actual update size which is only available after starting).
|
||||
@@ -1738,7 +1749,7 @@ void PipeWirePlayback::start()
|
||||
pw_stream_state state{pw_stream_get_state(stream, &error)};
|
||||
if(state == PW_STREAM_STATE_ERROR)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"PipeWire stream error: %s", error ? error : "(unknown)"};
|
||||
"PipeWire stream error: {}", error ? error : "(unknown)"};
|
||||
return state == PW_STREAM_STATE_STREAMING;
|
||||
});
|
||||
|
||||
@@ -1753,7 +1764,7 @@ void PipeWirePlayback::start()
|
||||
pw_time ptime{};
|
||||
if(int res{pw_stream_get_time_n(mStream.get(), &ptime, sizeof(ptime))})
|
||||
{
|
||||
ERR("Failed to get PipeWire stream time (res: %d)\n", res);
|
||||
ERR("Failed to get PipeWire stream time (res: {})", res);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1768,11 +1779,11 @@ void PipeWirePlayback::start()
|
||||
const uint totalbuffers{ptime.avail_buffers + ptime.queued_buffers};
|
||||
|
||||
/* Ensure the delay is in sample frames. */
|
||||
const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->Frequency *
|
||||
const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->mSampleRate *
|
||||
ptime.rate.num / ptime.rate.denom};
|
||||
|
||||
mDevice->UpdateSize = updatesize;
|
||||
mDevice->BufferSize = static_cast<uint>(ptime.buffered + delay +
|
||||
mDevice->mUpdateSize = updatesize;
|
||||
mDevice->mBufferSize = static_cast<uint>(ptime.buffered + delay +
|
||||
uint64_t{totalbuffers}*updatesize);
|
||||
break;
|
||||
}
|
||||
@@ -1783,17 +1794,17 @@ void PipeWirePlayback::start()
|
||||
if(ptime.rate.denom > 0 && updatesize > 0)
|
||||
{
|
||||
/* Ensure the delay is in sample frames. */
|
||||
const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->Frequency *
|
||||
const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->mSampleRate *
|
||||
ptime.rate.num / ptime.rate.denom};
|
||||
|
||||
mDevice->UpdateSize = updatesize;
|
||||
mDevice->BufferSize = static_cast<uint>(delay + updatesize);
|
||||
mDevice->mUpdateSize = updatesize;
|
||||
mDevice->mBufferSize = static_cast<uint>(delay + updatesize);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if(!--wait_count)
|
||||
{
|
||||
ERR("Timeout getting PipeWire stream buffering info\n");
|
||||
ERR("Timeout getting PipeWire stream buffering info");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1807,7 +1818,7 @@ void PipeWirePlayback::stop()
|
||||
{
|
||||
MainloopUniqueLock plock{mLoop};
|
||||
if(int res{pw_stream_set_active(mStream.get(), false)})
|
||||
ERR("Failed to stop PipeWire stream (res: %d)\n", res);
|
||||
ERR("Failed to stop PipeWire stream (res: {})", res);
|
||||
|
||||
/* Wait for the stream to stop playing. */
|
||||
plock.wait([stream=mStream.get()]()
|
||||
@@ -1828,7 +1839,7 @@ ClockLatency PipeWirePlayback::getClockLatency()
|
||||
{
|
||||
MainloopLockGuard looplock{mLoop};
|
||||
if(int res{pw_stream_get_time_n(mStream.get(), &ptime, sizeof(ptime))})
|
||||
ERR("Failed to get PipeWire stream time (res: %d)\n", res);
|
||||
ERR("Failed to get PipeWire stream time (res: {})", res);
|
||||
}
|
||||
|
||||
/* Now get the mixer time and the CLOCK_MONOTONIC time atomically (i.e. the
|
||||
@@ -1856,7 +1867,7 @@ ClockLatency PipeWirePlayback::getClockLatency()
|
||||
*/
|
||||
ptime.now = monoclock.count();
|
||||
curtic = mixtime;
|
||||
delay = nanoseconds{seconds{mDevice->BufferSize}} / mDevice->Frequency;
|
||||
delay = nanoseconds{seconds{mDevice->mBufferSize}} / mDevice->mSampleRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1916,7 +1927,7 @@ class PipeWireCapture final : public BackendBase {
|
||||
PwStreamPtr mStream;
|
||||
spa_hook mStreamListener{};
|
||||
|
||||
RingBufferPtr mRing{};
|
||||
RingBufferPtr mRing;
|
||||
|
||||
static constexpr pw_stream_events CreateEvents()
|
||||
{
|
||||
@@ -1930,7 +1941,7 @@ class PipeWireCapture final : public BackendBase {
|
||||
}
|
||||
|
||||
public:
|
||||
PipeWireCapture(DeviceBase *device) noexcept : BackendBase{device} { }
|
||||
explicit PipeWireCapture(DeviceBase *device) noexcept : BackendBase{device} { }
|
||||
~PipeWireCapture() final { if(mLoop) mLoop.stop(); }
|
||||
};
|
||||
|
||||
@@ -2017,7 +2028,7 @@ void PipeWireCapture::open(std::string_view name)
|
||||
}
|
||||
if(match == devlist.cend())
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Device name \"%.*s\" not found", al::sizei(name), name.data()};
|
||||
"Device name \"{}\" not found", name};
|
||||
|
||||
targetid = match->mSerial;
|
||||
if(match->mType != NodeType::Sink) devname = match->mName;
|
||||
@@ -2026,15 +2037,15 @@ void PipeWireCapture::open(std::string_view name)
|
||||
|
||||
if(!mLoop)
|
||||
{
|
||||
const uint count{OpenCount.fetch_add(1, std::memory_order_relaxed)};
|
||||
const std::string thread_name{"ALSoftC" + std::to_string(count)};
|
||||
const auto count = OpenCount.fetch_add(1u, std::memory_order_relaxed);
|
||||
const auto thread_name = fmt::format("ALSoftC{}", count);
|
||||
mLoop = ThreadMainloop::Create(thread_name.c_str());
|
||||
if(!mLoop)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire mainloop (errno: %d)", errno};
|
||||
"Failed to create PipeWire mainloop (errno: {})", errno};
|
||||
if(int res{mLoop.start()})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to start PipeWire mainloop (res: %d)", res};
|
||||
"Failed to start PipeWire mainloop (res: {})", res};
|
||||
}
|
||||
MainloopUniqueLock mlock{mLoop};
|
||||
if(!mContext)
|
||||
@@ -2043,14 +2054,14 @@ void PipeWireCapture::open(std::string_view name)
|
||||
mContext = mLoop.newContext(cprops);
|
||||
if(!mContext)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire event context (errno: %d)\n", errno};
|
||||
"Failed to create PipeWire event context (errno: {})\n", errno};
|
||||
}
|
||||
if(!mCore)
|
||||
{
|
||||
mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
|
||||
if(!mCore)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to connect PipeWire event context (errno: %d)\n", errno};
|
||||
"Failed to connect PipeWire event context (errno: {})\n", errno};
|
||||
}
|
||||
mlock.unlock();
|
||||
|
||||
@@ -2058,9 +2069,9 @@ void PipeWireCapture::open(std::string_view name)
|
||||
|
||||
mTargetId = targetid;
|
||||
if(!devname.empty())
|
||||
mDevice->DeviceName = std::move(devname);
|
||||
mDeviceName = std::move(devname);
|
||||
else
|
||||
mDevice->DeviceName = "PipeWire Input"sv;
|
||||
mDeviceName = "PipeWire Input"sv;
|
||||
|
||||
|
||||
bool is51rear{false};
|
||||
@@ -2075,19 +2086,16 @@ void PipeWireCapture::open(std::string_view name)
|
||||
if(match != devlist.cend())
|
||||
is51rear = match->mIs51Rear;
|
||||
}
|
||||
spa_audio_info_raw info{make_spa_info(mDevice, is51rear, UseDevType)};
|
||||
auto info = spa_audio_info_raw{make_spa_info(mDevice, is51rear, UseDevType)};
|
||||
|
||||
static constexpr uint32_t pod_buffer_size{1024};
|
||||
PodDynamicBuilder b(pod_buffer_size);
|
||||
|
||||
std::array params{static_cast<const spa_pod*>(spa_format_audio_raw_build(b.get(),
|
||||
SPA_PARAM_EnumFormat, &info))};
|
||||
if(!params[0])
|
||||
auto b = PodDynamicBuilder{};
|
||||
auto params = as_const_ptr(spa_format_audio_raw_build(b.get(), SPA_PARAM_EnumFormat, &info));
|
||||
if(!params)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to set PipeWire audio format parameters"};
|
||||
|
||||
auto&& binary = GetProcBinary();
|
||||
const char *appname{binary.fname.length() ? binary.fname.c_str() : "OpenAL Soft"};
|
||||
const char *appname{!binary.fname.empty() ? binary.fname.c_str() : "OpenAL Soft"};
|
||||
pw_properties *props{pw_properties_new(
|
||||
PW_KEY_NODE_NAME, appname,
|
||||
PW_KEY_NODE_DESCRIPTION, appname,
|
||||
@@ -2098,15 +2106,15 @@ void PipeWireCapture::open(std::string_view name)
|
||||
nullptr)};
|
||||
if(!props)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to create PipeWire stream properties (errno: %d)", errno};
|
||||
"Failed to create PipeWire stream properties (errno: {})", errno};
|
||||
|
||||
/* We don't actually care what the latency/update size is, as long as it's
|
||||
* reasonable. Unfortunately, when unspecified PipeWire seems to default to
|
||||
* around 40ms, which isn't great. So request 20ms instead.
|
||||
*/
|
||||
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", (mDevice->Frequency+25) / 50,
|
||||
mDevice->Frequency);
|
||||
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->Frequency);
|
||||
pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", (mDevice->mSampleRate+25) / 50,
|
||||
mDevice->mSampleRate);
|
||||
pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->mSampleRate);
|
||||
#ifdef PW_KEY_TARGET_OBJECT
|
||||
pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, mTargetId);
|
||||
#else
|
||||
@@ -2117,15 +2125,15 @@ void PipeWireCapture::open(std::string_view name)
|
||||
mStream = PwStreamPtr{pw_stream_new(mCore.get(), "Capture Stream", props)};
|
||||
if(!mStream)
|
||||
throw al::backend_exception{al::backend_error::NoDevice,
|
||||
"Failed to create PipeWire stream (errno: %d)", errno};
|
||||
"Failed to create PipeWire stream (errno: {})", errno};
|
||||
static constexpr pw_stream_events streamEvents{CreateEvents()};
|
||||
pw_stream_add_listener(mStream.get(), &mStreamListener, &streamEvents, this);
|
||||
|
||||
constexpr pw_stream_flags Flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
|
||||
| PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS};
|
||||
if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params.data(), 1)})
|
||||
if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, ¶ms, 1)})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Error connecting PipeWire stream (res: %d)", res};
|
||||
"Error connecting PipeWire stream (res: {})", res};
|
||||
|
||||
/* Wait for the stream to become paused (ready to start streaming). */
|
||||
plock.wait([stream=mStream.get()]()
|
||||
@@ -2134,7 +2142,7 @@ void PipeWireCapture::open(std::string_view name)
|
||||
pw_stream_state state{pw_stream_get_state(stream, &error)};
|
||||
if(state == PW_STREAM_STATE_ERROR)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Error connecting PipeWire stream: \"%s\"", error};
|
||||
"Error connecting PipeWire stream: \"{}\"", error};
|
||||
return state == PW_STREAM_STATE_PAUSED;
|
||||
});
|
||||
plock.unlock();
|
||||
@@ -2142,7 +2150,7 @@ void PipeWireCapture::open(std::string_view name)
|
||||
setDefaultWFXChannelOrder();
|
||||
|
||||
/* Ensure at least a 100ms capture buffer. */
|
||||
mRing = RingBuffer::Create(std::max(mDevice->Frequency/10u, mDevice->BufferSize),
|
||||
mRing = RingBuffer::Create(std::max(mDevice->mSampleRate/10u, mDevice->mBufferSize),
|
||||
mDevice->frameSizeFromFmt(), false);
|
||||
}
|
||||
|
||||
@@ -2152,7 +2160,7 @@ void PipeWireCapture::start()
|
||||
MainloopUniqueLock plock{mLoop};
|
||||
if(int res{pw_stream_set_active(mStream.get(), true)})
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"Failed to start PipeWire stream (res: %d)", res};
|
||||
"Failed to start PipeWire stream (res: {})", res};
|
||||
|
||||
plock.wait([stream=mStream.get()]()
|
||||
{
|
||||
@@ -2160,7 +2168,7 @@ void PipeWireCapture::start()
|
||||
pw_stream_state state{pw_stream_get_state(stream, &error)};
|
||||
if(state == PW_STREAM_STATE_ERROR)
|
||||
throw al::backend_exception{al::backend_error::DeviceError,
|
||||
"PipeWire stream error: %s", error ? error : "(unknown)"};
|
||||
"PipeWire stream error: {}", error ? error : "(unknown)"};
|
||||
return state == PW_STREAM_STATE_STREAMING;
|
||||
});
|
||||
}
|
||||
@@ -2169,7 +2177,7 @@ void PipeWireCapture::stop()
|
||||
{
|
||||
MainloopUniqueLock plock{mLoop};
|
||||
if(int res{pw_stream_set_active(mStream.get(), false)})
|
||||
ERR("Failed to stop PipeWire stream (res: %d)\n", res);
|
||||
ERR("Failed to stop PipeWire stream (res: {})", res);
|
||||
|
||||
plock.wait([stream=mStream.get()]()
|
||||
{ return pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING; });
|
||||
@@ -2192,11 +2200,11 @@ bool PipeWireBackendFactory::init()
|
||||
const char *version{pw_get_library_version()};
|
||||
if(!check_version(version))
|
||||
{
|
||||
WARN("PipeWire version \"%s\" too old (%s or newer required)\n", version,
|
||||
WARN("PipeWire version \"{}\" too old ({} or newer required)", version,
|
||||
pw_get_headers_version());
|
||||
return false;
|
||||
}
|
||||
TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version());
|
||||
TRACE("Found PipeWire version \"{}\" ({} or newer)", version, pw_get_headers_version());
|
||||
|
||||
pw_init(nullptr, nullptr);
|
||||
if(!gEventHandler.init())
|
||||
@@ -2209,7 +2217,7 @@ bool PipeWireBackendFactory::init()
|
||||
/* TODO: Temporary warning, until PipeWire gets a proper way to report
|
||||
* audio support.
|
||||
*/
|
||||
WARN("No audio support detected in PipeWire. See the PipeWire options in alsoftrc.sample if this is wrong.\n");
|
||||
WARN("No audio support detected in PipeWire. See the PipeWire options in alsoftrc.sample if this is wrong.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -2218,9 +2226,9 @@ bool PipeWireBackendFactory::init()
|
||||
bool PipeWireBackendFactory::querySupport(BackendType type)
|
||||
{ return type == BackendType::Playback || type == BackendType::Capture; }
|
||||
|
||||
std::string PipeWireBackendFactory::probe(BackendType type)
|
||||
auto PipeWireBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
|
||||
{
|
||||
std::string outnames;
|
||||
std::vector<std::string> outnames;
|
||||
|
||||
gEventHandler.waitForInit();
|
||||
EventWatcherLockGuard evtlock{gEventHandler};
|
||||
@@ -2241,31 +2249,31 @@ std::string PipeWireBackendFactory::probe(BackendType type)
|
||||
case BackendType::Playback:
|
||||
defmatch = std::find_if(defmatch, devlist.cend(), match_defsink);
|
||||
if(defmatch != devlist.cend())
|
||||
{
|
||||
/* Includes null char. */
|
||||
outnames.append(defmatch->mName.c_str(), defmatch->mName.length()+1);
|
||||
}
|
||||
outnames.emplace_back(defmatch->mName);
|
||||
for(auto iter = devlist.cbegin();iter != devlist.cend();++iter)
|
||||
{
|
||||
if(iter != defmatch && iter->mType != NodeType::Source)
|
||||
outnames.append(iter->mName.c_str(), iter->mName.length()+1);
|
||||
outnames.emplace_back(iter->mName);
|
||||
}
|
||||
break;
|
||||
case BackendType::Capture:
|
||||
outnames.reserve(devlist.size());
|
||||
defmatch = std::find_if(defmatch, devlist.cend(), match_defsource);
|
||||
if(defmatch != devlist.cend())
|
||||
{
|
||||
if(defmatch->mType == NodeType::Sink)
|
||||
outnames.append(GetMonitorPrefix());
|
||||
outnames.append(defmatch->mName.c_str(), defmatch->mName.length()+1);
|
||||
outnames.emplace_back(std::string{GetMonitorPrefix()}+defmatch->mName);
|
||||
else
|
||||
outnames.emplace_back(defmatch->mName);
|
||||
}
|
||||
for(auto iter = devlist.cbegin();iter != devlist.cend();++iter)
|
||||
{
|
||||
if(iter != defmatch)
|
||||
{
|
||||
if(iter->mType == NodeType::Sink)
|
||||
outnames.append(GetMonitorPrefix());
|
||||
outnames.append(iter->mName.c_str(), iter->mName.length()+1);
|
||||
outnames.emplace_back(std::string{GetMonitorPrefix()}+iter->mName);
|
||||
else
|
||||
outnames.emplace_back(iter->mName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2274,6 +2282,7 @@ std::string PipeWireBackendFactory::probe(BackendType type)
|
||||
return outnames;
|
||||
}
|
||||
|
||||
|
||||
BackendPtr PipeWireBackendFactory::createBackend(DeviceBase *device, BackendType type)
|
||||
{
|
||||
if(type == BackendType::Playback)
|
||||
|
||||
Reference in New Issue
Block a user