🛠️🐜 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.

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