alsa.cpp 47 KB

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