aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/pipewire.cpp
diff options
context:
space:
mode:
authorChris Robinson <chris.kcat@gmail.com>2021-12-25 19:34:12 -0800
committerChris Robinson <chris.kcat@gmail.com>2021-12-25 19:34:12 -0800
commit305201252e0a6818192e6e226bfe7ba57f137eb8 (patch)
treef49b3a70d8f119b505a76f71041b141bcdeaa9ea /alc/backends/pipewire.cpp
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.
Diffstat (limited to 'alc/backends/pipewire.cpp')
-rw-r--r--alc/backends/pipewire.cpp67
1 files changed, 64 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)