pipewire.cpp 81 KB

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