alsa.cpp 45 KB

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