🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2069 lines
71 KiB

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