aboutsummaryrefslogtreecommitdiffstats
path: root/alc/backends/pipewire.cpp
diff options
context:
space:
mode:
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)