🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1286 lines
44 KiB

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