alsa.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  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 "alsa.h"
  22. #include <algorithm>
  23. #include <atomic>
  24. #include <cassert>
  25. #include <cerrno>
  26. #include <chrono>
  27. #include <cstring>
  28. #include <exception>
  29. #include <memory>
  30. #include <mutex>
  31. #include <string>
  32. #include <string_view>
  33. #include <thread>
  34. #include <utility>
  35. #include <vector>
  36. #include "alc/alconfig.h"
  37. #include "almalloc.h"
  38. #include "alnumeric.h"
  39. #include "althrd_setname.h"
  40. #include "core/device.h"
  41. #include "core/helpers.h"
  42. #include "core/logging.h"
  43. #include "dynload.h"
  44. #include "fmt/core.h"
  45. #include "ringbuffer.h"
  46. #include <alsa/asoundlib.h>
  47. namespace {
  48. using namespace std::string_view_literals;
  49. [[nodiscard]] constexpr auto GetDefaultName() noexcept { return "ALSA Default"sv; }
  50. #if HAVE_DYNLOAD
  51. #define ALSA_FUNCS(MAGIC) \
  52. MAGIC(snd_strerror); \
  53. MAGIC(snd_pcm_open); \
  54. MAGIC(snd_pcm_close); \
  55. MAGIC(snd_pcm_nonblock); \
  56. MAGIC(snd_pcm_frames_to_bytes); \
  57. MAGIC(snd_pcm_bytes_to_frames); \
  58. MAGIC(snd_pcm_hw_params_malloc); \
  59. MAGIC(snd_pcm_hw_params_free); \
  60. MAGIC(snd_pcm_hw_params_any); \
  61. MAGIC(snd_pcm_hw_params_current); \
  62. MAGIC(snd_pcm_hw_params_get_access); \
  63. MAGIC(snd_pcm_hw_params_get_buffer_size); \
  64. MAGIC(snd_pcm_hw_params_get_buffer_time_min); \
  65. MAGIC(snd_pcm_hw_params_get_buffer_time_max); \
  66. MAGIC(snd_pcm_hw_params_get_channels); \
  67. MAGIC(snd_pcm_hw_params_get_period_size); \
  68. MAGIC(snd_pcm_hw_params_get_period_time_max); \
  69. MAGIC(snd_pcm_hw_params_get_period_time_min); \
  70. MAGIC(snd_pcm_hw_params_get_periods); \
  71. MAGIC(snd_pcm_hw_params_set_access); \
  72. MAGIC(snd_pcm_hw_params_set_buffer_size_min); \
  73. MAGIC(snd_pcm_hw_params_set_buffer_size_near); \
  74. MAGIC(snd_pcm_hw_params_set_buffer_time_near); \
  75. MAGIC(snd_pcm_hw_params_set_channels); \
  76. MAGIC(snd_pcm_hw_params_set_channels_near); \
  77. MAGIC(snd_pcm_hw_params_set_format); \
  78. MAGIC(snd_pcm_hw_params_set_period_time_near); \
  79. MAGIC(snd_pcm_hw_params_set_period_size_near); \
  80. MAGIC(snd_pcm_hw_params_set_periods_near); \
  81. MAGIC(snd_pcm_hw_params_set_rate_near); \
  82. MAGIC(snd_pcm_hw_params_set_rate); \
  83. MAGIC(snd_pcm_hw_params_set_rate_resample); \
  84. MAGIC(snd_pcm_hw_params_test_format); \
  85. MAGIC(snd_pcm_hw_params_test_channels); \
  86. MAGIC(snd_pcm_hw_params); \
  87. MAGIC(snd_pcm_sw_params); \
  88. MAGIC(snd_pcm_sw_params_current); \
  89. MAGIC(snd_pcm_sw_params_free); \
  90. MAGIC(snd_pcm_sw_params_malloc); \
  91. MAGIC(snd_pcm_sw_params_set_avail_min); \
  92. MAGIC(snd_pcm_sw_params_set_stop_threshold); \
  93. MAGIC(snd_pcm_prepare); \
  94. MAGIC(snd_pcm_start); \
  95. MAGIC(snd_pcm_resume); \
  96. MAGIC(snd_pcm_reset); \
  97. MAGIC(snd_pcm_wait); \
  98. MAGIC(snd_pcm_delay); \
  99. MAGIC(snd_pcm_state); \
  100. MAGIC(snd_pcm_avail_update); \
  101. MAGIC(snd_pcm_mmap_begin); \
  102. MAGIC(snd_pcm_mmap_commit); \
  103. MAGIC(snd_pcm_readi); \
  104. MAGIC(snd_pcm_writei); \
  105. MAGIC(snd_pcm_drain); \
  106. MAGIC(snd_pcm_drop); \
  107. MAGIC(snd_pcm_recover); \
  108. MAGIC(snd_pcm_info_malloc); \
  109. MAGIC(snd_pcm_info_free); \
  110. MAGIC(snd_pcm_info_set_device); \
  111. MAGIC(snd_pcm_info_set_subdevice); \
  112. MAGIC(snd_pcm_info_set_stream); \
  113. MAGIC(snd_pcm_info_get_name); \
  114. MAGIC(snd_ctl_pcm_next_device); \
  115. MAGIC(snd_ctl_pcm_info); \
  116. MAGIC(snd_ctl_open); \
  117. MAGIC(snd_ctl_close); \
  118. MAGIC(snd_ctl_card_info_malloc); \
  119. MAGIC(snd_ctl_card_info_free); \
  120. MAGIC(snd_ctl_card_info); \
  121. MAGIC(snd_ctl_card_info_get_name); \
  122. MAGIC(snd_ctl_card_info_get_id); \
  123. MAGIC(snd_card_next); \
  124. MAGIC(snd_config_update_free_global)
  125. void *alsa_handle;
  126. #define MAKE_FUNC(f) decltype(f) * p##f
  127. ALSA_FUNCS(MAKE_FUNC);
  128. #undef MAKE_FUNC
  129. #ifndef IN_IDE_PARSER
  130. #define snd_strerror psnd_strerror
  131. #define snd_pcm_open psnd_pcm_open
  132. #define snd_pcm_close psnd_pcm_close
  133. #define snd_pcm_nonblock psnd_pcm_nonblock
  134. #define snd_pcm_frames_to_bytes psnd_pcm_frames_to_bytes
  135. #define snd_pcm_bytes_to_frames psnd_pcm_bytes_to_frames
  136. #define snd_pcm_hw_params_malloc psnd_pcm_hw_params_malloc
  137. #define snd_pcm_hw_params_free psnd_pcm_hw_params_free
  138. #define snd_pcm_hw_params_any psnd_pcm_hw_params_any
  139. #define snd_pcm_hw_params_current psnd_pcm_hw_params_current
  140. #define snd_pcm_hw_params_set_access psnd_pcm_hw_params_set_access
  141. #define snd_pcm_hw_params_set_format psnd_pcm_hw_params_set_format
  142. #define snd_pcm_hw_params_set_channels psnd_pcm_hw_params_set_channels
  143. #define snd_pcm_hw_params_set_channels_near psnd_pcm_hw_params_set_channels_near
  144. #define snd_pcm_hw_params_set_periods_near psnd_pcm_hw_params_set_periods_near
  145. #define snd_pcm_hw_params_set_rate_near psnd_pcm_hw_params_set_rate_near
  146. #define snd_pcm_hw_params_set_rate psnd_pcm_hw_params_set_rate
  147. #define snd_pcm_hw_params_set_rate_resample psnd_pcm_hw_params_set_rate_resample
  148. #define snd_pcm_hw_params_set_buffer_time_near psnd_pcm_hw_params_set_buffer_time_near
  149. #define snd_pcm_hw_params_set_period_time_near psnd_pcm_hw_params_set_period_time_near
  150. #define snd_pcm_hw_params_set_buffer_size_near psnd_pcm_hw_params_set_buffer_size_near
  151. #define snd_pcm_hw_params_set_period_size_near psnd_pcm_hw_params_set_period_size_near
  152. #define snd_pcm_hw_params_set_buffer_size_min psnd_pcm_hw_params_set_buffer_size_min
  153. #define snd_pcm_hw_params_get_buffer_time_min psnd_pcm_hw_params_get_buffer_time_min
  154. #define snd_pcm_hw_params_get_buffer_time_max psnd_pcm_hw_params_get_buffer_time_max
  155. #define snd_pcm_hw_params_get_period_time_min psnd_pcm_hw_params_get_period_time_min
  156. #define snd_pcm_hw_params_get_period_time_max psnd_pcm_hw_params_get_period_time_max
  157. #define snd_pcm_hw_params_get_buffer_size psnd_pcm_hw_params_get_buffer_size
  158. #define snd_pcm_hw_params_get_period_size psnd_pcm_hw_params_get_period_size
  159. #define snd_pcm_hw_params_get_access psnd_pcm_hw_params_get_access
  160. #define snd_pcm_hw_params_get_periods psnd_pcm_hw_params_get_periods
  161. #define snd_pcm_hw_params_get_channels psnd_pcm_hw_params_get_channels
  162. #define snd_pcm_hw_params_test_format psnd_pcm_hw_params_test_format
  163. #define snd_pcm_hw_params_test_channels psnd_pcm_hw_params_test_channels
  164. #define snd_pcm_hw_params psnd_pcm_hw_params
  165. #define snd_pcm_sw_params_malloc psnd_pcm_sw_params_malloc
  166. #define snd_pcm_sw_params_current psnd_pcm_sw_params_current
  167. #define snd_pcm_sw_params_set_avail_min psnd_pcm_sw_params_set_avail_min
  168. #define snd_pcm_sw_params_set_stop_threshold psnd_pcm_sw_params_set_stop_threshold
  169. #define snd_pcm_sw_params psnd_pcm_sw_params
  170. #define snd_pcm_sw_params_free psnd_pcm_sw_params_free
  171. #define snd_pcm_prepare psnd_pcm_prepare
  172. #define snd_pcm_start psnd_pcm_start
  173. #define snd_pcm_resume psnd_pcm_resume
  174. #define snd_pcm_reset psnd_pcm_reset
  175. #define snd_pcm_wait psnd_pcm_wait
  176. #define snd_pcm_delay psnd_pcm_delay
  177. #define snd_pcm_state psnd_pcm_state
  178. #define snd_pcm_avail_update psnd_pcm_avail_update
  179. #define snd_pcm_mmap_begin psnd_pcm_mmap_begin
  180. #define snd_pcm_mmap_commit psnd_pcm_mmap_commit
  181. #define snd_pcm_readi psnd_pcm_readi
  182. #define snd_pcm_writei psnd_pcm_writei
  183. #define snd_pcm_drain psnd_pcm_drain
  184. #define snd_pcm_drop psnd_pcm_drop
  185. #define snd_pcm_recover psnd_pcm_recover
  186. #define snd_pcm_info_malloc psnd_pcm_info_malloc
  187. #define snd_pcm_info_free psnd_pcm_info_free
  188. #define snd_pcm_info_set_device psnd_pcm_info_set_device
  189. #define snd_pcm_info_set_subdevice psnd_pcm_info_set_subdevice
  190. #define snd_pcm_info_set_stream psnd_pcm_info_set_stream
  191. #define snd_pcm_info_get_name psnd_pcm_info_get_name
  192. #define snd_ctl_pcm_next_device psnd_ctl_pcm_next_device
  193. #define snd_ctl_pcm_info psnd_ctl_pcm_info
  194. #define snd_ctl_open psnd_ctl_open
  195. #define snd_ctl_close psnd_ctl_close
  196. #define snd_ctl_card_info_malloc psnd_ctl_card_info_malloc
  197. #define snd_ctl_card_info_free psnd_ctl_card_info_free
  198. #define snd_ctl_card_info psnd_ctl_card_info
  199. #define snd_ctl_card_info_get_name psnd_ctl_card_info_get_name
  200. #define snd_ctl_card_info_get_id psnd_ctl_card_info_get_id
  201. #define snd_card_next psnd_card_next
  202. #define snd_config_update_free_global psnd_config_update_free_global
  203. #endif
  204. #endif
  205. struct HwParamsDeleter {
  206. void operator()(snd_pcm_hw_params_t *ptr) { snd_pcm_hw_params_free(ptr); }
  207. };
  208. using HwParamsPtr = std::unique_ptr<snd_pcm_hw_params_t,HwParamsDeleter>;
  209. HwParamsPtr CreateHwParams()
  210. {
  211. snd_pcm_hw_params_t *hp{};
  212. snd_pcm_hw_params_malloc(&hp);
  213. return HwParamsPtr{hp};
  214. }
  215. struct SwParamsDeleter {
  216. void operator()(snd_pcm_sw_params_t *ptr) { snd_pcm_sw_params_free(ptr); }
  217. };
  218. using SwParamsPtr = std::unique_ptr<snd_pcm_sw_params_t,SwParamsDeleter>;
  219. SwParamsPtr CreateSwParams()
  220. {
  221. snd_pcm_sw_params_t *sp{};
  222. snd_pcm_sw_params_malloc(&sp);
  223. return SwParamsPtr{sp};
  224. }
  225. struct DevMap {
  226. std::string name;
  227. std::string device_name;
  228. template<typename T, typename U>
  229. DevMap(T&& name_, U&& devname)
  230. : name{std::forward<T>(name_)}, device_name{std::forward<U>(devname)}
  231. { }
  232. };
  233. std::vector<DevMap> PlaybackDevices;
  234. std::vector<DevMap> CaptureDevices;
  235. std::string_view prefix_name(snd_pcm_stream_t stream) noexcept
  236. {
  237. if(stream == SND_PCM_STREAM_PLAYBACK)
  238. return "device-prefix"sv;
  239. return "capture-prefix"sv;
  240. }
  241. struct SndCtlCardInfo {
  242. snd_ctl_card_info_t *mInfo{};
  243. SndCtlCardInfo() { snd_ctl_card_info_malloc(&mInfo); }
  244. ~SndCtlCardInfo() { if(mInfo) snd_ctl_card_info_free(mInfo); }
  245. SndCtlCardInfo(const SndCtlCardInfo&) = delete;
  246. SndCtlCardInfo& operator=(const SndCtlCardInfo&) = delete;
  247. [[nodiscard]]
  248. operator snd_ctl_card_info_t*() const noexcept { return mInfo; } /* NOLINT(google-explicit-constructor) */
  249. };
  250. struct SndPcmInfo {
  251. snd_pcm_info_t *mInfo{};
  252. SndPcmInfo() { snd_pcm_info_malloc(&mInfo); }
  253. ~SndPcmInfo() { if(mInfo) snd_pcm_info_free(mInfo); }
  254. SndPcmInfo(const SndPcmInfo&) = delete;
  255. SndPcmInfo& operator=(const SndPcmInfo&) = delete;
  256. [[nodiscard]]
  257. operator snd_pcm_info_t*() const noexcept { return mInfo; } /* NOLINT(google-explicit-constructor) */
  258. };
  259. struct SndCtl {
  260. snd_ctl_t *mHandle{};
  261. SndCtl() = default;
  262. ~SndCtl() { if(mHandle) snd_ctl_close(mHandle); }
  263. SndCtl(const SndCtl&) = delete;
  264. SndCtl& operator=(const SndCtl&) = delete;
  265. [[nodiscard]]
  266. auto open(const char *name, int mode) { return snd_ctl_open(&mHandle, name, mode); }
  267. [[nodiscard]]
  268. operator snd_ctl_t*() const noexcept { return mHandle; } /* NOLINT(google-explicit-constructor) */
  269. };
  270. std::vector<DevMap> probe_devices(snd_pcm_stream_t stream)
  271. {
  272. std::vector<DevMap> devlist;
  273. SndCtlCardInfo info;
  274. SndPcmInfo pcminfo;
  275. auto defname = ConfigValueStr({}, "alsa"sv,
  276. (stream == SND_PCM_STREAM_PLAYBACK) ? "device"sv : "capture"sv);
  277. devlist.emplace_back(GetDefaultName(), defname ? std::string_view{*defname} : "default"sv);
  278. if(auto customdevs = ConfigValueStr({}, "alsa"sv,
  279. (stream == SND_PCM_STREAM_PLAYBACK) ? "custom-devices"sv : "custom-captures"sv))
  280. {
  281. size_t curpos{customdevs->find_first_not_of(';')};
  282. while(curpos < customdevs->length())
  283. {
  284. size_t nextpos{customdevs->find(';', curpos+1)};
  285. const size_t seppos{customdevs->find('=', curpos)};
  286. if(seppos == curpos || seppos >= nextpos)
  287. {
  288. const auto spec = std::string_view{*customdevs}.substr(curpos, nextpos-curpos);
  289. ERR("Invalid ALSA device specification \"{}\"", spec);
  290. }
  291. else
  292. {
  293. const std::string_view strview{*customdevs};
  294. const auto &entry = devlist.emplace_back(strview.substr(curpos, seppos-curpos),
  295. strview.substr(seppos+1, nextpos-seppos-1));
  296. TRACE("Got device \"{}\", \"{}\"", entry.name, entry.device_name);
  297. }
  298. if(nextpos < customdevs->length())
  299. nextpos = customdevs->find_first_not_of(';', nextpos+1);
  300. curpos = nextpos;
  301. }
  302. }
  303. const std::string main_prefix{ConfigValueStr({}, "alsa"sv, prefix_name(stream))
  304. .value_or("plughw:")};
  305. int card{-1};
  306. int err{snd_card_next(&card)};
  307. for(;err >= 0 && card >= 0;err = snd_card_next(&card))
  308. {
  309. std::string name{"hw:" + std::to_string(card)};
  310. SndCtl handle;
  311. err = handle.open(name.c_str(), 0);
  312. if(err < 0)
  313. {
  314. ERR("control open (hw:{}): {}", card, snd_strerror(err));
  315. continue;
  316. }
  317. err = snd_ctl_card_info(handle, info);
  318. if(err < 0)
  319. {
  320. ERR("control hardware info (hw:{}): {}", card, snd_strerror(err));
  321. continue;
  322. }
  323. const char *cardname{snd_ctl_card_info_get_name(info)};
  324. const char *cardid{snd_ctl_card_info_get_id(info)};
  325. name = prefix_name(stream);
  326. name += '-';
  327. name += cardid;
  328. const std::string card_prefix{ConfigValueStr({}, "alsa"sv, name).value_or(main_prefix)};
  329. int dev{-1};
  330. while(true)
  331. {
  332. if(snd_ctl_pcm_next_device(handle, &dev) < 0)
  333. ERR("snd_ctl_pcm_next_device failed");
  334. if(dev < 0) break;
  335. snd_pcm_info_set_device(pcminfo, static_cast<uint>(dev));
  336. snd_pcm_info_set_subdevice(pcminfo, 0);
  337. snd_pcm_info_set_stream(pcminfo, stream);
  338. err = snd_ctl_pcm_info(handle, pcminfo);
  339. if(err < 0)
  340. {
  341. if(err != -ENOENT)
  342. ERR("control digital audio info (hw:{}): {}", card, snd_strerror(err));
  343. continue;
  344. }
  345. /* "prefix-cardid-dev" */
  346. name = fmt::format("{}-{}-{}", prefix_name(stream), cardid, dev);
  347. const auto device_prefix = std::string{ConfigValueStr({}, "alsa"sv, name)
  348. .value_or(card_prefix)};
  349. /* "CardName, PcmName (CARD=cardid,DEV=dev)" */
  350. name = fmt::format("{}, {} (CARD={},DEV={})", cardname, snd_pcm_info_get_name(pcminfo),
  351. cardid, dev);
  352. /* "devprefixCARD=cardid,DEV=dev" */
  353. auto device = fmt::format("{}CARD={},DEV={}", device_prefix, cardid, dev);
  354. const auto &entry = devlist.emplace_back(std::move(name), std::move(device));
  355. TRACE("Got device \"{}\", \"{}\"", entry.name, entry.device_name);
  356. }
  357. }
  358. if(err < 0)
  359. ERR("snd_card_next failed: {}", snd_strerror(err));
  360. return devlist;
  361. }
  362. int verify_state(snd_pcm_t *handle)
  363. {
  364. snd_pcm_state_t state{snd_pcm_state(handle)};
  365. switch(state)
  366. {
  367. case SND_PCM_STATE_OPEN:
  368. case SND_PCM_STATE_SETUP:
  369. case SND_PCM_STATE_PREPARED:
  370. case SND_PCM_STATE_RUNNING:
  371. case SND_PCM_STATE_DRAINING:
  372. case SND_PCM_STATE_PAUSED:
  373. /* All Okay */
  374. break;
  375. case SND_PCM_STATE_XRUN:
  376. if(int err{snd_pcm_recover(handle, -EPIPE, 1)}; err < 0)
  377. return err;
  378. break;
  379. case SND_PCM_STATE_SUSPENDED:
  380. if(int err{snd_pcm_recover(handle, -ESTRPIPE, 1)}; err < 0)
  381. return err;
  382. break;
  383. case SND_PCM_STATE_DISCONNECTED:
  384. return -ENODEV;
  385. /* ALSA headers have made this enum public, leaving us in a bind: use
  386. * the enum despite being private and internal to the libasound, or
  387. * ignore when an enum value isn't handled. We can't rely on it being
  388. * declared either, since older headers don't have it and it could be
  389. * removed in the future. We can't even really rely on its value, since
  390. * being private/internal means it's subject to change, but this is the
  391. * best we can do.
  392. */
  393. case 1024 /*SND_PCM_STATE_PRIVATE1*/:
  394. assert(state != 1024);
  395. }
  396. return state;
  397. }
  398. struct AlsaPlayback final : public BackendBase {
  399. explicit AlsaPlayback(DeviceBase *device) noexcept : BackendBase{device} { }
  400. ~AlsaPlayback() override;
  401. int mixerProc();
  402. int mixerNoMMapProc();
  403. void open(std::string_view name) override;
  404. bool reset() override;
  405. void start() override;
  406. void stop() override;
  407. ClockLatency getClockLatency() override;
  408. snd_pcm_t *mPcmHandle{nullptr};
  409. std::mutex mMutex;
  410. uint mFrameStep{};
  411. std::vector<std::byte> mBuffer;
  412. std::atomic<bool> mKillNow{true};
  413. std::thread mThread;
  414. };
  415. AlsaPlayback::~AlsaPlayback()
  416. {
  417. if(mPcmHandle)
  418. snd_pcm_close(mPcmHandle);
  419. mPcmHandle = nullptr;
  420. }
  421. int AlsaPlayback::mixerProc()
  422. {
  423. SetRTPriority();
  424. althrd_setname(GetMixerThreadName());
  425. const snd_pcm_uframes_t update_size{mDevice->mUpdateSize};
  426. const snd_pcm_uframes_t buffer_size{mDevice->mBufferSize};
  427. while(!mKillNow.load(std::memory_order_acquire))
  428. {
  429. int state{verify_state(mPcmHandle)};
  430. if(state < 0)
  431. {
  432. ERR("Invalid state detected: {}", snd_strerror(state));
  433. mDevice->handleDisconnect("Bad state: {}", snd_strerror(state));
  434. break;
  435. }
  436. snd_pcm_sframes_t avails{snd_pcm_avail_update(mPcmHandle)};
  437. if(avails < 0)
  438. {
  439. ERR("available update failed: {}", snd_strerror(static_cast<int>(avails)));
  440. continue;
  441. }
  442. snd_pcm_uframes_t avail{static_cast<snd_pcm_uframes_t>(avails)};
  443. if(avail > buffer_size)
  444. {
  445. WARN("available samples exceeds the buffer size");
  446. snd_pcm_reset(mPcmHandle);
  447. continue;
  448. }
  449. // make sure there's frames to process
  450. if(avail < update_size)
  451. {
  452. if(state != SND_PCM_STATE_RUNNING)
  453. {
  454. int err{snd_pcm_start(mPcmHandle)};
  455. if(err < 0)
  456. {
  457. ERR("start failed: {}", snd_strerror(err));
  458. continue;
  459. }
  460. }
  461. if(snd_pcm_wait(mPcmHandle, 1000) == 0)
  462. ERR("Wait timeout... buffer size too low?");
  463. continue;
  464. }
  465. avail -= avail%update_size;
  466. // it is possible that contiguous areas are smaller, thus we use a loop
  467. std::lock_guard<std::mutex> dlock{mMutex};
  468. while(avail > 0)
  469. {
  470. snd_pcm_uframes_t frames{avail};
  471. const snd_pcm_channel_area_t *areas{};
  472. snd_pcm_uframes_t offset{};
  473. int err{snd_pcm_mmap_begin(mPcmHandle, &areas, &offset, &frames)};
  474. if(err < 0)
  475. {
  476. ERR("mmap begin error: {}", snd_strerror(err));
  477. break;
  478. }
  479. /* NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
  480. char *WritePtr{static_cast<char*>(areas->addr) + (offset * areas->step / 8)};
  481. mDevice->renderSamples(WritePtr, static_cast<uint>(frames), mFrameStep);
  482. snd_pcm_sframes_t commitres{snd_pcm_mmap_commit(mPcmHandle, offset, frames)};
  483. if(commitres < 0 || static_cast<snd_pcm_uframes_t>(commitres) != frames)
  484. {
  485. ERR("mmap commit error: {}",
  486. snd_strerror(commitres >= 0 ? -EPIPE : static_cast<int>(commitres)));
  487. break;
  488. }
  489. avail -= frames;
  490. }
  491. }
  492. return 0;
  493. }
  494. int AlsaPlayback::mixerNoMMapProc()
  495. {
  496. SetRTPriority();
  497. althrd_setname(GetMixerThreadName());
  498. const snd_pcm_uframes_t update_size{mDevice->mUpdateSize};
  499. const snd_pcm_uframes_t buffer_size{mDevice->mBufferSize};
  500. while(!mKillNow.load(std::memory_order_acquire))
  501. {
  502. int state{verify_state(mPcmHandle)};
  503. if(state < 0)
  504. {
  505. ERR("Invalid state detected: {}", snd_strerror(state));
  506. mDevice->handleDisconnect("Bad state: {}", snd_strerror(state));
  507. break;
  508. }
  509. snd_pcm_sframes_t avail{snd_pcm_avail_update(mPcmHandle)};
  510. if(avail < 0)
  511. {
  512. ERR("available update failed: {}", snd_strerror(static_cast<int>(avail)));
  513. continue;
  514. }
  515. if(static_cast<snd_pcm_uframes_t>(avail) > buffer_size)
  516. {
  517. WARN("available samples exceeds the buffer size");
  518. snd_pcm_reset(mPcmHandle);
  519. continue;
  520. }
  521. if(static_cast<snd_pcm_uframes_t>(avail) < update_size)
  522. {
  523. if(state != SND_PCM_STATE_RUNNING)
  524. {
  525. int err{snd_pcm_start(mPcmHandle)};
  526. if(err < 0)
  527. {
  528. ERR("start failed: {}", snd_strerror(err));
  529. continue;
  530. }
  531. }
  532. if(snd_pcm_wait(mPcmHandle, 1000) == 0)
  533. ERR("Wait timeout... buffer size too low?");
  534. continue;
  535. }
  536. auto WritePtr = mBuffer.begin();
  537. avail = snd_pcm_bytes_to_frames(mPcmHandle, static_cast<ssize_t>(mBuffer.size()));
  538. std::lock_guard<std::mutex> dlock{mMutex};
  539. mDevice->renderSamples(al::to_address(WritePtr), static_cast<uint>(avail), mFrameStep);
  540. while(avail > 0)
  541. {
  542. snd_pcm_sframes_t ret{snd_pcm_writei(mPcmHandle, al::to_address(WritePtr),
  543. static_cast<snd_pcm_uframes_t>(avail))};
  544. switch(ret)
  545. {
  546. case -EAGAIN:
  547. continue;
  548. #if ESTRPIPE != EPIPE
  549. case -ESTRPIPE:
  550. #endif
  551. case -EPIPE:
  552. case -EINTR:
  553. ret = snd_pcm_recover(mPcmHandle, static_cast<int>(ret), 1);
  554. if(ret < 0)
  555. avail = 0;
  556. break;
  557. default:
  558. if(ret >= 0)
  559. {
  560. WritePtr += snd_pcm_frames_to_bytes(mPcmHandle, ret);
  561. avail -= ret;
  562. }
  563. break;
  564. }
  565. if(ret < 0)
  566. {
  567. ret = snd_pcm_prepare(mPcmHandle);
  568. if(ret < 0) break;
  569. }
  570. }
  571. }
  572. return 0;
  573. }
  574. void AlsaPlayback::open(std::string_view name)
  575. {
  576. std::string driver{"default"};
  577. if(!name.empty())
  578. {
  579. if(PlaybackDevices.empty())
  580. PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK);
  581. auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
  582. [name](const DevMap &entry) -> bool { return entry.name == name; });
  583. if(iter == PlaybackDevices.cend())
  584. throw al::backend_exception{al::backend_error::NoDevice,
  585. "Device name \"{}\" not found", name};
  586. driver = iter->device_name;
  587. }
  588. else
  589. {
  590. name = GetDefaultName();
  591. if(auto driveropt = ConfigValueStr({}, "alsa"sv, "device"sv))
  592. driver = std::move(driveropt).value();
  593. }
  594. TRACE("Opening device \"{}\"", driver);
  595. snd_pcm_t *pcmHandle{};
  596. int err{snd_pcm_open(&pcmHandle, driver.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)};
  597. if(err < 0)
  598. throw al::backend_exception{al::backend_error::NoDevice,
  599. "Could not open ALSA device \"{}\"", driver};
  600. if(mPcmHandle)
  601. snd_pcm_close(mPcmHandle);
  602. mPcmHandle = pcmHandle;
  603. /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
  604. snd_config_update_free_global();
  605. mDeviceName = name;
  606. }
  607. bool AlsaPlayback::reset()
  608. {
  609. snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN};
  610. switch(mDevice->FmtType)
  611. {
  612. case DevFmtByte:
  613. format = SND_PCM_FORMAT_S8;
  614. break;
  615. case DevFmtUByte:
  616. format = SND_PCM_FORMAT_U8;
  617. break;
  618. case DevFmtShort:
  619. format = SND_PCM_FORMAT_S16;
  620. break;
  621. case DevFmtUShort:
  622. format = SND_PCM_FORMAT_U16;
  623. break;
  624. case DevFmtInt:
  625. format = SND_PCM_FORMAT_S32;
  626. break;
  627. case DevFmtUInt:
  628. format = SND_PCM_FORMAT_U32;
  629. break;
  630. case DevFmtFloat:
  631. format = SND_PCM_FORMAT_FLOAT;
  632. break;
  633. }
  634. bool allowmmap{GetConfigValueBool(mDevice->mDeviceName, "alsa"sv, "mmap"sv, true)};
  635. uint periodLen{static_cast<uint>(mDevice->mUpdateSize * 1000000_u64 / mDevice->mSampleRate)};
  636. uint bufferLen{static_cast<uint>(mDevice->mBufferSize * 1000000_u64 / mDevice->mSampleRate)};
  637. uint rate{mDevice->mSampleRate};
  638. HwParamsPtr hp{CreateHwParams()};
  639. #define CHECK(x) do { \
  640. if(int err{x}; err < 0) \
  641. throw al::backend_exception{al::backend_error::DeviceError, #x " failed: {}", \
  642. snd_strerror(err)}; \
  643. } while(0)
  644. CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get()));
  645. /* set interleaved access */
  646. if(!allowmmap
  647. || snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
  648. {
  649. /* No mmap */
  650. CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED));
  651. }
  652. /* test and set format (implicitly sets sample bits) */
  653. if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) < 0)
  654. {
  655. struct FormatMap {
  656. snd_pcm_format_t format;
  657. DevFmtType fmttype;
  658. };
  659. static constexpr std::array formatlist{
  660. FormatMap{SND_PCM_FORMAT_FLOAT, DevFmtFloat },
  661. FormatMap{SND_PCM_FORMAT_S32, DevFmtInt },
  662. FormatMap{SND_PCM_FORMAT_U32, DevFmtUInt },
  663. FormatMap{SND_PCM_FORMAT_S16, DevFmtShort },
  664. FormatMap{SND_PCM_FORMAT_U16, DevFmtUShort},
  665. FormatMap{SND_PCM_FORMAT_S8, DevFmtByte },
  666. FormatMap{SND_PCM_FORMAT_U8, DevFmtUByte },
  667. };
  668. for(const auto &fmt : formatlist)
  669. {
  670. format = fmt.format;
  671. if(snd_pcm_hw_params_test_format(mPcmHandle, hp.get(), format) >= 0)
  672. {
  673. mDevice->FmtType = fmt.fmttype;
  674. break;
  675. }
  676. }
  677. }
  678. CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format));
  679. /* set channels (implicitly sets frame bits) */
  680. if(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt()) < 0)
  681. {
  682. uint numchans{2u};
  683. CHECK(snd_pcm_hw_params_set_channels_near(mPcmHandle, hp.get(), &numchans));
  684. if(numchans < 1)
  685. throw al::backend_exception{al::backend_error::DeviceError, "Got 0 device channels"};
  686. if(numchans == 1) mDevice->FmtChans = DevFmtMono;
  687. else mDevice->FmtChans = DevFmtStereo;
  688. }
  689. /* set rate (implicitly constrains period/buffer parameters) */
  690. if(!GetConfigValueBool(mDevice->mDeviceName, "alsa", "allow-resampler", false)
  691. || !mDevice->Flags.test(FrequencyRequest))
  692. {
  693. if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 0) < 0)
  694. WARN("Failed to disable ALSA resampler");
  695. }
  696. else if(snd_pcm_hw_params_set_rate_resample(mPcmHandle, hp.get(), 1) < 0)
  697. WARN("Failed to enable ALSA resampler");
  698. CHECK(snd_pcm_hw_params_set_rate_near(mPcmHandle, hp.get(), &rate, nullptr));
  699. /* set period time (implicitly constrains period/buffer parameters) */
  700. if(int err{snd_pcm_hw_params_set_period_time_near(mPcmHandle, hp.get(), &periodLen, nullptr)}; err < 0)
  701. ERR("snd_pcm_hw_params_set_period_time_near failed: {}", snd_strerror(err));
  702. /* set buffer time (implicitly sets buffer size/bytes/time and period size/bytes) */
  703. if(int err{snd_pcm_hw_params_set_buffer_time_near(mPcmHandle, hp.get(), &bufferLen, nullptr)}; err < 0)
  704. ERR("snd_pcm_hw_params_set_buffer_time_near failed: {}", snd_strerror(err));
  705. /* install and prepare hardware configuration */
  706. CHECK(snd_pcm_hw_params(mPcmHandle, hp.get()));
  707. /* retrieve configuration info */
  708. snd_pcm_uframes_t periodSizeInFrames{};
  709. snd_pcm_uframes_t bufferSizeInFrames{};
  710. snd_pcm_access_t access{};
  711. CHECK(snd_pcm_hw_params_get_access(hp.get(), &access));
  712. CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr));
  713. CHECK(snd_pcm_hw_params_get_buffer_size(hp.get(), &bufferSizeInFrames));
  714. CHECK(snd_pcm_hw_params_get_channels(hp.get(), &mFrameStep));
  715. hp = nullptr;
  716. SwParamsPtr sp{CreateSwParams()};
  717. CHECK(snd_pcm_sw_params_current(mPcmHandle, sp.get()));
  718. CHECK(snd_pcm_sw_params_set_avail_min(mPcmHandle, sp.get(), periodSizeInFrames));
  719. CHECK(snd_pcm_sw_params_set_stop_threshold(mPcmHandle, sp.get(), bufferSizeInFrames));
  720. CHECK(snd_pcm_sw_params(mPcmHandle, sp.get()));
  721. #undef CHECK
  722. sp = nullptr;
  723. mDevice->mBufferSize = static_cast<uint>(bufferSizeInFrames);
  724. mDevice->mUpdateSize = static_cast<uint>(periodSizeInFrames);
  725. mDevice->mSampleRate = rate;
  726. setDefaultChannelOrder();
  727. return true;
  728. }
  729. void AlsaPlayback::start()
  730. {
  731. snd_pcm_access_t access{};
  732. HwParamsPtr hp{CreateHwParams()};
  733. #define CHECK(x) do { \
  734. if(int err{x}; err < 0) \
  735. throw al::backend_exception{al::backend_error::DeviceError, #x " failed: {}", \
  736. snd_strerror(err)}; \
  737. } while(0)
  738. CHECK(snd_pcm_hw_params_current(mPcmHandle, hp.get()));
  739. /* retrieve configuration info */
  740. CHECK(snd_pcm_hw_params_get_access(hp.get(), &access));
  741. hp = nullptr;
  742. int (AlsaPlayback::*thread_func)(){};
  743. if(access == SND_PCM_ACCESS_RW_INTERLEAVED)
  744. {
  745. auto datalen = snd_pcm_frames_to_bytes(mPcmHandle, mDevice->mUpdateSize);
  746. mBuffer.resize(static_cast<size_t>(datalen));
  747. thread_func = &AlsaPlayback::mixerNoMMapProc;
  748. }
  749. else
  750. {
  751. CHECK(snd_pcm_prepare(mPcmHandle));
  752. thread_func = &AlsaPlayback::mixerProc;
  753. }
  754. #undef CHECK
  755. try {
  756. mKillNow.store(false, std::memory_order_release);
  757. mThread = std::thread{thread_func, this};
  758. }
  759. catch(std::exception& e) {
  760. throw al::backend_exception{al::backend_error::DeviceError,
  761. "Failed to start mixing thread: {}", e.what()};
  762. }
  763. }
  764. void AlsaPlayback::stop()
  765. {
  766. if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
  767. return;
  768. mThread.join();
  769. mBuffer.clear();
  770. int err{snd_pcm_drop(mPcmHandle)};
  771. if(err < 0)
  772. ERR("snd_pcm_drop failed: {}", snd_strerror(err));
  773. }
  774. ClockLatency AlsaPlayback::getClockLatency()
  775. {
  776. std::lock_guard<std::mutex> dlock{mMutex};
  777. ClockLatency ret{};
  778. ret.ClockTime = mDevice->getClockTime();
  779. snd_pcm_sframes_t delay{};
  780. int err{snd_pcm_delay(mPcmHandle, &delay)};
  781. if(err < 0)
  782. {
  783. ERR("Failed to get pcm delay: {}", snd_strerror(err));
  784. delay = 0;
  785. }
  786. ret.Latency = std::chrono::seconds{std::max<snd_pcm_sframes_t>(0, delay)};
  787. ret.Latency /= mDevice->mSampleRate;
  788. return ret;
  789. }
  790. struct AlsaCapture final : public BackendBase {
  791. explicit AlsaCapture(DeviceBase *device) noexcept : BackendBase{device} { }
  792. ~AlsaCapture() override;
  793. void open(std::string_view name) override;
  794. void start() override;
  795. void stop() override;
  796. void captureSamples(std::byte *buffer, uint samples) override;
  797. uint availableSamples() override;
  798. ClockLatency getClockLatency() override;
  799. snd_pcm_t *mPcmHandle{nullptr};
  800. std::vector<std::byte> mBuffer;
  801. bool mDoCapture{false};
  802. RingBufferPtr mRing{nullptr};
  803. snd_pcm_sframes_t mLastAvail{0};
  804. };
  805. AlsaCapture::~AlsaCapture()
  806. {
  807. if(mPcmHandle)
  808. snd_pcm_close(mPcmHandle);
  809. mPcmHandle = nullptr;
  810. }
  811. void AlsaCapture::open(std::string_view name)
  812. {
  813. std::string driver{"default"};
  814. if(!name.empty())
  815. {
  816. if(CaptureDevices.empty())
  817. CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE);
  818. auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
  819. [name](const DevMap &entry) -> bool { return entry.name == name; });
  820. if(iter == CaptureDevices.cend())
  821. throw al::backend_exception{al::backend_error::NoDevice,
  822. "Device name \"{}\" not found", name};
  823. driver = iter->device_name;
  824. }
  825. else
  826. {
  827. name = GetDefaultName();
  828. if(auto driveropt = ConfigValueStr({}, "alsa"sv, "capture"sv))
  829. driver = std::move(driveropt).value();
  830. }
  831. TRACE("Opening device \"{}\"", driver);
  832. if(int err{snd_pcm_open(&mPcmHandle, driver.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)}; err < 0)
  833. throw al::backend_exception{al::backend_error::NoDevice,
  834. "Could not open ALSA device \"{}\"", driver};
  835. /* Free alsa's global config tree. Otherwise valgrind reports a ton of leaks. */
  836. snd_config_update_free_global();
  837. snd_pcm_format_t format{SND_PCM_FORMAT_UNKNOWN};
  838. switch(mDevice->FmtType)
  839. {
  840. case DevFmtByte:
  841. format = SND_PCM_FORMAT_S8;
  842. break;
  843. case DevFmtUByte:
  844. format = SND_PCM_FORMAT_U8;
  845. break;
  846. case DevFmtShort:
  847. format = SND_PCM_FORMAT_S16;
  848. break;
  849. case DevFmtUShort:
  850. format = SND_PCM_FORMAT_U16;
  851. break;
  852. case DevFmtInt:
  853. format = SND_PCM_FORMAT_S32;
  854. break;
  855. case DevFmtUInt:
  856. format = SND_PCM_FORMAT_U32;
  857. break;
  858. case DevFmtFloat:
  859. format = SND_PCM_FORMAT_FLOAT;
  860. break;
  861. }
  862. snd_pcm_uframes_t bufferSizeInFrames{std::max(mDevice->mBufferSize,
  863. 100u*mDevice->mSampleRate/1000u)};
  864. snd_pcm_uframes_t periodSizeInFrames{std::min(mDevice->mBufferSize,
  865. 25u*mDevice->mSampleRate/1000u)};
  866. bool needring{false};
  867. HwParamsPtr hp{CreateHwParams()};
  868. #define CHECK(x) do { \
  869. if(int err{x}; err < 0) \
  870. throw al::backend_exception{al::backend_error::DeviceError, #x " failed: {}", \
  871. snd_strerror(err)}; \
  872. } while(0)
  873. CHECK(snd_pcm_hw_params_any(mPcmHandle, hp.get()));
  874. /* set interleaved access */
  875. CHECK(snd_pcm_hw_params_set_access(mPcmHandle, hp.get(), SND_PCM_ACCESS_RW_INTERLEAVED));
  876. /* set format (implicitly sets sample bits) */
  877. CHECK(snd_pcm_hw_params_set_format(mPcmHandle, hp.get(), format));
  878. /* set channels (implicitly sets frame bits) */
  879. CHECK(snd_pcm_hw_params_set_channels(mPcmHandle, hp.get(), mDevice->channelsFromFmt()));
  880. /* set rate (implicitly constrains period/buffer parameters) */
  881. CHECK(snd_pcm_hw_params_set_rate(mPcmHandle, hp.get(), mDevice->mSampleRate, 0));
  882. /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
  883. if(snd_pcm_hw_params_set_buffer_size_min(mPcmHandle, hp.get(), &bufferSizeInFrames) < 0)
  884. {
  885. TRACE("Buffer too large, using intermediate ring buffer");
  886. needring = true;
  887. CHECK(snd_pcm_hw_params_set_buffer_size_near(mPcmHandle, hp.get(), &bufferSizeInFrames));
  888. }
  889. /* set buffer size in frame units (implicitly sets period size/bytes/time and buffer time/bytes) */
  890. CHECK(snd_pcm_hw_params_set_period_size_near(mPcmHandle, hp.get(), &periodSizeInFrames, nullptr));
  891. /* install and prepare hardware configuration */
  892. CHECK(snd_pcm_hw_params(mPcmHandle, hp.get()));
  893. /* retrieve configuration info */
  894. CHECK(snd_pcm_hw_params_get_period_size(hp.get(), &periodSizeInFrames, nullptr));
  895. #undef CHECK
  896. hp = nullptr;
  897. if(needring)
  898. mRing = RingBuffer::Create(mDevice->mBufferSize, mDevice->frameSizeFromFmt(), false);
  899. mDeviceName = name;
  900. }
  901. void AlsaCapture::start()
  902. {
  903. if(int err{snd_pcm_prepare(mPcmHandle)}; err < 0)
  904. throw al::backend_exception{al::backend_error::DeviceError, "snd_pcm_prepare failed: {}",
  905. snd_strerror(err)};
  906. if(int err{snd_pcm_start(mPcmHandle)}; err < 0)
  907. throw al::backend_exception{al::backend_error::DeviceError, "snd_pcm_start failed: {}",
  908. snd_strerror(err)};
  909. mDoCapture = true;
  910. }
  911. void AlsaCapture::stop()
  912. {
  913. /* OpenAL requires access to unread audio after stopping, but ALSA's
  914. * snd_pcm_drain is unreliable and snd_pcm_drop drops it. Capture what's
  915. * available now so it'll be available later after the drop.
  916. */
  917. uint avail{availableSamples()};
  918. if(!mRing && avail > 0)
  919. {
  920. /* The ring buffer implicitly captures when checking availability.
  921. * Direct access needs to explicitly capture it into temp storage.
  922. */
  923. auto temp = std::vector<std::byte>(
  924. static_cast<size_t>(snd_pcm_frames_to_bytes(mPcmHandle, avail)));
  925. captureSamples(temp.data(), avail);
  926. mBuffer = std::move(temp);
  927. }
  928. if(int err{snd_pcm_drop(mPcmHandle)}; err < 0)
  929. ERR("snd_pcm_drop failed: {}", snd_strerror(err));
  930. mDoCapture = false;
  931. }
  932. void AlsaCapture::captureSamples(std::byte *buffer, uint samples)
  933. {
  934. if(mRing)
  935. {
  936. std::ignore = mRing->read(buffer, samples);
  937. return;
  938. }
  939. const auto outspan = al::span{buffer,
  940. static_cast<size_t>(snd_pcm_frames_to_bytes(mPcmHandle, samples))};
  941. auto outiter = outspan.begin();
  942. mLastAvail -= samples;
  943. while(mDevice->Connected.load(std::memory_order_acquire) && samples > 0)
  944. {
  945. snd_pcm_sframes_t amt{0};
  946. if(!mBuffer.empty())
  947. {
  948. /* First get any data stored from the last stop */
  949. amt = snd_pcm_bytes_to_frames(mPcmHandle, static_cast<ssize_t>(mBuffer.size()));
  950. if(static_cast<snd_pcm_uframes_t>(amt) > samples) amt = samples;
  951. amt = snd_pcm_frames_to_bytes(mPcmHandle, amt);
  952. std::copy_n(mBuffer.begin(), amt, outiter);
  953. mBuffer.erase(mBuffer.begin(), mBuffer.begin()+amt);
  954. amt = snd_pcm_bytes_to_frames(mPcmHandle, amt);
  955. }
  956. else if(mDoCapture)
  957. amt = snd_pcm_readi(mPcmHandle, al::to_address(outiter), samples);
  958. if(amt < 0)
  959. {
  960. ERR("read error: {}", snd_strerror(static_cast<int>(amt)));
  961. if(amt == -EAGAIN)
  962. continue;
  963. amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1);
  964. if(amt >= 0)
  965. {
  966. amt = snd_pcm_start(mPcmHandle);
  967. if(amt >= 0)
  968. amt = snd_pcm_avail_update(mPcmHandle);
  969. }
  970. if(amt < 0)
  971. {
  972. const char *err{snd_strerror(static_cast<int>(amt))};
  973. ERR("restore error: {}", err);
  974. mDevice->handleDisconnect("Capture recovery failure: {}", err);
  975. break;
  976. }
  977. /* If the amount available is less than what's asked, we lost it
  978. * during recovery. So just give silence instead. */
  979. if(static_cast<snd_pcm_uframes_t>(amt) < samples)
  980. break;
  981. continue;
  982. }
  983. outiter += amt;
  984. samples -= static_cast<uint>(amt);
  985. }
  986. if(samples > 0)
  987. std::fill_n(outiter, snd_pcm_frames_to_bytes(mPcmHandle, samples),
  988. std::byte((mDevice->FmtType == DevFmtUByte) ? 0x80 : 0));
  989. }
  990. uint AlsaCapture::availableSamples()
  991. {
  992. snd_pcm_sframes_t avail{0};
  993. if(mDevice->Connected.load(std::memory_order_acquire) && mDoCapture)
  994. avail = snd_pcm_avail_update(mPcmHandle);
  995. if(avail < 0)
  996. {
  997. ERR("snd_pcm_avail_update failed: {}", snd_strerror(static_cast<int>(avail)));
  998. avail = snd_pcm_recover(mPcmHandle, static_cast<int>(avail), 1);
  999. if(avail >= 0)
  1000. {
  1001. if(mDoCapture)
  1002. avail = snd_pcm_start(mPcmHandle);
  1003. if(avail >= 0)
  1004. avail = snd_pcm_avail_update(mPcmHandle);
  1005. }
  1006. if(avail < 0)
  1007. {
  1008. const char *err{snd_strerror(static_cast<int>(avail))};
  1009. ERR("restore error: {}", err);
  1010. mDevice->handleDisconnect("Capture recovery failure: {}", err);
  1011. }
  1012. }
  1013. if(!mRing)
  1014. {
  1015. avail = std::max<snd_pcm_sframes_t>(avail, 0);
  1016. avail += snd_pcm_bytes_to_frames(mPcmHandle, static_cast<ssize_t>(mBuffer.size()));
  1017. mLastAvail = std::max(mLastAvail, avail);
  1018. return static_cast<uint>(mLastAvail);
  1019. }
  1020. while(avail > 0)
  1021. {
  1022. auto vec = mRing->getWriteVector();
  1023. if(vec[0].len == 0) break;
  1024. snd_pcm_sframes_t amt{std::min(static_cast<snd_pcm_sframes_t>(vec[0].len), avail)};
  1025. amt = snd_pcm_readi(mPcmHandle, vec[0].buf, static_cast<snd_pcm_uframes_t>(amt));
  1026. if(amt < 0)
  1027. {
  1028. ERR("read error: {}", snd_strerror(static_cast<int>(amt)));
  1029. if(amt == -EAGAIN)
  1030. continue;
  1031. amt = snd_pcm_recover(mPcmHandle, static_cast<int>(amt), 1);
  1032. if(amt >= 0)
  1033. {
  1034. if(mDoCapture)
  1035. amt = snd_pcm_start(mPcmHandle);
  1036. if(amt >= 0)
  1037. amt = snd_pcm_avail_update(mPcmHandle);
  1038. }
  1039. if(amt < 0)
  1040. {
  1041. const char *err{snd_strerror(static_cast<int>(amt))};
  1042. ERR("restore error: {}", err);
  1043. mDevice->handleDisconnect("Capture recovery failure: {}", err);
  1044. break;
  1045. }
  1046. avail = amt;
  1047. continue;
  1048. }
  1049. mRing->writeAdvance(static_cast<snd_pcm_uframes_t>(amt));
  1050. avail -= amt;
  1051. }
  1052. return static_cast<uint>(mRing->readSpace());
  1053. }
  1054. ClockLatency AlsaCapture::getClockLatency()
  1055. {
  1056. ClockLatency ret{};
  1057. ret.ClockTime = mDevice->getClockTime();
  1058. snd_pcm_sframes_t delay{};
  1059. int err{snd_pcm_delay(mPcmHandle, &delay)};
  1060. if(err < 0)
  1061. {
  1062. ERR("Failed to get pcm delay: {}", snd_strerror(err));
  1063. delay = 0;
  1064. }
  1065. ret.Latency = std::chrono::seconds{std::max<snd_pcm_sframes_t>(0, delay)};
  1066. ret.Latency /= mDevice->mSampleRate;
  1067. return ret;
  1068. }
  1069. } // namespace
  1070. bool AlsaBackendFactory::init()
  1071. {
  1072. #if HAVE_DYNLOAD
  1073. if(!alsa_handle)
  1074. {
  1075. alsa_handle = LoadLib("libasound.so.2");
  1076. if(!alsa_handle)
  1077. {
  1078. WARN("Failed to load {}", "libasound.so.2");
  1079. return false;
  1080. }
  1081. std::string missing_funcs;
  1082. #define LOAD_FUNC(f) do { \
  1083. p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(alsa_handle, #f)); \
  1084. if(p##f == nullptr) missing_funcs += "\n" #f; \
  1085. } while(0)
  1086. ALSA_FUNCS(LOAD_FUNC);
  1087. #undef LOAD_FUNC
  1088. if(!missing_funcs.empty())
  1089. {
  1090. WARN("Missing expected functions:{}", missing_funcs);
  1091. CloseLib(alsa_handle);
  1092. alsa_handle = nullptr;
  1093. return false;
  1094. }
  1095. }
  1096. #endif
  1097. return true;
  1098. }
  1099. bool AlsaBackendFactory::querySupport(BackendType type)
  1100. { return (type == BackendType::Playback || type == BackendType::Capture); }
  1101. auto AlsaBackendFactory::enumerate(BackendType type) -> std::vector<std::string>
  1102. {
  1103. std::vector<std::string> outnames;
  1104. auto add_device = [&outnames](const DevMap &entry) -> void
  1105. { outnames.emplace_back(entry.name); };
  1106. switch(type)
  1107. {
  1108. case BackendType::Playback:
  1109. PlaybackDevices = probe_devices(SND_PCM_STREAM_PLAYBACK);
  1110. outnames.reserve(PlaybackDevices.size());
  1111. std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
  1112. break;
  1113. case BackendType::Capture:
  1114. CaptureDevices = probe_devices(SND_PCM_STREAM_CAPTURE);
  1115. outnames.reserve(CaptureDevices.size());
  1116. std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
  1117. break;
  1118. }
  1119. return outnames;
  1120. }
  1121. BackendPtr AlsaBackendFactory::createBackend(DeviceBase *device, BackendType type)
  1122. {
  1123. if(type == BackendType::Playback)
  1124. return BackendPtr{new AlsaPlayback{device}};
  1125. if(type == BackendType::Capture)
  1126. return BackendPtr{new AlsaCapture{device}};
  1127. return nullptr;
  1128. }
  1129. BackendFactory &AlsaBackendFactory::getFactory()
  1130. {
  1131. static AlsaBackendFactory factory{};
  1132. return factory;
  1133. }