diff options
author | Chris Robinson <[email protected]> | 2021-12-25 19:34:12 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2021-12-25 19:34:12 -0800 |
commit | 305201252e0a6818192e6e226bfe7ba57f137eb8 (patch) | |
tree | f49b3a70d8f119b505a76f71041b141bcdeaa9ea | |
parent | 6bb9912513284ce5b6d6fbc7eb33b9bf38a647e8 (diff) |
Check for audio devices when initializing PipeWire
This isn't great since it can fail when PipeWire is handling audio but no
devices are available at initialization, causing the Pulseaudio or ALSA backend
to be selected instead. Future versions of PipeWire are expected to have a
better way to detect if it's handling audio, but for now this is better than
nothing.
A config option is available for users to have the PipeWire backend be usable
even with no devices at initialization, just in case.
-rw-r--r-- | alc/backends/pipewire.cpp | 67 | ||||
-rw-r--r-- | alsoftrc.sample | 15 |
2 files changed, 79 insertions, 3 deletions
diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index 68532cd7..ba972141 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -35,6 +35,7 @@ #include <utility> #include "albyte.h" +#include "alc/alconfig.h" #include "almalloc.h" #include "alnumeric.h" #include "aloptional.h" @@ -319,11 +320,14 @@ struct EventManager { * corresponding to it is reached, mInitDone will be set to true. */ std::atomic<bool> mInitDone{false}; + std::atomic<bool> mHasAudio{false}; int mInitSeq{}; bool init(); ~EventManager(); + void kill(); + auto lock() const { return mLoop.lock(); } auto unlock() const { return mLoop.unlock(); } @@ -337,6 +341,23 @@ struct EventManager { mLoop.wait(); } + /** + * Waits for audio support to be detected, or initialization to finish, + * whichever is first. Returns true if audio support was detected. The + * event manager must *NOT* be locked when calling this. + */ + bool waitForAudio() + { + MainloopLockGuard _{mLoop}; + bool has_audio{mHasAudio.load(std::memory_order_acquire)}; + while(unlikely(!has_audio && !mInitDone.load(std::memory_order_acquire))) + { + mLoop.wait(); + has_audio = mHasAudio.load(std::memory_order_acquire); + } + return has_audio; + } + void syncInit() { /* If initialization isn't done, update the sequence ID so it won't @@ -889,6 +910,30 @@ EventManager::~EventManager() if(mContext) pw_context_destroy(mContext); } +void EventManager::kill() +{ + if(mLoop) mLoop.stop(); + + for(NodeProxy *node : mProxyList) + al::destroy_at(node); + mProxyList.clear(); + if(mDefaultMetadata) + al::destroy_at(mDefaultMetadata); + mDefaultMetadata = nullptr; + + if(mRegistry) + pw_proxy_destroy(reinterpret_cast<pw_proxy*>(mRegistry)); + mRegistry = nullptr; + if(mCore) + pw_core_disconnect(mCore); + mCore = nullptr; + if(mContext) + pw_context_destroy(mContext); + mContext = nullptr; + + mLoop = ThreadMainloop{}; +} + void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t version, const spa_dict *props) { @@ -919,6 +964,12 @@ void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t auto *node = static_cast<NodeProxy*>(pw_proxy_get_user_data(proxy)); mProxyList.emplace_back(al::construct_at(node, id, proxy)); syncInit(); + + /* Signal any waiters that we have found a source or sink for audio + * support. + */ + if(!mHasAudio.exchange(true, std::memory_order_acq_rel)) + mLoop.signal(false); } else if(std::strcmp(type, PW_TYPE_INTERFACE_Metadata) == 0) { @@ -1710,10 +1761,20 @@ bool PipeWireBackendFactory::init() return false; pw_init(0, nullptr); + if(!gEventHandler.init()) + return false; - /* TODO: Check that audio devices are supported. */ - - return gEventHandler.init(); + if(!GetConfigValueBool(nullptr, "pipewire", "assume-audio", false) + && !gEventHandler.waitForAudio()) + { + gEventHandler.kill(); + /* 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"); + return false; + } + return true; } bool PipeWireBackendFactory::querySupport(BackendType type) diff --git a/alsoftrc.sample b/alsoftrc.sample index 80bab07c..7b94fa35 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -352,6 +352,21 @@ #boost = 0 ## +## PipeWire backend stuff +## +[pipewire] + +## assume-audio: (global) +# Causes the backend to succeed initialization even if PipeWire reports no +# audio support. Currently, audio support is detected by the presence of audio +# source or sink nodes, although this can cause false negatives in cases where +# device availability during library initialization is spotty. Future versions +# of PipeWire are expected to have a more robust method to test audio support, +# but in the mean time this can be set to true to assume PipeWire has audio +# support even when no nodes may be reported at initialization time. +#assume-audio = false + +## ## PulseAudio backend stuff ## [pulse] |