aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2021-12-25 19:34:12 -0800
committerChris Robinson <[email protected]>2021-12-25 19:34:12 -0800
commit305201252e0a6818192e6e226bfe7ba57f137eb8 (patch)
treef49b3a70d8f119b505a76f71041b141bcdeaa9ea
parent6bb9912513284ce5b6d6fbc7eb33b9bf38a647e8 (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.cpp67
-rw-r--r--alsoftrc.sample15
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]