]> git.tdb.fi Git - ext/openal.git/blob - alc/backends/pipewire.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / alc / backends / pipewire.cpp
1 /**
2  * OpenAL cross platform audio library
3  * Copyright (C) 2010 by Chris Robinson
4  * This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Library General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  *  License along with this library; if not, write to the
16  *  Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * Or go to http://www.gnu.org/copyleft/lgpl.html
19  */
20
21 #include "config.h"
22
23 #include "pipewire.h"
24
25 #include <algorithm>
26 #include <atomic>
27 #include <cstring>
28 #include <cerrno>
29 #include <chrono>
30 #include <ctime>
31 #include <list>
32 #include <memory>
33 #include <mutex>
34 #include <stdint.h>
35 #include <thread>
36 #include <type_traits>
37 #include <utility>
38
39 #include "albyte.h"
40 #include "alc/alconfig.h"
41 #include "almalloc.h"
42 #include "alnumeric.h"
43 #include "aloptional.h"
44 #include "alspan.h"
45 #include "alstring.h"
46 #include "core/devformat.h"
47 #include "core/device.h"
48 #include "core/helpers.h"
49 #include "core/logging.h"
50 #include "dynload.h"
51 #include "opthelpers.h"
52 #include "ringbuffer.h"
53
54 /* Ignore warnings caused by PipeWire headers (lots in standard C++ mode). GCC
55  * doesn't support ignoring -Weverything, so we have the list the individual
56  * warnings to ignore (and ignoring -Winline doesn't seem to work).
57  */
58 _Pragma("GCC diagnostic push")
59 _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
60 _Pragma("GCC diagnostic ignored \"-Wconversion\"")
61 _Pragma("GCC diagnostic ignored \"-Wfloat-conversion\"")
62 _Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
63 _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
64 _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
65 _Pragma("GCC diagnostic ignored \"-Wsign-compare\"")
66 _Pragma("GCC diagnostic ignored \"-Winline\"")
67 _Pragma("GCC diagnostic ignored \"-Wpragmas\"")
68 _Pragma("GCC diagnostic ignored \"-Weverything\"")
69 #include "pipewire/pipewire.h"
70 #include "pipewire/extensions/metadata.h"
71 #include "spa/buffer/buffer.h"
72 #include "spa/param/audio/format-utils.h"
73 #include "spa/param/audio/raw.h"
74 #include "spa/param/param.h"
75 #include "spa/pod/builder.h"
76 #include "spa/utils/json.h"
77
78 namespace {
79 /* Wrap some nasty macros here too... */
80 template<typename ...Args>
81 auto ppw_core_add_listener(pw_core *core, Args&& ...args)
82 { return pw_core_add_listener(core, std::forward<Args>(args)...); }
83 template<typename ...Args>
84 auto ppw_core_sync(pw_core *core, Args&& ...args)
85 { return pw_core_sync(core, std::forward<Args>(args)...); }
86 template<typename ...Args>
87 auto ppw_registry_add_listener(pw_registry *reg, Args&& ...args)
88 { return pw_registry_add_listener(reg, std::forward<Args>(args)...); }
89 template<typename ...Args>
90 auto ppw_node_add_listener(pw_node *node, Args&& ...args)
91 { return pw_node_add_listener(node, std::forward<Args>(args)...); }
92 template<typename ...Args>
93 auto ppw_node_subscribe_params(pw_node *node, Args&& ...args)
94 { return pw_node_subscribe_params(node, std::forward<Args>(args)...); }
95 template<typename ...Args>
96 auto ppw_metadata_add_listener(pw_metadata *mdata, Args&& ...args)
97 { return pw_metadata_add_listener(mdata, std::forward<Args>(args)...); }
98
99
100 constexpr auto get_pod_type(const spa_pod *pod) noexcept
101 { return SPA_POD_TYPE(pod); }
102
103 template<typename T>
104 constexpr auto get_pod_body(const spa_pod *pod, size_t count) noexcept
105 { return al::span<T>{static_cast<T*>(SPA_POD_BODY(pod)), count}; }
106 template<typename T, size_t N>
107 constexpr auto get_pod_body(const spa_pod *pod) noexcept
108 { return al::span<T,N>{static_cast<T*>(SPA_POD_BODY(pod)), N}; }
109
110 constexpr auto make_pod_builder(void *data, uint32_t size) noexcept
111 { return SPA_POD_BUILDER_INIT(data, size); }
112
113 constexpr auto get_array_value_type(const spa_pod *pod) noexcept
114 { return SPA_POD_ARRAY_VALUE_TYPE(pod); }
115
116 constexpr auto PwIdAny = PW_ID_ANY;
117
118 } // namespace
119 _Pragma("GCC diagnostic pop")
120
121 namespace {
122
123 /* Added in 0.3.33, but we currently only require 0.3.23. */
124 #ifndef PW_KEY_NODE_RATE
125 #define PW_KEY_NODE_RATE "node.rate"
126 #endif
127
128 using std::chrono::seconds;
129 using std::chrono::milliseconds;
130 using std::chrono::nanoseconds;
131 using uint = unsigned int;
132
133 constexpr char pwireDevice[] = "PipeWire Output";
134 constexpr char pwireInput[] = "PipeWire Input";
135
136
137 bool check_version(const char *version)
138 {
139     /* There doesn't seem to be a function to get the version as an integer, so
140      * instead we have to parse the string, which hopefully won't break in the
141      * future.
142      */
143     int major{0}, minor{0}, revision{0};
144     int ret{sscanf(version, "%d.%d.%d", &major, &minor, &revision)};
145     if(ret == 3 && (major > PW_MAJOR || (major == PW_MAJOR && minor > PW_MINOR)
146         || (major == PW_MAJOR && minor == PW_MINOR && revision >= PW_MICRO)))
147         return true;
148     return false;
149 }
150
151 #ifdef HAVE_DYNLOAD
152 #define PWIRE_FUNCS(MAGIC)                                                    \
153     MAGIC(pw_context_connect)                                                 \
154     MAGIC(pw_context_destroy)                                                 \
155     MAGIC(pw_context_new)                                                     \
156     MAGIC(pw_core_disconnect)                                                 \
157     MAGIC(pw_get_library_version)                                             \
158     MAGIC(pw_init)                                                            \
159     MAGIC(pw_properties_free)                                                 \
160     MAGIC(pw_properties_new)                                                  \
161     MAGIC(pw_properties_set)                                                  \
162     MAGIC(pw_properties_setf)                                                 \
163     MAGIC(pw_proxy_add_object_listener)                                       \
164     MAGIC(pw_proxy_destroy)                                                   \
165     MAGIC(pw_proxy_get_user_data)                                             \
166     MAGIC(pw_stream_add_listener)                                             \
167     MAGIC(pw_stream_connect)                                                  \
168     MAGIC(pw_stream_dequeue_buffer)                                           \
169     MAGIC(pw_stream_destroy)                                                  \
170     MAGIC(pw_stream_get_state)                                                \
171     MAGIC(pw_stream_new)                                                      \
172     MAGIC(pw_stream_queue_buffer)                                             \
173     MAGIC(pw_stream_set_active)                                               \
174     MAGIC(pw_thread_loop_new)                                                 \
175     MAGIC(pw_thread_loop_destroy)                                             \
176     MAGIC(pw_thread_loop_get_loop)                                            \
177     MAGIC(pw_thread_loop_start)                                               \
178     MAGIC(pw_thread_loop_stop)                                                \
179     MAGIC(pw_thread_loop_lock)                                                \
180     MAGIC(pw_thread_loop_wait)                                                \
181     MAGIC(pw_thread_loop_signal)                                              \
182     MAGIC(pw_thread_loop_unlock)
183 #if PW_CHECK_VERSION(0,3,50)
184 #define PWIRE_FUNCS2(MAGIC)                                                   \
185     MAGIC(pw_stream_get_time_n)
186 #else
187 #define PWIRE_FUNCS2(MAGIC)                                                   \
188     MAGIC(pw_stream_get_time)
189 #endif
190
191 void *pwire_handle;
192 #define MAKE_FUNC(f) decltype(f) * p##f;
193 PWIRE_FUNCS(MAKE_FUNC)
194 PWIRE_FUNCS2(MAKE_FUNC)
195 #undef MAKE_FUNC
196
197 bool pwire_load()
198 {
199     if(pwire_handle)
200         return true;
201
202     static constexpr char pwire_library[] = "libpipewire-0.3.so.0";
203     std::string missing_funcs;
204
205     pwire_handle = LoadLib(pwire_library);
206     if(!pwire_handle)
207     {
208         WARN("Failed to load %s\n", pwire_library);
209         return false;
210     }
211
212 #define LOAD_FUNC(f) do {                                                     \
213     p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(pwire_handle, #f));     \
214     if(p##f == nullptr) missing_funcs += "\n" #f;                             \
215 } while(0);
216     PWIRE_FUNCS(LOAD_FUNC)
217     PWIRE_FUNCS2(LOAD_FUNC)
218 #undef LOAD_FUNC
219
220     if(!missing_funcs.empty())
221     {
222         WARN("Missing expected functions:%s\n", missing_funcs.c_str());
223         CloseLib(pwire_handle);
224         pwire_handle = nullptr;
225         return false;
226     }
227
228     return true;
229 }
230
231 #ifndef IN_IDE_PARSER
232 #define pw_context_connect ppw_context_connect
233 #define pw_context_destroy ppw_context_destroy
234 #define pw_context_new ppw_context_new
235 #define pw_core_disconnect ppw_core_disconnect
236 #define pw_get_library_version ppw_get_library_version
237 #define pw_init ppw_init
238 #define pw_properties_free ppw_properties_free
239 #define pw_properties_new ppw_properties_new
240 #define pw_properties_set ppw_properties_set
241 #define pw_properties_setf ppw_properties_setf
242 #define pw_proxy_add_object_listener ppw_proxy_add_object_listener
243 #define pw_proxy_destroy ppw_proxy_destroy
244 #define pw_proxy_get_user_data ppw_proxy_get_user_data
245 #define pw_stream_add_listener ppw_stream_add_listener
246 #define pw_stream_connect ppw_stream_connect
247 #define pw_stream_dequeue_buffer ppw_stream_dequeue_buffer
248 #define pw_stream_destroy ppw_stream_destroy
249 #define pw_stream_get_state ppw_stream_get_state
250 #define pw_stream_new ppw_stream_new
251 #define pw_stream_queue_buffer ppw_stream_queue_buffer
252 #define pw_stream_set_active ppw_stream_set_active
253 #define pw_thread_loop_destroy ppw_thread_loop_destroy
254 #define pw_thread_loop_get_loop ppw_thread_loop_get_loop
255 #define pw_thread_loop_lock ppw_thread_loop_lock
256 #define pw_thread_loop_new ppw_thread_loop_new
257 #define pw_thread_loop_signal ppw_thread_loop_signal
258 #define pw_thread_loop_start ppw_thread_loop_start
259 #define pw_thread_loop_stop ppw_thread_loop_stop
260 #define pw_thread_loop_unlock ppw_thread_loop_unlock
261 #define pw_thread_loop_wait ppw_thread_loop_wait
262 #if PW_CHECK_VERSION(0,3,50)
263 #define pw_stream_get_time_n ppw_stream_get_time_n
264 #else
265 inline auto pw_stream_get_time_n(pw_stream *stream, pw_time *ptime, size_t /*size*/)
266 { return ppw_stream_get_time(stream, ptime); }
267 #endif
268 #endif
269
270 #else
271
272 constexpr bool pwire_load() { return true; }
273 #endif
274
275 /* Helpers for retrieving values from params */
276 template<uint32_t T> struct PodInfo { };
277
278 template<>
279 struct PodInfo<SPA_TYPE_Int> {
280     using Type = int32_t;
281     static auto get_value(const spa_pod *pod, int32_t *val)
282     { return spa_pod_get_int(pod, val); }
283 };
284 template<>
285 struct PodInfo<SPA_TYPE_Id> {
286     using Type = uint32_t;
287     static auto get_value(const spa_pod *pod, uint32_t *val)
288     { return spa_pod_get_id(pod, val); }
289 };
290
291 template<uint32_t T>
292 using Pod_t = typename PodInfo<T>::Type;
293
294 template<uint32_t T>
295 al::span<const Pod_t<T>> get_array_span(const spa_pod *pod)
296 {
297     uint32_t nvals;
298     if(void *v{spa_pod_get_array(pod, &nvals)})
299     {
300         if(get_array_value_type(pod) == T)
301             return {static_cast<const Pod_t<T>*>(v), nvals};
302     }
303     return {};
304 }
305
306 template<uint32_t T>
307 al::optional<Pod_t<T>> get_value(const spa_pod *value)
308 {
309     Pod_t<T> val{};
310     if(PodInfo<T>::get_value(value, &val) == 0)
311         return val;
312     return al::nullopt;
313 }
314
315 /* Internally, PipeWire types "inherit" from each other, but this is hidden
316  * from the API and the caller is expected to C-style cast to inherited types
317  * as needed. It's also not made very clear what types a given type can be
318  * casted to. To make it a bit safer, this as() method allows casting pw_*
319  * types to known inherited types, generating a compile-time error for
320  * unexpected/invalid casts.
321  */
322 template<typename To, typename From>
323 To as(From) noexcept = delete;
324
325 /* pw_proxy
326  * - pw_registry
327  * - pw_node
328  * - pw_metadata
329  */
330 template<>
331 pw_proxy* as(pw_registry *reg) noexcept { return reinterpret_cast<pw_proxy*>(reg); }
332 template<>
333 pw_proxy* as(pw_node *node) noexcept { return reinterpret_cast<pw_proxy*>(node); }
334 template<>
335 pw_proxy* as(pw_metadata *mdata) noexcept { return reinterpret_cast<pw_proxy*>(mdata); }
336
337
338 struct PwContextDeleter {
339     void operator()(pw_context *context) const { pw_context_destroy(context); }
340 };
341 using PwContextPtr = std::unique_ptr<pw_context,PwContextDeleter>;
342
343 struct PwCoreDeleter {
344     void operator()(pw_core *core) const { pw_core_disconnect(core); }
345 };
346 using PwCorePtr = std::unique_ptr<pw_core,PwCoreDeleter>;
347
348 struct PwRegistryDeleter {
349     void operator()(pw_registry *reg) const { pw_proxy_destroy(as<pw_proxy*>(reg)); }
350 };
351 using PwRegistryPtr = std::unique_ptr<pw_registry,PwRegistryDeleter>;
352
353 struct PwNodeDeleter {
354     void operator()(pw_node *node) const { pw_proxy_destroy(as<pw_proxy*>(node)); }
355 };
356 using PwNodePtr = std::unique_ptr<pw_node,PwNodeDeleter>;
357
358 struct PwMetadataDeleter {
359     void operator()(pw_metadata *mdata) const { pw_proxy_destroy(as<pw_proxy*>(mdata)); }
360 };
361 using PwMetadataPtr = std::unique_ptr<pw_metadata,PwMetadataDeleter>;
362
363 struct PwStreamDeleter {
364     void operator()(pw_stream *stream) const { pw_stream_destroy(stream); }
365 };
366 using PwStreamPtr = std::unique_ptr<pw_stream,PwStreamDeleter>;
367
368 /* Enums for bitflags... again... *sigh* */
369 constexpr pw_stream_flags operator|(pw_stream_flags lhs, pw_stream_flags rhs) noexcept
370 { return static_cast<pw_stream_flags>(lhs | al::to_underlying(rhs)); }
371
372 constexpr pw_stream_flags& operator|=(pw_stream_flags &lhs, pw_stream_flags rhs) noexcept
373 { lhs = lhs | rhs; return lhs; }
374
375 class ThreadMainloop {
376     pw_thread_loop *mLoop{};
377
378 public:
379     ThreadMainloop() = default;
380     ThreadMainloop(const ThreadMainloop&) = delete;
381     ThreadMainloop(ThreadMainloop&& rhs) noexcept : mLoop{rhs.mLoop} { rhs.mLoop = nullptr; }
382     explicit ThreadMainloop(pw_thread_loop *loop) noexcept : mLoop{loop} { }
383     ~ThreadMainloop() { if(mLoop) pw_thread_loop_destroy(mLoop); }
384
385     ThreadMainloop& operator=(const ThreadMainloop&) = delete;
386     ThreadMainloop& operator=(ThreadMainloop&& rhs) noexcept
387     { std::swap(mLoop, rhs.mLoop); return *this; }
388     ThreadMainloop& operator=(std::nullptr_t) noexcept
389     {
390         if(mLoop)
391             pw_thread_loop_destroy(mLoop);
392         mLoop = nullptr;
393         return *this;
394     }
395
396     explicit operator bool() const noexcept { return mLoop != nullptr; }
397
398     auto start() const { return pw_thread_loop_start(mLoop); }
399     auto stop() const { return pw_thread_loop_stop(mLoop); }
400
401     auto getLoop() const { return pw_thread_loop_get_loop(mLoop); }
402
403     auto lock() const { return pw_thread_loop_lock(mLoop); }
404     auto unlock() const { return pw_thread_loop_unlock(mLoop); }
405
406     auto signal(bool wait) const { return pw_thread_loop_signal(mLoop, wait); }
407
408     auto newContext(pw_properties *props=nullptr, size_t user_data_size=0)
409     { return PwContextPtr{pw_context_new(getLoop(), props, user_data_size)}; }
410
411     static auto Create(const char *name, spa_dict *props=nullptr)
412     { return ThreadMainloop{pw_thread_loop_new(name, props)}; }
413
414     friend struct MainloopUniqueLock;
415 };
416 struct MainloopUniqueLock : public std::unique_lock<ThreadMainloop> {
417     using std::unique_lock<ThreadMainloop>::unique_lock;
418     MainloopUniqueLock& operator=(MainloopUniqueLock&&) = default;
419
420     auto wait() const -> void
421     { pw_thread_loop_wait(mutex()->mLoop); }
422
423     template<typename Predicate>
424     auto wait(Predicate done_waiting) const -> void
425     { while(!done_waiting()) wait(); }
426 };
427 using MainloopLockGuard = std::lock_guard<ThreadMainloop>;
428
429
430 /* There's quite a mess here, but the purpose is to track active devices and
431  * their default formats, so playback devices can be configured to match. The
432  * device list is updated asynchronously, so it will have the latest list of
433  * devices provided by the server.
434  */
435
436 struct NodeProxy;
437 struct MetadataProxy;
438
439 /* The global thread watching for global events. This particular class responds
440  * to objects being added to or removed from the registry.
441  */
442 struct EventManager {
443     ThreadMainloop mLoop{};
444     PwContextPtr mContext{};
445     PwCorePtr mCore{};
446     PwRegistryPtr mRegistry{};
447     spa_hook mRegistryListener{};
448     spa_hook mCoreListener{};
449
450     /* A list of proxy objects watching for events about changes to objects in
451      * the registry.
452      */
453     std::vector<NodeProxy*> mNodeList;
454     MetadataProxy *mDefaultMetadata{nullptr};
455
456     /* Initialization handling. When init() is called, mInitSeq is set to a
457      * SequenceID that marks the end of populating the registry. As objects of
458      * interest are found, events to parse them are generated and mInitSeq is
459      * updated with a newer ID. When mInitSeq stops being updated and the event
460      * corresponding to it is reached, mInitDone will be set to true.
461      */
462     std::atomic<bool> mInitDone{false};
463     std::atomic<bool> mHasAudio{false};
464     int mInitSeq{};
465
466     bool init();
467     ~EventManager();
468
469     void kill();
470
471     auto lock() const { return mLoop.lock(); }
472     auto unlock() const { return mLoop.unlock(); }
473
474     /**
475      * Waits for initialization to finish. The event manager must *NOT* be
476      * locked when calling this.
477      */
478     void waitForInit()
479     {
480         if(!mInitDone.load(std::memory_order_acquire)) UNLIKELY
481         {
482             MainloopUniqueLock plock{mLoop};
483             plock.wait([this](){ return mInitDone.load(std::memory_order_acquire); });
484         }
485     }
486
487     /**
488      * Waits for audio support to be detected, or initialization to finish,
489      * whichever is first. Returns true if audio support was detected. The
490      * event manager must *NOT* be locked when calling this.
491      */
492     bool waitForAudio()
493     {
494         MainloopUniqueLock plock{mLoop};
495         bool has_audio{};
496         plock.wait([this,&has_audio]()
497         {
498             has_audio = mHasAudio.load(std::memory_order_acquire);
499             return has_audio || mInitDone.load(std::memory_order_acquire);
500         });
501         return has_audio;
502     }
503
504     void syncInit()
505     {
506         /* If initialization isn't done, update the sequence ID so it won't
507          * complete until after currently scheduled events.
508          */
509         if(!mInitDone.load(std::memory_order_relaxed))
510             mInitSeq = ppw_core_sync(mCore.get(), PW_ID_CORE, mInitSeq);
511     }
512
513     void addCallback(uint32_t id, uint32_t permissions, const char *type, uint32_t version,
514         const spa_dict *props);
515     static void addCallbackC(void *object, uint32_t id, uint32_t permissions, const char *type,
516         uint32_t version, const spa_dict *props)
517     { static_cast<EventManager*>(object)->addCallback(id, permissions, type, version, props); }
518
519     void removeCallback(uint32_t id);
520     static void removeCallbackC(void *object, uint32_t id)
521     { static_cast<EventManager*>(object)->removeCallback(id); }
522
523     static constexpr pw_registry_events CreateRegistryEvents()
524     {
525         pw_registry_events ret{};
526         ret.version = PW_VERSION_REGISTRY_EVENTS;
527         ret.global = &EventManager::addCallbackC;
528         ret.global_remove = &EventManager::removeCallbackC;
529         return ret;
530     }
531
532     void coreCallback(uint32_t id, int seq);
533     static void coreCallbackC(void *object, uint32_t id, int seq)
534     { static_cast<EventManager*>(object)->coreCallback(id, seq); }
535
536     static constexpr pw_core_events CreateCoreEvents()
537     {
538         pw_core_events ret{};
539         ret.version = PW_VERSION_CORE_EVENTS;
540         ret.done = &EventManager::coreCallbackC;
541         return ret;
542     }
543 };
544 using EventWatcherUniqueLock = std::unique_lock<EventManager>;
545 using EventWatcherLockGuard = std::lock_guard<EventManager>;
546
547 EventManager gEventHandler;
548
549 /* Enumerated devices. This is updated asynchronously as the app runs, and the
550  * gEventHandler thread loop must be locked when accessing the list.
551  */
552 enum class NodeType : unsigned char {
553     Sink, Source, Duplex
554 };
555 constexpr auto InvalidChannelConfig = DevFmtChannels(255);
556 struct DeviceNode {
557     uint32_t mId{};
558
559     uint64_t mSerial{};
560     std::string mName;
561     std::string mDevName;
562
563     NodeType mType{};
564     bool mIsHeadphones{};
565     bool mIs51Rear{};
566
567     uint mSampleRate{};
568     DevFmtChannels mChannels{InvalidChannelConfig};
569
570     static std::vector<DeviceNode> sList;
571     static DeviceNode &Add(uint32_t id);
572     static DeviceNode *Find(uint32_t id);
573     static void Remove(uint32_t id);
574     static std::vector<DeviceNode> &GetList() noexcept { return sList; }
575
576     void parseSampleRate(const spa_pod *value) noexcept;
577     void parsePositions(const spa_pod *value) noexcept;
578     void parseChannelCount(const spa_pod *value) noexcept;
579 };
580 std::vector<DeviceNode> DeviceNode::sList;
581 std::string DefaultSinkDevice;
582 std::string DefaultSourceDevice;
583
584 const char *AsString(NodeType type) noexcept
585 {
586     switch(type)
587     {
588     case NodeType::Sink: return "sink";
589     case NodeType::Source: return "source";
590     case NodeType::Duplex: return "duplex";
591     }
592     return "<unknown>";
593 }
594
595 DeviceNode &DeviceNode::Add(uint32_t id)
596 {
597     auto match_id = [id](DeviceNode &n) noexcept -> bool
598     { return n.mId == id; };
599
600     /* If the node is already in the list, return the existing entry. */
601     auto match = std::find_if(sList.begin(), sList.end(), match_id);
602     if(match != sList.end()) return *match;
603
604     sList.emplace_back();
605     auto &n = sList.back();
606     n.mId = id;
607     return n;
608 }
609
610 DeviceNode *DeviceNode::Find(uint32_t id)
611 {
612     auto match_id = [id](DeviceNode &n) noexcept -> bool
613     { return n.mId == id; };
614
615     auto match = std::find_if(sList.begin(), sList.end(), match_id);
616     if(match != sList.end()) return al::to_address(match);
617
618     return nullptr;
619 }
620
621 void DeviceNode::Remove(uint32_t id)
622 {
623     auto match_id = [id](DeviceNode &n) noexcept -> bool
624     {
625         if(n.mId != id)
626             return false;
627         TRACE("Removing device \"%s\"\n", n.mDevName.c_str());
628         return true;
629     };
630
631     auto end = std::remove_if(sList.begin(), sList.end(), match_id);
632     sList.erase(end, sList.end());
633 }
634
635
636 const spa_audio_channel MonoMap[]{
637     SPA_AUDIO_CHANNEL_MONO
638 }, StereoMap[] {
639     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR
640 }, QuadMap[]{
641     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR
642 }, X51Map[]{
643     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
644     SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
645 }, X51RearMap[]{
646     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
647     SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR
648 }, X61Map[]{
649     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
650     SPA_AUDIO_CHANNEL_RC, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
651 }, X71Map[]{
652     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
653     SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR
654 }, X714Map[]{
655     SPA_AUDIO_CHANNEL_FL, SPA_AUDIO_CHANNEL_FR, SPA_AUDIO_CHANNEL_FC, SPA_AUDIO_CHANNEL_LFE,
656     SPA_AUDIO_CHANNEL_RL, SPA_AUDIO_CHANNEL_RR, SPA_AUDIO_CHANNEL_SL, SPA_AUDIO_CHANNEL_SR,
657     SPA_AUDIO_CHANNEL_TFL, SPA_AUDIO_CHANNEL_TFR, SPA_AUDIO_CHANNEL_TRL, SPA_AUDIO_CHANNEL_TRR
658 };
659
660 /**
661  * Checks if every channel in 'map1' exists in 'map0' (that is, map0 is equal
662  * to or a superset of map1).
663  */
664 template<size_t N>
665 bool MatchChannelMap(const al::span<const uint32_t> map0, const spa_audio_channel (&map1)[N])
666 {
667     if(map0.size() < N)
668         return false;
669     for(const spa_audio_channel chid : map1)
670     {
671         if(std::find(map0.begin(), map0.end(), chid) == map0.end())
672             return false;
673     }
674     return true;
675 }
676
677 void DeviceNode::parseSampleRate(const spa_pod *value) noexcept
678 {
679     /* TODO: Can this be anything else? Long, Float, Double? */
680     uint32_t nvals{}, choiceType{};
681     value = spa_pod_get_values(value, &nvals, &choiceType);
682
683     const uint podType{get_pod_type(value)};
684     if(podType != SPA_TYPE_Int)
685     {
686         WARN("Unhandled sample rate POD type: %u\n", podType);
687         return;
688     }
689
690     if(choiceType == SPA_CHOICE_Range)
691     {
692         if(nvals != 3)
693         {
694             WARN("Unexpected SPA_CHOICE_Range count: %u\n", nvals);
695             return;
696         }
697         auto srates = get_pod_body<int32_t,3>(value);
698
699         /* [0] is the default, [1] is the min, and [2] is the max. */
700         TRACE("Device ID %" PRIu64 " sample rate: %d (range: %d -> %d)\n", mSerial, srates[0],
701             srates[1], srates[2]);
702         mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE));
703         return;
704     }
705
706     if(choiceType == SPA_CHOICE_Enum)
707     {
708         if(nvals == 0)
709         {
710             WARN("Unexpected SPA_CHOICE_Enum count: %u\n", nvals);
711             return;
712         }
713         auto srates = get_pod_body<int32_t>(value, nvals);
714
715         /* [0] is the default, [1...size()-1] are available selections. */
716         std::string others{(srates.size() > 1) ? std::to_string(srates[1]) : std::string{}};
717         for(size_t i{2};i < srates.size();++i)
718         {
719             others += ", ";
720             others += std::to_string(srates[i]);
721         }
722         TRACE("Device ID %" PRIu64 " sample rate: %d (%s)\n", mSerial, srates[0], others.c_str());
723         /* Pick the first rate listed that's within the allowed range (default
724          * rate if possible).
725          */
726         for(const auto &rate : srates)
727         {
728             if(rate >= MIN_OUTPUT_RATE && rate <= MAX_OUTPUT_RATE)
729             {
730                 mSampleRate = static_cast<uint>(rate);
731                 break;
732             }
733         }
734         return;
735     }
736
737     if(choiceType == SPA_CHOICE_None)
738     {
739         if(nvals != 1)
740         {
741             WARN("Unexpected SPA_CHOICE_None count: %u\n", nvals);
742             return;
743         }
744         auto srates = get_pod_body<int32_t,1>(value);
745
746         TRACE("Device ID %" PRIu64 " sample rate: %d\n", mSerial, srates[0]);
747         mSampleRate = static_cast<uint>(clampi(srates[0], MIN_OUTPUT_RATE, MAX_OUTPUT_RATE));
748         return;
749     }
750
751     WARN("Unhandled sample rate choice type: %u\n", choiceType);
752 }
753
754 void DeviceNode::parsePositions(const spa_pod *value) noexcept
755 {
756     const auto chanmap = get_array_span<SPA_TYPE_Id>(value);
757     if(chanmap.empty()) return;
758
759     mIs51Rear = false;
760
761     if(MatchChannelMap(chanmap, X714Map))
762         mChannels = DevFmtX714;
763     else if(MatchChannelMap(chanmap, X71Map))
764         mChannels = DevFmtX71;
765     else if(MatchChannelMap(chanmap, X61Map))
766         mChannels = DevFmtX61;
767     else if(MatchChannelMap(chanmap, X51Map))
768         mChannels = DevFmtX51;
769     else if(MatchChannelMap(chanmap, X51RearMap))
770     {
771         mChannels = DevFmtX51;
772         mIs51Rear = true;
773     }
774     else if(MatchChannelMap(chanmap, QuadMap))
775         mChannels = DevFmtQuad;
776     else if(MatchChannelMap(chanmap, StereoMap))
777         mChannels = DevFmtStereo;
778     else
779         mChannels = DevFmtMono;
780     TRACE("Device ID %" PRIu64 " got %zu position%s for %s%s\n", mSerial, chanmap.size(),
781         (chanmap.size()==1)?"":"s", DevFmtChannelsString(mChannels), mIs51Rear?"(rear)":"");
782 }
783
784 void DeviceNode::parseChannelCount(const spa_pod *value) noexcept
785 {
786     /* As a fallback with just a channel count, just assume mono or stereo. */
787     const auto chancount = get_value<SPA_TYPE_Int>(value);
788     if(!chancount) return;
789
790     mIs51Rear = false;
791
792     if(*chancount >= 2)
793         mChannels = DevFmtStereo;
794     else if(*chancount >= 1)
795         mChannels = DevFmtMono;
796     TRACE("Device ID %" PRIu64 " got %d channel%s for %s\n", mSerial, *chancount,
797         (*chancount==1)?"":"s", DevFmtChannelsString(mChannels));
798 }
799
800
801 constexpr char MonitorPrefix[]{"Monitor of "};
802 constexpr auto MonitorPrefixLen = al::size(MonitorPrefix) - 1;
803 constexpr char AudioSinkClass[]{"Audio/Sink"};
804 constexpr char AudioSourceClass[]{"Audio/Source"};
805 constexpr char AudioSourceVirtualClass[]{"Audio/Source/Virtual"};
806 constexpr char AudioDuplexClass[]{"Audio/Duplex"};
807 constexpr char StreamClass[]{"Stream/"};
808
809 /* A generic PipeWire node proxy object used to track changes to sink and
810  * source nodes.
811  */
812 struct NodeProxy {
813     static constexpr pw_node_events CreateNodeEvents()
814     {
815         pw_node_events ret{};
816         ret.version = PW_VERSION_NODE_EVENTS;
817         ret.info = &NodeProxy::infoCallbackC;
818         ret.param = &NodeProxy::paramCallbackC;
819         return ret;
820     }
821
822     uint32_t mId{};
823
824     PwNodePtr mNode{};
825     spa_hook mListener{};
826
827     NodeProxy(uint32_t id, PwNodePtr node)
828       : mId{id}, mNode{std::move(node)}
829     {
830         static constexpr pw_node_events nodeEvents{CreateNodeEvents()};
831         ppw_node_add_listener(mNode.get(), &mListener, &nodeEvents, this);
832
833         /* Track changes to the enumerable formats (indicates the default
834          * format, which is what we're interested in).
835          */
836         uint32_t fmtids[]{SPA_PARAM_EnumFormat};
837         ppw_node_subscribe_params(mNode.get(), al::data(fmtids), al::size(fmtids));
838     }
839     ~NodeProxy()
840     { spa_hook_remove(&mListener); }
841
842
843     void infoCallback(const pw_node_info *info);
844     static void infoCallbackC(void *object, const pw_node_info *info)
845     { static_cast<NodeProxy*>(object)->infoCallback(info); }
846
847     void paramCallback(int seq, uint32_t id, uint32_t index, uint32_t next, const spa_pod *param);
848     static void paramCallbackC(void *object, int seq, uint32_t id, uint32_t index, uint32_t next,
849         const spa_pod *param)
850     { static_cast<NodeProxy*>(object)->paramCallback(seq, id, index, next, param); }
851 };
852
853 void NodeProxy::infoCallback(const pw_node_info *info)
854 {
855     /* We only care about property changes here (media class, name/desc).
856      * Format changes will automatically invoke the param callback.
857      *
858      * TODO: Can the media class or name/desc change without being removed and
859      * readded?
860      */
861     if((info->change_mask&PW_NODE_CHANGE_MASK_PROPS))
862     {
863         /* Can this actually change? */
864         const char *media_class{spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS)};
865         if(!media_class) UNLIKELY return;
866
867         NodeType ntype{};
868         if(al::strcasecmp(media_class, AudioSinkClass) == 0)
869             ntype = NodeType::Sink;
870         else if(al::strcasecmp(media_class, AudioSourceClass) == 0
871             || al::strcasecmp(media_class, AudioSourceVirtualClass) == 0)
872             ntype = NodeType::Source;
873         else if(al::strcasecmp(media_class, AudioDuplexClass) == 0)
874             ntype = NodeType::Duplex;
875         else
876         {
877             TRACE("Dropping device node %u which became type \"%s\"\n", info->id, media_class);
878             DeviceNode::Remove(info->id);
879             return;
880         }
881
882         const char *devName{spa_dict_lookup(info->props, PW_KEY_NODE_NAME)};
883         const char *nodeName{spa_dict_lookup(info->props, PW_KEY_NODE_DESCRIPTION)};
884         if(!nodeName || !*nodeName) nodeName = spa_dict_lookup(info->props, PW_KEY_NODE_NICK);
885         if(!nodeName || !*nodeName) nodeName = devName;
886
887         uint64_t serial_id{info->id};
888 #ifdef PW_KEY_OBJECT_SERIAL
889         if(const char *serial_str{spa_dict_lookup(info->props, PW_KEY_OBJECT_SERIAL)})
890         {
891             char *serial_end{};
892             serial_id = std::strtoull(serial_str, &serial_end, 0);
893             if(*serial_end != '\0' || errno == ERANGE)
894             {
895                 ERR("Unexpected object serial: %s\n", serial_str);
896                 serial_id = info->id;
897             }
898         }
899 #endif
900
901         const char *form_factor{spa_dict_lookup(info->props, PW_KEY_DEVICE_FORM_FACTOR)};
902         TRACE("Got %s device \"%s\"%s%s%s\n", AsString(ntype), devName ? devName : "(nil)",
903             form_factor?" (":"", form_factor?form_factor:"", form_factor?")":"");
904         TRACE("  \"%s\" = ID %" PRIu64 "\n", nodeName ? nodeName : "(nil)", serial_id);
905
906         DeviceNode &node = DeviceNode::Add(info->id);
907         node.mSerial = serial_id;
908         if(nodeName && *nodeName) node.mName = nodeName;
909         else node.mName = "PipeWire node #"+std::to_string(info->id);
910         node.mDevName = devName ? devName : "";
911         node.mType = ntype;
912         node.mIsHeadphones = form_factor && (al::strcasecmp(form_factor, "headphones") == 0
913             || al::strcasecmp(form_factor, "headset") == 0);
914     }
915 }
916
917 void NodeProxy::paramCallback(int, uint32_t id, uint32_t, uint32_t, const spa_pod *param)
918 {
919     if(id == SPA_PARAM_EnumFormat)
920     {
921         DeviceNode *node{DeviceNode::Find(mId)};
922         if(!node) UNLIKELY return;
923
924         if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_rate)})
925             node->parseSampleRate(&prop->value);
926
927         if(const spa_pod_prop *prop{spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_position)})
928             node->parsePositions(&prop->value);
929         else if((prop=spa_pod_find_prop(param, nullptr, SPA_FORMAT_AUDIO_channels)) != nullptr)
930             node->parseChannelCount(&prop->value);
931     }
932 }
933
934
935 /* A metadata proxy object used to query the default sink and source. */
936 struct MetadataProxy {
937     static constexpr pw_metadata_events CreateMetadataEvents()
938     {
939         pw_metadata_events ret{};
940         ret.version = PW_VERSION_METADATA_EVENTS;
941         ret.property = &MetadataProxy::propertyCallbackC;
942         return ret;
943     }
944
945     uint32_t mId{};
946
947     PwMetadataPtr mMetadata{};
948     spa_hook mListener{};
949
950     MetadataProxy(uint32_t id, PwMetadataPtr mdata)
951       : mId{id}, mMetadata{std::move(mdata)}
952     {
953         static constexpr pw_metadata_events metadataEvents{CreateMetadataEvents()};
954         ppw_metadata_add_listener(mMetadata.get(), &mListener, &metadataEvents, this);
955     }
956     ~MetadataProxy()
957     { spa_hook_remove(&mListener); }
958
959
960     int propertyCallback(uint32_t id, const char *key, const char *type, const char *value);
961     static int propertyCallbackC(void *object, uint32_t id, const char *key, const char *type,
962         const char *value)
963     { return static_cast<MetadataProxy*>(object)->propertyCallback(id, key, type, value); }
964 };
965
966 int MetadataProxy::propertyCallback(uint32_t id, const char *key, const char *type,
967     const char *value)
968 {
969     if(id != PW_ID_CORE)
970         return 0;
971
972     bool isCapture{};
973     if(std::strcmp(key, "default.audio.sink") == 0)
974         isCapture = false;
975     else if(std::strcmp(key, "default.audio.source") == 0)
976         isCapture = true;
977     else
978         return 0;
979
980     if(!type)
981     {
982         TRACE("Default %s device cleared\n", isCapture ? "capture" : "playback");
983         if(!isCapture) DefaultSinkDevice.clear();
984         else DefaultSourceDevice.clear();
985         return 0;
986     }
987     if(std::strcmp(type, "Spa:String:JSON") != 0)
988     {
989         ERR("Unexpected %s property type: %s\n", key, type);
990         return 0;
991     }
992
993     spa_json it[2]{};
994     spa_json_init(&it[0], value, strlen(value));
995     if(spa_json_enter_object(&it[0], &it[1]) <= 0)
996         return 0;
997
998     auto get_json_string = [](spa_json *iter)
999     {
1000         al::optional<std::string> str;
1001
1002         const char *val{};
1003         int len{spa_json_next(iter, &val)};
1004         if(len <= 0) return str;
1005
1006         str.emplace().resize(static_cast<uint>(len), '\0');
1007         if(spa_json_parse_string(val, len, &str->front()) <= 0)
1008             str.reset();
1009         else while(!str->empty() && str->back() == '\0')
1010             str->pop_back();
1011         return str;
1012     };
1013     while(auto propKey = get_json_string(&it[1]))
1014     {
1015         if(*propKey == "name")
1016         {
1017             auto propValue = get_json_string(&it[1]);
1018             if(!propValue) break;
1019
1020             TRACE("Got default %s device \"%s\"\n", isCapture ? "capture" : "playback",
1021                 propValue->c_str());
1022             if(!isCapture)
1023                 DefaultSinkDevice = std::move(*propValue);
1024             else
1025                 DefaultSourceDevice = std::move(*propValue);
1026         }
1027         else
1028         {
1029             const char *v{};
1030             if(spa_json_next(&it[1], &v) <= 0)
1031                 break;
1032         }
1033     }
1034     return 0;
1035 }
1036
1037
1038 bool EventManager::init()
1039 {
1040     mLoop = ThreadMainloop::Create("PWEventThread");
1041     if(!mLoop)
1042     {
1043         ERR("Failed to create PipeWire event thread loop (errno: %d)\n", errno);
1044         return false;
1045     }
1046
1047     mContext = mLoop.newContext(pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", nullptr));
1048     if(!mContext)
1049     {
1050         ERR("Failed to create PipeWire event context (errno: %d)\n", errno);
1051         return false;
1052     }
1053
1054     mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
1055     if(!mCore)
1056     {
1057         ERR("Failed to connect PipeWire event context (errno: %d)\n", errno);
1058         return false;
1059     }
1060
1061     mRegistry = PwRegistryPtr{pw_core_get_registry(mCore.get(), PW_VERSION_REGISTRY, 0)};
1062     if(!mRegistry)
1063     {
1064         ERR("Failed to get PipeWire event registry (errno: %d)\n", errno);
1065         return false;
1066     }
1067
1068     static constexpr pw_core_events coreEvents{CreateCoreEvents()};
1069     static constexpr pw_registry_events registryEvents{CreateRegistryEvents()};
1070
1071     ppw_core_add_listener(mCore.get(), &mCoreListener, &coreEvents, this);
1072     ppw_registry_add_listener(mRegistry.get(), &mRegistryListener, &registryEvents, this);
1073
1074     /* Set an initial sequence ID for initialization, to trigger after the
1075      * registry is first populated.
1076      */
1077     mInitSeq = ppw_core_sync(mCore.get(), PW_ID_CORE, 0);
1078
1079     if(int res{mLoop.start()})
1080     {
1081         ERR("Failed to start PipeWire event thread loop (res: %d)\n", res);
1082         return false;
1083     }
1084
1085     return true;
1086 }
1087
1088 EventManager::~EventManager()
1089 {
1090     if(mLoop) mLoop.stop();
1091
1092     for(NodeProxy *node : mNodeList)
1093         al::destroy_at(node);
1094     if(mDefaultMetadata)
1095         al::destroy_at(mDefaultMetadata);
1096 }
1097
1098 void EventManager::kill()
1099 {
1100     if(mLoop) mLoop.stop();
1101
1102     for(NodeProxy *node : mNodeList)
1103         al::destroy_at(node);
1104     mNodeList.clear();
1105     if(mDefaultMetadata)
1106         al::destroy_at(mDefaultMetadata);
1107     mDefaultMetadata = nullptr;
1108
1109     mRegistry = nullptr;
1110     mCore = nullptr;
1111     mContext = nullptr;
1112     mLoop = nullptr;
1113 }
1114
1115 void EventManager::addCallback(uint32_t id, uint32_t, const char *type, uint32_t version,
1116     const spa_dict *props)
1117 {
1118     /* We're only interested in interface nodes. */
1119     if(std::strcmp(type, PW_TYPE_INTERFACE_Node) == 0)
1120     {
1121         const char *media_class{spa_dict_lookup(props, PW_KEY_MEDIA_CLASS)};
1122         if(!media_class) return;
1123
1124         /* Specifically, audio sinks and sources (and duplexes). */
1125         const bool isGood{al::strcasecmp(media_class, AudioSinkClass) == 0
1126             || al::strcasecmp(media_class, AudioSourceClass) == 0
1127             || al::strcasecmp(media_class, AudioSourceVirtualClass) == 0
1128             || al::strcasecmp(media_class, AudioDuplexClass) == 0};
1129         if(!isGood)
1130         {
1131             if(std::strstr(media_class, "/Video") == nullptr
1132                 && std::strncmp(media_class, StreamClass, sizeof(StreamClass)-1) != 0)
1133                 TRACE("Ignoring node class %s\n", media_class);
1134             return;
1135         }
1136
1137         /* Create the proxy object. */
1138         auto node = PwNodePtr{static_cast<pw_node*>(pw_registry_bind(mRegistry.get(), id, type,
1139             version, sizeof(NodeProxy)))};
1140         if(!node)
1141         {
1142             ERR("Failed to create node proxy object (errno: %d)\n", errno);
1143             return;
1144         }
1145
1146         /* Initialize the NodeProxy to hold the node object, add it to the
1147          * active node list, and update the sync point.
1148          */
1149         auto *proxy = static_cast<NodeProxy*>(pw_proxy_get_user_data(as<pw_proxy*>(node.get())));
1150         mNodeList.emplace_back(al::construct_at(proxy, id, std::move(node)));
1151         syncInit();
1152
1153         /* Signal any waiters that we have found a source or sink for audio
1154          * support.
1155          */
1156         if(!mHasAudio.exchange(true, std::memory_order_acq_rel))
1157             mLoop.signal(false);
1158     }
1159     else if(std::strcmp(type, PW_TYPE_INTERFACE_Metadata) == 0)
1160     {
1161         const char *data_class{spa_dict_lookup(props, PW_KEY_METADATA_NAME)};
1162         if(!data_class) return;
1163
1164         if(std::strcmp(data_class, "default") != 0)
1165         {
1166             TRACE("Ignoring metadata \"%s\"\n", data_class);
1167             return;
1168         }
1169
1170         if(mDefaultMetadata)
1171         {
1172             ERR("Duplicate default metadata\n");
1173             return;
1174         }
1175
1176         auto mdata = PwMetadataPtr{static_cast<pw_metadata*>(pw_registry_bind(mRegistry.get(), id,
1177             type, version, sizeof(MetadataProxy)))};
1178         if(!mdata)
1179         {
1180             ERR("Failed to create metadata proxy object (errno: %d)\n", errno);
1181             return;
1182         }
1183
1184         auto *proxy = static_cast<MetadataProxy*>(
1185             pw_proxy_get_user_data(as<pw_proxy*>(mdata.get())));
1186         mDefaultMetadata = al::construct_at(proxy, id, std::move(mdata));
1187         syncInit();
1188     }
1189 }
1190
1191 void EventManager::removeCallback(uint32_t id)
1192 {
1193     DeviceNode::Remove(id);
1194
1195     auto clear_node = [id](NodeProxy *node) noexcept
1196     {
1197         if(node->mId != id)
1198             return false;
1199         al::destroy_at(node);
1200         return true;
1201     };
1202     auto node_end = std::remove_if(mNodeList.begin(), mNodeList.end(), clear_node);
1203     mNodeList.erase(node_end, mNodeList.end());
1204
1205     if(mDefaultMetadata && mDefaultMetadata->mId == id)
1206     {
1207         al::destroy_at(mDefaultMetadata);
1208         mDefaultMetadata = nullptr;
1209     }
1210 }
1211
1212 void EventManager::coreCallback(uint32_t id, int seq)
1213 {
1214     if(id == PW_ID_CORE && seq == mInitSeq)
1215     {
1216         /* Initialization done. Remove this callback and signal anyone that may
1217          * be waiting.
1218          */
1219         spa_hook_remove(&mCoreListener);
1220
1221         mInitDone.store(true);
1222         mLoop.signal(false);
1223     }
1224 }
1225
1226
1227 enum use_f32p_e : bool { UseDevType=false, ForceF32Planar=true };
1228 spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e use_f32p)
1229 {
1230     spa_audio_info_raw info{};
1231     if(use_f32p)
1232     {
1233         device->FmtType = DevFmtFloat;
1234         info.format = SPA_AUDIO_FORMAT_F32P;
1235     }
1236     else switch(device->FmtType)
1237     {
1238     case DevFmtByte: info.format = SPA_AUDIO_FORMAT_S8; break;
1239     case DevFmtUByte: info.format = SPA_AUDIO_FORMAT_U8; break;
1240     case DevFmtShort: info.format = SPA_AUDIO_FORMAT_S16; break;
1241     case DevFmtUShort: info.format = SPA_AUDIO_FORMAT_U16; break;
1242     case DevFmtInt: info.format = SPA_AUDIO_FORMAT_S32; break;
1243     case DevFmtUInt: info.format = SPA_AUDIO_FORMAT_U32; break;
1244     case DevFmtFloat: info.format = SPA_AUDIO_FORMAT_F32; break;
1245     }
1246
1247     info.rate = device->Frequency;
1248
1249     al::span<const spa_audio_channel> map{};
1250     switch(device->FmtChans)
1251     {
1252     case DevFmtMono: map = MonoMap; break;
1253     case DevFmtStereo: map = StereoMap; break;
1254     case DevFmtQuad: map = QuadMap; break;
1255     case DevFmtX51:
1256         if(is51rear) map = X51RearMap;
1257         else map = X51Map;
1258         break;
1259     case DevFmtX61: map = X61Map; break;
1260     case DevFmtX71: map = X71Map; break;
1261     case DevFmtX714: map = X714Map; break;
1262     case DevFmtX3D71: map = X71Map; break;
1263     case DevFmtAmbi3D:
1264         info.flags |= SPA_AUDIO_FLAG_UNPOSITIONED;
1265         info.channels = device->channelsFromFmt();
1266         break;
1267     }
1268     if(!map.empty())
1269     {
1270         info.channels = static_cast<uint32_t>(map.size());
1271         std::copy(map.begin(), map.end(), info.position);
1272     }
1273
1274     return info;
1275 }
1276
1277 class PipeWirePlayback final : public BackendBase {
1278     void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error);
1279     static void stateChangedCallbackC(void *data, pw_stream_state old, pw_stream_state state,
1280         const char *error)
1281     { static_cast<PipeWirePlayback*>(data)->stateChangedCallback(old, state, error); }
1282
1283     void ioChangedCallback(uint32_t id, void *area, uint32_t size);
1284     static void ioChangedCallbackC(void *data, uint32_t id, void *area, uint32_t size)
1285     { static_cast<PipeWirePlayback*>(data)->ioChangedCallback(id, area, size); }
1286
1287     void outputCallback();
1288     static void outputCallbackC(void *data)
1289     { static_cast<PipeWirePlayback*>(data)->outputCallback(); }
1290
1291     void open(const char *name) override;
1292     bool reset() override;
1293     void start() override;
1294     void stop() override;
1295     ClockLatency getClockLatency() override;
1296
1297     uint64_t mTargetId{PwIdAny};
1298     nanoseconds mTimeBase{0};
1299     ThreadMainloop mLoop;
1300     PwContextPtr mContext;
1301     PwCorePtr mCore;
1302     PwStreamPtr mStream;
1303     spa_hook mStreamListener{};
1304     spa_io_rate_match *mRateMatch{};
1305     std::unique_ptr<float*[]> mChannelPtrs;
1306     uint mNumChannels{};
1307
1308     static constexpr pw_stream_events CreateEvents()
1309     {
1310         pw_stream_events ret{};
1311         ret.version = PW_VERSION_STREAM_EVENTS;
1312         ret.state_changed = &PipeWirePlayback::stateChangedCallbackC;
1313         ret.io_changed = &PipeWirePlayback::ioChangedCallbackC;
1314         ret.process = &PipeWirePlayback::outputCallbackC;
1315         return ret;
1316     }
1317
1318 public:
1319     PipeWirePlayback(DeviceBase *device) noexcept : BackendBase{device} { }
1320     ~PipeWirePlayback()
1321     {
1322         /* Stop the mainloop so the stream can be properly destroyed. */
1323         if(mLoop) mLoop.stop();
1324     }
1325
1326     DEF_NEWDEL(PipeWirePlayback)
1327 };
1328
1329
1330 void PipeWirePlayback::stateChangedCallback(pw_stream_state, pw_stream_state, const char*)
1331 { mLoop.signal(false); }
1332
1333 void PipeWirePlayback::ioChangedCallback(uint32_t id, void *area, uint32_t size)
1334 {
1335     switch(id)
1336     {
1337     case SPA_IO_RateMatch:
1338         if(size >= sizeof(spa_io_rate_match))
1339             mRateMatch = static_cast<spa_io_rate_match*>(area);
1340         break;
1341     }
1342 }
1343
1344 void PipeWirePlayback::outputCallback()
1345 {
1346     pw_buffer *pw_buf{pw_stream_dequeue_buffer(mStream.get())};
1347     if(!pw_buf) UNLIKELY return;
1348
1349     const al::span<spa_data> datas{pw_buf->buffer->datas,
1350         minu(mNumChannels, pw_buf->buffer->n_datas)};
1351 #if PW_CHECK_VERSION(0,3,49)
1352     /* In 0.3.49, pw_buffer::requested specifies the number of samples needed
1353      * by the resampler/graph for this audio update.
1354      */
1355     uint length{static_cast<uint>(pw_buf->requested)};
1356 #else
1357     /* In 0.3.48 and earlier, spa_io_rate_match::size apparently has the number
1358      * of samples per update.
1359      */
1360     uint length{mRateMatch ? mRateMatch->size : 0u};
1361 #endif
1362     /* If no length is specified, use the device's update size as a fallback. */
1363     if(!length) UNLIKELY length = mDevice->UpdateSize;
1364
1365     /* For planar formats, each datas[] seems to contain one channel, so store
1366      * the pointers in an array. Limit the render length in case the available
1367      * buffer length in any one channel is smaller than we wanted (shouldn't
1368      * be, but just in case).
1369      */
1370     float **chanptr_end{mChannelPtrs.get()};
1371     for(const auto &data : datas)
1372     {
1373         length = minu(length, data.maxsize/sizeof(float));
1374         *chanptr_end = static_cast<float*>(data.data);
1375         ++chanptr_end;
1376     }
1377
1378     mDevice->renderSamples({mChannelPtrs.get(), chanptr_end}, length);
1379
1380     for(const auto &data : datas)
1381     {
1382         data.chunk->offset = 0;
1383         data.chunk->stride = sizeof(float);
1384         data.chunk->size   = length * sizeof(float);
1385     }
1386     pw_buf->size = length;
1387     pw_stream_queue_buffer(mStream.get(), pw_buf);
1388 }
1389
1390
1391 void PipeWirePlayback::open(const char *name)
1392 {
1393     static std::atomic<uint> OpenCount{0};
1394
1395     uint64_t targetid{PwIdAny};
1396     std::string devname{};
1397     gEventHandler.waitForInit();
1398     if(!name)
1399     {
1400         EventWatcherLockGuard _{gEventHandler};
1401         auto&& devlist = DeviceNode::GetList();
1402
1403         auto match = devlist.cend();
1404         if(!DefaultSinkDevice.empty())
1405         {
1406             auto match_default = [](const DeviceNode &n) -> bool
1407             { return n.mDevName == DefaultSinkDevice; };
1408             match = std::find_if(devlist.cbegin(), devlist.cend(), match_default);
1409         }
1410         if(match == devlist.cend())
1411         {
1412             auto match_playback = [](const DeviceNode &n) -> bool
1413             { return n.mType != NodeType::Source; };
1414             match = std::find_if(devlist.cbegin(), devlist.cend(), match_playback);
1415             if(match == devlist.cend())
1416                 throw al::backend_exception{al::backend_error::NoDevice,
1417                     "No PipeWire playback device found"};
1418         }
1419
1420         targetid = match->mSerial;
1421         devname = match->mName;
1422     }
1423     else
1424     {
1425         EventWatcherLockGuard _{gEventHandler};
1426         auto&& devlist = DeviceNode::GetList();
1427
1428         auto match_name = [name](const DeviceNode &n) -> bool
1429         { return n.mType != NodeType::Source && n.mName == name; };
1430         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name);
1431         if(match == devlist.cend())
1432             throw al::backend_exception{al::backend_error::NoDevice,
1433                 "Device name \"%s\" not found", name};
1434
1435         targetid = match->mSerial;
1436         devname = match->mName;
1437     }
1438
1439     if(!mLoop)
1440     {
1441         const uint count{OpenCount.fetch_add(1, std::memory_order_relaxed)};
1442         const std::string thread_name{"ALSoftP" + std::to_string(count)};
1443         mLoop = ThreadMainloop::Create(thread_name.c_str());
1444         if(!mLoop)
1445             throw al::backend_exception{al::backend_error::DeviceError,
1446                 "Failed to create PipeWire mainloop (errno: %d)", errno};
1447         if(int res{mLoop.start()})
1448             throw al::backend_exception{al::backend_error::DeviceError,
1449                 "Failed to start PipeWire mainloop (res: %d)", res};
1450     }
1451     MainloopUniqueLock mlock{mLoop};
1452     if(!mContext)
1453     {
1454         pw_properties *cprops{pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", nullptr)};
1455         mContext = mLoop.newContext(cprops);
1456         if(!mContext)
1457             throw al::backend_exception{al::backend_error::DeviceError,
1458                 "Failed to create PipeWire event context (errno: %d)\n", errno};
1459     }
1460     if(!mCore)
1461     {
1462         mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
1463         if(!mCore)
1464             throw al::backend_exception{al::backend_error::DeviceError,
1465                 "Failed to connect PipeWire event context (errno: %d)\n", errno};
1466     }
1467     mlock.unlock();
1468
1469     /* TODO: Ensure the target ID is still valid/usable and accepts streams. */
1470
1471     mTargetId = targetid;
1472     if(!devname.empty())
1473         mDevice->DeviceName = std::move(devname);
1474     else
1475         mDevice->DeviceName = pwireDevice;
1476 }
1477
1478 bool PipeWirePlayback::reset()
1479 {
1480     if(mStream)
1481     {
1482         MainloopLockGuard _{mLoop};
1483         mStream = nullptr;
1484     }
1485     mStreamListener = {};
1486     mRateMatch = nullptr;
1487     mTimeBase = GetDeviceClockTime(mDevice);
1488
1489     /* If connecting to a specific device, update various device parameters to
1490      * match its format.
1491      */
1492     bool is51rear{false};
1493     mDevice->Flags.reset(DirectEar);
1494     if(mTargetId != PwIdAny)
1495     {
1496         EventWatcherLockGuard _{gEventHandler};
1497         auto&& devlist = DeviceNode::GetList();
1498
1499         auto match_id = [targetid=mTargetId](const DeviceNode &n) -> bool
1500         { return targetid == n.mSerial; };
1501         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_id);
1502         if(match != devlist.cend())
1503         {
1504             if(!mDevice->Flags.test(FrequencyRequest) && match->mSampleRate > 0)
1505             {
1506                 /* Scale the update size if the sample rate changes. */
1507                 const double scale{static_cast<double>(match->mSampleRate) / mDevice->Frequency};
1508                 const double numbufs{static_cast<double>(mDevice->BufferSize)/mDevice->UpdateSize};
1509                 mDevice->Frequency = match->mSampleRate;
1510                 mDevice->UpdateSize = static_cast<uint>(clampd(mDevice->UpdateSize*scale + 0.5,
1511                     64.0, 8192.0));
1512                 mDevice->BufferSize = static_cast<uint>(numbufs*mDevice->UpdateSize + 0.5);
1513             }
1514             if(!mDevice->Flags.test(ChannelsRequest) && match->mChannels != InvalidChannelConfig)
1515                 mDevice->FmtChans = match->mChannels;
1516             if(match->mChannels == DevFmtStereo && match->mIsHeadphones)
1517                 mDevice->Flags.set(DirectEar);
1518             is51rear = match->mIs51Rear;
1519         }
1520     }
1521     /* Force planar 32-bit float output for playback. This is what PipeWire
1522      * handles internally, and it's easier for us too.
1523      */
1524     spa_audio_info_raw info{make_spa_info(mDevice, is51rear, ForceF32Planar)};
1525
1526     /* TODO: How to tell what an appropriate size is? Examples just use this
1527      * magic value.
1528      */
1529     constexpr uint32_t pod_buffer_size{1024};
1530     auto pod_buffer = std::make_unique<al::byte[]>(pod_buffer_size);
1531     spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)};
1532
1533     const spa_pod *params{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)};
1534     if(!params)
1535         throw al::backend_exception{al::backend_error::DeviceError,
1536             "Failed to set PipeWire audio format parameters"};
1537
1538     /* TODO: Which properties are actually needed here? Any others that could
1539      * be useful?
1540      */
1541     auto&& binary = GetProcBinary();
1542     const char *appname{binary.fname.length() ? binary.fname.c_str() : "OpenAL Soft"};
1543     pw_properties *props{pw_properties_new(PW_KEY_NODE_NAME, appname,
1544         PW_KEY_NODE_DESCRIPTION, appname,
1545         PW_KEY_MEDIA_TYPE, "Audio",
1546         PW_KEY_MEDIA_CATEGORY, "Playback",
1547         PW_KEY_MEDIA_ROLE, "Game",
1548         PW_KEY_NODE_ALWAYS_PROCESS, "true",
1549         nullptr)};
1550     if(!props)
1551         throw al::backend_exception{al::backend_error::DeviceError,
1552             "Failed to create PipeWire stream properties (errno: %d)", errno};
1553
1554     pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", mDevice->UpdateSize,
1555         mDevice->Frequency);
1556     pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->Frequency);
1557 #ifdef PW_KEY_TARGET_OBJECT
1558     pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, mTargetId);
1559 #else
1560     pw_properties_setf(props, PW_KEY_NODE_TARGET, "%" PRIu64, mTargetId);
1561 #endif
1562
1563     MainloopUniqueLock plock{mLoop};
1564     /* The stream takes overship of 'props', even in the case of failure. */
1565     mStream = PwStreamPtr{pw_stream_new(mCore.get(), "Playback Stream", props)};
1566     if(!mStream)
1567         throw al::backend_exception{al::backend_error::NoDevice,
1568             "Failed to create PipeWire stream (errno: %d)", errno};
1569     static constexpr pw_stream_events streamEvents{CreateEvents()};
1570     pw_stream_add_listener(mStream.get(), &mStreamListener, &streamEvents, this);
1571
1572     pw_stream_flags flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
1573         | PW_STREAM_FLAG_MAP_BUFFERS};
1574     if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pipewire", "rt-mix", true))
1575         flags |= PW_STREAM_FLAG_RT_PROCESS;
1576     if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_OUTPUT, PwIdAny, flags, &params, 1)})
1577         throw al::backend_exception{al::backend_error::DeviceError,
1578             "Error connecting PipeWire stream (res: %d)", res};
1579
1580     /* Wait for the stream to become paused (ready to start streaming). */
1581     plock.wait([stream=mStream.get()]()
1582     {
1583         const char *error{};
1584         pw_stream_state state{pw_stream_get_state(stream, &error)};
1585         if(state == PW_STREAM_STATE_ERROR)
1586             throw al::backend_exception{al::backend_error::DeviceError,
1587                 "Error connecting PipeWire stream: \"%s\"", error};
1588         return state == PW_STREAM_STATE_PAUSED;
1589     });
1590
1591     /* TODO: Update mDevice->UpdateSize with the stream's quantum, and
1592      * mDevice->BufferSize with the total known buffering delay from the head
1593      * of this playback stream to the tail of the device output.
1594      *
1595      * This info is apparently not available until after the stream starts.
1596      */
1597     plock.unlock();
1598
1599     mNumChannels = mDevice->channelsFromFmt();
1600     mChannelPtrs = std::make_unique<float*[]>(mNumChannels);
1601
1602     setDefaultWFXChannelOrder();
1603
1604     return true;
1605 }
1606
1607 void PipeWirePlayback::start()
1608 {
1609     MainloopUniqueLock plock{mLoop};
1610     if(int res{pw_stream_set_active(mStream.get(), true)})
1611         throw al::backend_exception{al::backend_error::DeviceError,
1612             "Failed to start PipeWire stream (res: %d)", res};
1613
1614     /* Wait for the stream to start playing (would be nice to not, but we need
1615      * the actual update size which is only available after starting).
1616      */
1617     plock.wait([stream=mStream.get()]()
1618     {
1619         const char *error{};
1620         pw_stream_state state{pw_stream_get_state(stream, &error)};
1621         if(state == PW_STREAM_STATE_ERROR)
1622             throw al::backend_exception{al::backend_error::DeviceError,
1623                 "PipeWire stream error: %s", error ? error : "(unknown)"};
1624         return state == PW_STREAM_STATE_STREAMING;
1625     });
1626
1627     /* HACK: Try to work out the update size and total buffering size. There's
1628      * no actual query for this, so we have to work it out from the stream time
1629      * info, and assume it stays accurate with future updates. The stream time
1630      * info may also not be available right away, so we have to wait until it
1631      * is (up to about 2 seconds).
1632      */
1633     int wait_count{100};
1634     do {
1635         pw_time ptime{};
1636         if(int res{pw_stream_get_time_n(mStream.get(), &ptime, sizeof(ptime))})
1637         {
1638             ERR("Failed to get PipeWire stream time (res: %d)\n", res);
1639             break;
1640         }
1641
1642         /* The rate match size is the update size for each buffer. */
1643         const uint updatesize{mRateMatch ? mRateMatch->size : 0u};
1644 #if PW_CHECK_VERSION(0,3,50)
1645         /* Assume ptime.avail_buffers+ptime.queued_buffers is the target buffer
1646          * queue size.
1647          */
1648         if(ptime.rate.denom > 0 && (ptime.avail_buffers || ptime.queued_buffers) && updatesize > 0)
1649         {
1650             const uint totalbuffers{ptime.avail_buffers + ptime.queued_buffers};
1651
1652             /* Ensure the delay is in sample frames. */
1653             const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->Frequency *
1654                 ptime.rate.num / ptime.rate.denom};
1655
1656             mDevice->UpdateSize = updatesize;
1657             mDevice->BufferSize = static_cast<uint>(ptime.buffered + delay +
1658                 totalbuffers*updatesize);
1659             break;
1660         }
1661 #else
1662         /* Prior to 0.3.50, we can only measure the delay with the update size,
1663          * assuming one buffer and no resample buffering.
1664          */
1665         if(ptime.rate.denom > 0 && updatesize > 0)
1666         {
1667             /* Ensure the delay is in sample frames. */
1668             const uint64_t delay{static_cast<uint64_t>(ptime.delay) * mDevice->Frequency *
1669                 ptime.rate.num / ptime.rate.denom};
1670
1671             mDevice->UpdateSize = updatesize;
1672             mDevice->BufferSize = static_cast<uint>(delay + updatesize);
1673             break;
1674         }
1675 #endif
1676         if(!--wait_count)
1677             break;
1678
1679         plock.unlock();
1680         std::this_thread::sleep_for(milliseconds{20});
1681         plock.lock();
1682     } while(pw_stream_get_state(mStream.get(), nullptr) == PW_STREAM_STATE_STREAMING);
1683 }
1684
1685 void PipeWirePlayback::stop()
1686 {
1687     MainloopUniqueLock plock{mLoop};
1688     if(int res{pw_stream_set_active(mStream.get(), false)})
1689         throw al::backend_exception{al::backend_error::DeviceError,
1690             "Failed to stop PipeWire stream (res: %d)", res};
1691
1692     /* Wait for the stream to stop playing. */
1693     plock.wait([stream=mStream.get()]()
1694     { return pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING; });
1695 }
1696
1697 ClockLatency PipeWirePlayback::getClockLatency()
1698 {
1699     /* Given a real-time low-latency output, this is rather complicated to get
1700      * accurate timing. So, here we go.
1701      */
1702
1703     /* First, get the stream time info (tick delay, ticks played, and the
1704      * CLOCK_MONOTONIC time closest to when that last tick was played).
1705      */
1706     pw_time ptime{};
1707     if(mStream)
1708     {
1709         MainloopLockGuard _{mLoop};
1710         if(int res{pw_stream_get_time_n(mStream.get(), &ptime, sizeof(ptime))})
1711             ERR("Failed to get PipeWire stream time (res: %d)\n", res);
1712     }
1713
1714     /* Now get the mixer time and the CLOCK_MONOTONIC time atomically (i.e. the
1715      * monotonic clock closest to 'now', and the last mixer time at 'now').
1716      */
1717     nanoseconds mixtime{};
1718     timespec tspec{};
1719     uint refcount;
1720     do {
1721         refcount = mDevice->waitForMix();
1722         mixtime = GetDeviceClockTime(mDevice);
1723         clock_gettime(CLOCK_MONOTONIC, &tspec);
1724         std::atomic_thread_fence(std::memory_order_acquire);
1725     } while(refcount != ReadRef(mDevice->MixCount));
1726
1727     /* Convert the monotonic clock, stream ticks, and stream delay to
1728      * nanoseconds.
1729      */
1730     nanoseconds monoclock{seconds{tspec.tv_sec} + nanoseconds{tspec.tv_nsec}};
1731     nanoseconds curtic{}, delay{};
1732     if(ptime.rate.denom < 1) UNLIKELY
1733     {
1734         /* If there's no stream rate, the stream hasn't had a chance to get
1735          * going and return time info yet. Just use dummy values.
1736          */
1737         ptime.now = monoclock.count();
1738         curtic = mixtime;
1739         delay = nanoseconds{seconds{mDevice->BufferSize}} / mDevice->Frequency;
1740     }
1741     else
1742     {
1743         /* The stream gets recreated with each reset, so include the time that
1744          * had already passed with previous streams.
1745          */
1746         curtic = mTimeBase;
1747         /* More safely scale the ticks to avoid overflowing the pre-division
1748          * temporary as it gets larger.
1749          */
1750         curtic += seconds{ptime.ticks / ptime.rate.denom} * ptime.rate.num;
1751         curtic += nanoseconds{seconds{ptime.ticks%ptime.rate.denom} * ptime.rate.num} /
1752             ptime.rate.denom;
1753
1754         /* The delay should be small enough to not worry about overflow. */
1755         delay = nanoseconds{seconds{ptime.delay} * ptime.rate.num} / ptime.rate.denom;
1756     }
1757
1758     /* If the mixer time is ahead of the stream time, there's that much more
1759      * delay relative to the stream delay.
1760      */
1761     if(mixtime > curtic)
1762         delay += mixtime - curtic;
1763     /* Reduce the delay according to how much time has passed since the known
1764      * stream time. This isn't 100% accurate since the system monotonic clock
1765      * doesn't tick at the exact same rate as the audio device, but it should
1766      * be good enough with ptime.now being constantly updated every few
1767      * milliseconds with ptime.ticks.
1768      */
1769     delay -= monoclock - nanoseconds{ptime.now};
1770
1771     /* Return the mixer time and delay. Clamp the delay to no less than 0,
1772      * incase timer drift got that severe.
1773      */
1774     ClockLatency ret{};
1775     ret.ClockTime = mixtime;
1776     ret.Latency = std::max(delay, nanoseconds{});
1777
1778     return ret;
1779 }
1780
1781
1782 class PipeWireCapture final : public BackendBase {
1783     void stateChangedCallback(pw_stream_state old, pw_stream_state state, const char *error);
1784     static void stateChangedCallbackC(void *data, pw_stream_state old, pw_stream_state state,
1785         const char *error)
1786     { static_cast<PipeWireCapture*>(data)->stateChangedCallback(old, state, error); }
1787
1788     void inputCallback();
1789     static void inputCallbackC(void *data)
1790     { static_cast<PipeWireCapture*>(data)->inputCallback(); }
1791
1792     void open(const char *name) override;
1793     void start() override;
1794     void stop() override;
1795     void captureSamples(al::byte *buffer, uint samples) override;
1796     uint availableSamples() override;
1797
1798     uint64_t mTargetId{PwIdAny};
1799     ThreadMainloop mLoop;
1800     PwContextPtr mContext;
1801     PwCorePtr mCore;
1802     PwStreamPtr mStream;
1803     spa_hook mStreamListener{};
1804
1805     RingBufferPtr mRing{};
1806
1807     static constexpr pw_stream_events CreateEvents()
1808     {
1809         pw_stream_events ret{};
1810         ret.version = PW_VERSION_STREAM_EVENTS;
1811         ret.state_changed = &PipeWireCapture::stateChangedCallbackC;
1812         ret.process = &PipeWireCapture::inputCallbackC;
1813         return ret;
1814     }
1815
1816 public:
1817     PipeWireCapture(DeviceBase *device) noexcept : BackendBase{device} { }
1818     ~PipeWireCapture() { if(mLoop) mLoop.stop(); }
1819
1820     DEF_NEWDEL(PipeWireCapture)
1821 };
1822
1823
1824 void PipeWireCapture::stateChangedCallback(pw_stream_state, pw_stream_state, const char*)
1825 { mLoop.signal(false); }
1826
1827 void PipeWireCapture::inputCallback()
1828 {
1829     pw_buffer *pw_buf{pw_stream_dequeue_buffer(mStream.get())};
1830     if(!pw_buf) UNLIKELY return;
1831
1832     spa_data *bufdata{pw_buf->buffer->datas};
1833     const uint offset{minu(bufdata->chunk->offset, bufdata->maxsize)};
1834     const uint size{minu(bufdata->chunk->size, bufdata->maxsize - offset)};
1835
1836     mRing->write(static_cast<char*>(bufdata->data) + offset, size / mRing->getElemSize());
1837
1838     pw_stream_queue_buffer(mStream.get(), pw_buf);
1839 }
1840
1841
1842 void PipeWireCapture::open(const char *name)
1843 {
1844     static std::atomic<uint> OpenCount{0};
1845
1846     uint64_t targetid{PwIdAny};
1847     std::string devname{};
1848     gEventHandler.waitForInit();
1849     if(!name)
1850     {
1851         EventWatcherLockGuard _{gEventHandler};
1852         auto&& devlist = DeviceNode::GetList();
1853
1854         auto match = devlist.cend();
1855         if(!DefaultSourceDevice.empty())
1856         {
1857             auto match_default = [](const DeviceNode &n) -> bool
1858             { return n.mDevName == DefaultSourceDevice; };
1859             match = std::find_if(devlist.cbegin(), devlist.cend(), match_default);
1860         }
1861         if(match == devlist.cend())
1862         {
1863             auto match_capture = [](const DeviceNode &n) -> bool
1864             { return n.mType != NodeType::Sink; };
1865             match = std::find_if(devlist.cbegin(), devlist.cend(), match_capture);
1866         }
1867         if(match == devlist.cend())
1868         {
1869             match = devlist.cbegin();
1870             if(match == devlist.cend())
1871                 throw al::backend_exception{al::backend_error::NoDevice,
1872                     "No PipeWire capture device found"};
1873         }
1874
1875         targetid = match->mSerial;
1876         if(match->mType != NodeType::Sink) devname = match->mName;
1877         else devname = MonitorPrefix+match->mName;
1878     }
1879     else
1880     {
1881         EventWatcherLockGuard _{gEventHandler};
1882         auto&& devlist = DeviceNode::GetList();
1883
1884         auto match_name = [name](const DeviceNode &n) -> bool
1885         { return n.mType != NodeType::Sink && n.mName == name; };
1886         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_name);
1887         if(match == devlist.cend() && std::strncmp(name, MonitorPrefix, MonitorPrefixLen) == 0)
1888         {
1889             const char *sinkname{name + MonitorPrefixLen};
1890             auto match_sinkname = [sinkname](const DeviceNode &n) -> bool
1891             { return n.mType == NodeType::Sink && n.mName == sinkname; };
1892             match = std::find_if(devlist.cbegin(), devlist.cend(), match_sinkname);
1893         }
1894         if(match == devlist.cend())
1895             throw al::backend_exception{al::backend_error::NoDevice,
1896                 "Device name \"%s\" not found", name};
1897
1898         targetid = match->mSerial;
1899         devname = name;
1900     }
1901
1902     if(!mLoop)
1903     {
1904         const uint count{OpenCount.fetch_add(1, std::memory_order_relaxed)};
1905         const std::string thread_name{"ALSoftC" + std::to_string(count)};
1906         mLoop = ThreadMainloop::Create(thread_name.c_str());
1907         if(!mLoop)
1908             throw al::backend_exception{al::backend_error::DeviceError,
1909                 "Failed to create PipeWire mainloop (errno: %d)", errno};
1910         if(int res{mLoop.start()})
1911             throw al::backend_exception{al::backend_error::DeviceError,
1912                 "Failed to start PipeWire mainloop (res: %d)", res};
1913     }
1914     MainloopUniqueLock mlock{mLoop};
1915     if(!mContext)
1916     {
1917         pw_properties *cprops{pw_properties_new(PW_KEY_CONFIG_NAME, "client-rt.conf", nullptr)};
1918         mContext = mLoop.newContext(cprops);
1919         if(!mContext)
1920             throw al::backend_exception{al::backend_error::DeviceError,
1921                 "Failed to create PipeWire event context (errno: %d)\n", errno};
1922     }
1923     if(!mCore)
1924     {
1925         mCore = PwCorePtr{pw_context_connect(mContext.get(), nullptr, 0)};
1926         if(!mCore)
1927             throw al::backend_exception{al::backend_error::DeviceError,
1928                 "Failed to connect PipeWire event context (errno: %d)\n", errno};
1929     }
1930     mlock.unlock();
1931
1932     /* TODO: Ensure the target ID is still valid/usable and accepts streams. */
1933
1934     mTargetId = targetid;
1935     if(!devname.empty())
1936         mDevice->DeviceName = std::move(devname);
1937     else
1938         mDevice->DeviceName = pwireInput;
1939
1940
1941     bool is51rear{false};
1942     if(mTargetId != PwIdAny)
1943     {
1944         EventWatcherLockGuard _{gEventHandler};
1945         auto&& devlist = DeviceNode::GetList();
1946
1947         auto match_id = [targetid=mTargetId](const DeviceNode &n) -> bool
1948         { return targetid == n.mSerial; };
1949         auto match = std::find_if(devlist.cbegin(), devlist.cend(), match_id);
1950         if(match != devlist.cend())
1951             is51rear = match->mIs51Rear;
1952     }
1953     spa_audio_info_raw info{make_spa_info(mDevice, is51rear, UseDevType)};
1954
1955     constexpr uint32_t pod_buffer_size{1024};
1956     auto pod_buffer = std::make_unique<al::byte[]>(pod_buffer_size);
1957     spa_pod_builder b{make_pod_builder(pod_buffer.get(), pod_buffer_size)};
1958
1959     const spa_pod *params[]{spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)};
1960     if(!params[0])
1961         throw al::backend_exception{al::backend_error::DeviceError,
1962             "Failed to set PipeWire audio format parameters"};
1963
1964     auto&& binary = GetProcBinary();
1965     const char *appname{binary.fname.length() ? binary.fname.c_str() : "OpenAL Soft"};
1966     pw_properties *props{pw_properties_new(
1967         PW_KEY_NODE_NAME, appname,
1968         PW_KEY_NODE_DESCRIPTION, appname,
1969         PW_KEY_MEDIA_TYPE, "Audio",
1970         PW_KEY_MEDIA_CATEGORY, "Capture",
1971         PW_KEY_MEDIA_ROLE, "Game",
1972         PW_KEY_NODE_ALWAYS_PROCESS, "true",
1973         nullptr)};
1974     if(!props)
1975         throw al::backend_exception{al::backend_error::DeviceError,
1976             "Failed to create PipeWire stream properties (errno: %d)", errno};
1977
1978     /* We don't actually care what the latency/update size is, as long as it's
1979      * reasonable. Unfortunately, when unspecified PipeWire seems to default to
1980      * around 40ms, which isn't great. So request 20ms instead.
1981      */
1982     pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", (mDevice->Frequency+25) / 50,
1983         mDevice->Frequency);
1984     pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", mDevice->Frequency);
1985 #ifdef PW_KEY_TARGET_OBJECT
1986     pw_properties_setf(props, PW_KEY_TARGET_OBJECT, "%" PRIu64, mTargetId);
1987 #else
1988     pw_properties_setf(props, PW_KEY_NODE_TARGET, "%" PRIu64, mTargetId);
1989 #endif
1990
1991     MainloopUniqueLock plock{mLoop};
1992     mStream = PwStreamPtr{pw_stream_new(mCore.get(), "Capture Stream", props)};
1993     if(!mStream)
1994         throw al::backend_exception{al::backend_error::NoDevice,
1995             "Failed to create PipeWire stream (errno: %d)", errno};
1996     static constexpr pw_stream_events streamEvents{CreateEvents()};
1997     pw_stream_add_listener(mStream.get(), &mStreamListener, &streamEvents, this);
1998
1999     constexpr pw_stream_flags Flags{PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE
2000         | PW_STREAM_FLAG_MAP_BUFFERS | PW_STREAM_FLAG_RT_PROCESS};
2001     if(int res{pw_stream_connect(mStream.get(), PW_DIRECTION_INPUT, PwIdAny, Flags, params, 1)})
2002         throw al::backend_exception{al::backend_error::DeviceError,
2003             "Error connecting PipeWire stream (res: %d)", res};
2004
2005     /* Wait for the stream to become paused (ready to start streaming). */
2006     plock.wait([stream=mStream.get()]()
2007     {
2008         const char *error{};
2009         pw_stream_state state{pw_stream_get_state(stream, &error)};
2010         if(state == PW_STREAM_STATE_ERROR)
2011             throw al::backend_exception{al::backend_error::DeviceError,
2012                 "Error connecting PipeWire stream: \"%s\"", error};
2013         return state == PW_STREAM_STATE_PAUSED;
2014     });
2015     plock.unlock();
2016
2017     setDefaultWFXChannelOrder();
2018
2019     /* Ensure at least a 100ms capture buffer. */
2020     mRing = RingBuffer::Create(maxu(mDevice->Frequency/10, mDevice->BufferSize),
2021         mDevice->frameSizeFromFmt(), false);
2022 }
2023
2024
2025 void PipeWireCapture::start()
2026 {
2027     MainloopUniqueLock plock{mLoop};
2028     if(int res{pw_stream_set_active(mStream.get(), true)})
2029         throw al::backend_exception{al::backend_error::DeviceError,
2030             "Failed to start PipeWire stream (res: %d)", res};
2031
2032     plock.wait([stream=mStream.get()]()
2033     {
2034         const char *error{};
2035         pw_stream_state state{pw_stream_get_state(stream, &error)};
2036         if(state == PW_STREAM_STATE_ERROR)
2037             throw al::backend_exception{al::backend_error::DeviceError,
2038                 "PipeWire stream error: %s", error ? error : "(unknown)"};
2039         return state == PW_STREAM_STATE_STREAMING;
2040     });
2041 }
2042
2043 void PipeWireCapture::stop()
2044 {
2045     MainloopUniqueLock plock{mLoop};
2046     if(int res{pw_stream_set_active(mStream.get(), false)})
2047         throw al::backend_exception{al::backend_error::DeviceError,
2048             "Failed to stop PipeWire stream (res: %d)", res};
2049
2050     plock.wait([stream=mStream.get()]()
2051     { return pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING; });
2052 }
2053
2054 uint PipeWireCapture::availableSamples()
2055 { return static_cast<uint>(mRing->readSpace()); }
2056
2057 void PipeWireCapture::captureSamples(al::byte *buffer, uint samples)
2058 { mRing->read(buffer, samples); }
2059
2060 } // namespace
2061
2062
2063 bool PipeWireBackendFactory::init()
2064 {
2065     if(!pwire_load())
2066         return false;
2067
2068     const char *version{pw_get_library_version()};
2069     if(!check_version(version))
2070     {
2071         WARN("PipeWire version \"%s\" too old (%s or newer required)\n", version,
2072             pw_get_headers_version());
2073         return false;
2074     }
2075     TRACE("Found PipeWire version \"%s\" (%s or newer)\n", version, pw_get_headers_version());
2076
2077     pw_init(0, nullptr);
2078     if(!gEventHandler.init())
2079         return false;
2080
2081     if(!GetConfigValueBool(nullptr, "pipewire", "assume-audio", false)
2082         && !gEventHandler.waitForAudio())
2083     {
2084         gEventHandler.kill();
2085         /* TODO: Temporary warning, until PipeWire gets a proper way to report
2086          * audio support.
2087          */
2088         WARN("No audio support detected in PipeWire. See the PipeWire options in alsoftrc.sample if this is wrong.\n");
2089         return false;
2090     }
2091     return true;
2092 }
2093
2094 bool PipeWireBackendFactory::querySupport(BackendType type)
2095 { return type == BackendType::Playback || type == BackendType::Capture; }
2096
2097 std::string PipeWireBackendFactory::probe(BackendType type)
2098 {
2099     std::string outnames;
2100
2101     gEventHandler.waitForInit();
2102     EventWatcherLockGuard _{gEventHandler};
2103     auto&& devlist = DeviceNode::GetList();
2104
2105     auto match_defsink = [](const DeviceNode &n) -> bool
2106     { return n.mDevName == DefaultSinkDevice; };
2107     auto match_defsource = [](const DeviceNode &n) -> bool
2108     { return n.mDevName == DefaultSourceDevice; };
2109
2110     auto sort_devnode = [](DeviceNode &lhs, DeviceNode &rhs) noexcept -> bool
2111     { return lhs.mId < rhs.mId; };
2112     std::sort(devlist.begin(), devlist.end(), sort_devnode);
2113
2114     auto defmatch = devlist.cbegin();
2115     switch(type)
2116     {
2117     case BackendType::Playback:
2118         defmatch = std::find_if(defmatch, devlist.cend(), match_defsink);
2119         if(defmatch != devlist.cend())
2120         {
2121             /* Includes null char. */
2122             outnames.append(defmatch->mName.c_str(), defmatch->mName.length()+1);
2123         }
2124         for(auto iter = devlist.cbegin();iter != devlist.cend();++iter)
2125         {
2126             if(iter != defmatch && iter->mType != NodeType::Source)
2127                 outnames.append(iter->mName.c_str(), iter->mName.length()+1);
2128         }
2129         break;
2130     case BackendType::Capture:
2131         defmatch = std::find_if(defmatch, devlist.cend(), match_defsource);
2132         if(defmatch != devlist.cend())
2133         {
2134             if(defmatch->mType == NodeType::Sink)
2135                 outnames.append(MonitorPrefix);
2136             outnames.append(defmatch->mName.c_str(), defmatch->mName.length()+1);
2137         }
2138         for(auto iter = devlist.cbegin();iter != devlist.cend();++iter)
2139         {
2140             if(iter != defmatch)
2141             {
2142                 if(iter->mType == NodeType::Sink)
2143                     outnames.append(MonitorPrefix);
2144                 outnames.append(iter->mName.c_str(), iter->mName.length()+1);
2145             }
2146         }
2147         break;
2148     }
2149
2150     return outnames;
2151 }
2152
2153 BackendPtr PipeWireBackendFactory::createBackend(DeviceBase *device, BackendType type)
2154 {
2155     if(type == BackendType::Playback)
2156         return BackendPtr{new PipeWirePlayback{device}};
2157     if(type == BackendType::Capture)
2158         return BackendPtr{new PipeWireCapture{device}};
2159     return nullptr;
2160 }
2161
2162 BackendFactory &PipeWireBackendFactory::getFactory()
2163 {
2164     static PipeWireBackendFactory factory{};
2165     return factory;
2166 }