🛠️🐜 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.

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