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

955 lines
26 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2011-2013 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/qsa.h"
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <sched.h>
  25. #include <errno.h>
  26. #include <memory.h>
  27. #include <poll.h>
  28. #include <thread>
  29. #include <memory>
  30. #include <algorithm>
  31. #include "alMain.h"
  32. #include "alu.h"
  33. #include "threads.h"
  34. #include <sys/asoundlib.h>
  35. #include <sys/neutrino.h>
  36. namespace {
  37. struct qsa_data {
  38. snd_pcm_t* pcmHandle{nullptr};
  39. int audio_fd{-1};
  40. snd_pcm_channel_setup_t csetup{};
  41. snd_pcm_channel_params_t cparams{};
  42. ALvoid* buffer{nullptr};
  43. ALsizei size{0};
  44. std::atomic<ALenum> mKillNow{AL_TRUE};
  45. std::thread mThread;
  46. };
  47. struct DevMap {
  48. ALCchar* name;
  49. int card;
  50. int dev;
  51. };
  52. al::vector<DevMap> DeviceNameMap;
  53. al::vector<DevMap> CaptureNameMap;
  54. constexpr ALCchar qsaDevice[] = "QSA Default";
  55. constexpr struct {
  56. int32_t format;
  57. } formatlist[] = {
  58. {SND_PCM_SFMT_FLOAT_LE},
  59. {SND_PCM_SFMT_S32_LE},
  60. {SND_PCM_SFMT_U32_LE},
  61. {SND_PCM_SFMT_S16_LE},
  62. {SND_PCM_SFMT_U16_LE},
  63. {SND_PCM_SFMT_S8},
  64. {SND_PCM_SFMT_U8},
  65. {0},
  66. };
  67. constexpr struct {
  68. int32_t rate;
  69. } ratelist[] = {
  70. {192000},
  71. {176400},
  72. {96000},
  73. {88200},
  74. {48000},
  75. {44100},
  76. {32000},
  77. {24000},
  78. {22050},
  79. {16000},
  80. {12000},
  81. {11025},
  82. {8000},
  83. {0},
  84. };
  85. constexpr struct {
  86. int32_t channels;
  87. } channellist[] = {
  88. {8},
  89. {7},
  90. {6},
  91. {4},
  92. {2},
  93. {1},
  94. {0},
  95. };
  96. void deviceList(int type, al::vector<DevMap> *devmap)
  97. {
  98. snd_ctl_t* handle;
  99. snd_pcm_info_t pcminfo;
  100. int max_cards, card, err, dev;
  101. DevMap entry;
  102. char name[1024];
  103. snd_ctl_hw_info info;
  104. max_cards = snd_cards();
  105. if(max_cards < 0)
  106. return;
  107. std::for_each(devmap->begin(), devmap->end(),
  108. [](const DevMap &entry) -> void
  109. { free(entry.name); }
  110. );
  111. devmap->clear();
  112. entry.name = strdup(qsaDevice);
  113. entry.card = 0;
  114. entry.dev = 0;
  115. devmap->push_back(entry);
  116. for(card = 0;card < max_cards;card++)
  117. {
  118. if((err=snd_ctl_open(&handle, card)) < 0)
  119. continue;
  120. if((err=snd_ctl_hw_info(handle, &info)) < 0)
  121. {
  122. snd_ctl_close(handle);
  123. continue;
  124. }
  125. for(dev = 0;dev < (int)info.pcmdevs;dev++)
  126. {
  127. if((err=snd_ctl_pcm_info(handle, dev, &pcminfo)) < 0)
  128. continue;
  129. if((type==SND_PCM_CHANNEL_PLAYBACK && (pcminfo.flags&SND_PCM_INFO_PLAYBACK)) ||
  130. (type==SND_PCM_CHANNEL_CAPTURE && (pcminfo.flags&SND_PCM_INFO_CAPTURE)))
  131. {
  132. snprintf(name, sizeof(name), "%s [%s] (hw:%d,%d)", info.name, pcminfo.name, card, dev);
  133. entry.name = strdup(name);
  134. entry.card = card;
  135. entry.dev = dev;
  136. devmap->push_back(entry);
  137. TRACE("Got device \"%s\", card %d, dev %d\n", name, card, dev);
  138. }
  139. }
  140. snd_ctl_close(handle);
  141. }
  142. }
  143. /* Wrappers to use an old-style backend with the new interface. */
  144. struct PlaybackWrapper final : public BackendBase {
  145. PlaybackWrapper(ALCdevice *device) noexcept : BackendBase{device} { }
  146. ~PlaybackWrapper() override;
  147. ALCenum open(const ALCchar *name) override;
  148. ALCboolean reset() override;
  149. ALCboolean start() override;
  150. void stop() override;
  151. std::unique_ptr<qsa_data> mExtraData;
  152. static constexpr inline const char *CurrentPrefix() noexcept { return "PlaybackWrapper::"; }
  153. DEF_NEWDEL(PlaybackWrapper)
  154. };
  155. FORCE_ALIGN static int qsa_proc_playback(void *ptr)
  156. {
  157. PlaybackWrapper *self = static_cast<PlaybackWrapper*>(ptr);
  158. ALCdevice *device = self->mDevice;
  159. qsa_data *data = self->mExtraData.get();
  160. snd_pcm_channel_status_t status;
  161. sched_param param;
  162. char* write_ptr;
  163. ALint len;
  164. int sret;
  165. SetRTPriority();
  166. althrd_setname(MIXER_THREAD_NAME);
  167. /* Increase default 10 priority to 11 to avoid jerky sound */
  168. SchedGet(0, 0, &param);
  169. param.sched_priority=param.sched_curpriority+1;
  170. SchedSet(0, 0, SCHED_NOCHANGE, &param);
  171. const ALint frame_size = device->frameSizeFromFmt();
  172. self->lock();
  173. while(!data->mKillNow.load(std::memory_order_acquire))
  174. {
  175. pollfd pollitem{};
  176. pollitem.fd = data->audio_fd;
  177. pollitem.events = POLLOUT;
  178. /* Select also works like time slice to OS */
  179. self->unlock();
  180. sret = poll(&pollitem, 1, 2000);
  181. self->lock();
  182. if(sret == -1)
  183. {
  184. if(errno == EINTR || errno == EAGAIN)
  185. continue;
  186. ERR("poll error: %s\n", strerror(errno));
  187. aluHandleDisconnect(device, "Failed waiting for playback buffer: %s", strerror(errno));
  188. break;
  189. }
  190. if(sret == 0)
  191. {
  192. ERR("poll timeout\n");
  193. continue;
  194. }
  195. len = data->size;
  196. write_ptr = static_cast<char*>(data->buffer);
  197. aluMixData(device, write_ptr, len/frame_size);
  198. while(len>0 && !data->mKillNow.load(std::memory_order_acquire))
  199. {
  200. int wrote = snd_pcm_plugin_write(data->pcmHandle, write_ptr, len);
  201. if(wrote <= 0)
  202. {
  203. if(errno==EAGAIN || errno==EWOULDBLOCK)
  204. continue;
  205. memset(&status, 0, sizeof(status));
  206. status.channel = SND_PCM_CHANNEL_PLAYBACK;
  207. snd_pcm_plugin_status(data->pcmHandle, &status);
  208. /* we need to reinitialize the sound channel if we've underrun the buffer */
  209. if(status.status == SND_PCM_STATUS_UNDERRUN ||
  210. status.status == SND_PCM_STATUS_READY)
  211. {
  212. if(snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK) < 0)
  213. {
  214. aluHandleDisconnect(device, "Playback recovery failed");
  215. break;
  216. }
  217. }
  218. }
  219. else
  220. {
  221. write_ptr += wrote;
  222. len -= wrote;
  223. }
  224. }
  225. }
  226. self->unlock();
  227. return 0;
  228. }
  229. /************/
  230. /* Playback */
  231. /************/
  232. static ALCenum qsa_open_playback(PlaybackWrapper *self, const ALCchar* deviceName)
  233. {
  234. ALCdevice *device = self->mDevice;
  235. int card, dev;
  236. int status;
  237. std::unique_ptr<qsa_data> data{new qsa_data{}};
  238. data->mKillNow.store(AL_TRUE, std::memory_order_relaxed);
  239. if(!deviceName)
  240. deviceName = qsaDevice;
  241. if(strcmp(deviceName, qsaDevice) == 0)
  242. status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK);
  243. else
  244. {
  245. if(DeviceNameMap.empty())
  246. deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
  247. auto iter = std::find_if(DeviceNameMap.begin(), DeviceNameMap.end(),
  248. [deviceName](const DevMap &entry) -> bool
  249. { return entry.name && strcmp(deviceName, entry.name) == 0; }
  250. );
  251. if(iter == DeviceNameMap.cend())
  252. return ALC_INVALID_DEVICE;
  253. status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK);
  254. }
  255. if(status < 0)
  256. return ALC_INVALID_DEVICE;
  257. data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK);
  258. if(data->audio_fd < 0)
  259. {
  260. snd_pcm_close(data->pcmHandle);
  261. return ALC_INVALID_DEVICE;
  262. }
  263. device->DeviceName = deviceName;
  264. self->mExtraData = std::move(data);
  265. return ALC_NO_ERROR;
  266. }
  267. static void qsa_close_playback(PlaybackWrapper *self)
  268. {
  269. qsa_data *data = self->mExtraData.get();
  270. if (data->buffer!=NULL)
  271. {
  272. free(data->buffer);
  273. data->buffer=NULL;
  274. }
  275. snd_pcm_close(data->pcmHandle);
  276. self->mExtraData = nullptr;
  277. }
  278. static ALCboolean qsa_reset_playback(PlaybackWrapper *self)
  279. {
  280. ALCdevice *device = self->mDevice;
  281. qsa_data *data = self->mExtraData.get();
  282. int32_t format=-1;
  283. switch(device->FmtType)
  284. {
  285. case DevFmtByte:
  286. format=SND_PCM_SFMT_S8;
  287. break;
  288. case DevFmtUByte:
  289. format=SND_PCM_SFMT_U8;
  290. break;
  291. case DevFmtShort:
  292. format=SND_PCM_SFMT_S16_LE;
  293. break;
  294. case DevFmtUShort:
  295. format=SND_PCM_SFMT_U16_LE;
  296. break;
  297. case DevFmtInt:
  298. format=SND_PCM_SFMT_S32_LE;
  299. break;
  300. case DevFmtUInt:
  301. format=SND_PCM_SFMT_U32_LE;
  302. break;
  303. case DevFmtFloat:
  304. format=SND_PCM_SFMT_FLOAT_LE;
  305. break;
  306. }
  307. /* we actually don't want to block on writes */
  308. snd_pcm_nonblock_mode(data->pcmHandle, 1);
  309. /* Disable mmap to control data transfer to the audio device */
  310. snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
  311. snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_BUFFER_PARTIAL_BLOCKS);
  312. // configure a sound channel
  313. memset(&data->cparams, 0, sizeof(data->cparams));
  314. data->cparams.channel=SND_PCM_CHANNEL_PLAYBACK;
  315. data->cparams.mode=SND_PCM_MODE_BLOCK;
  316. data->cparams.start_mode=SND_PCM_START_FULL;
  317. data->cparams.stop_mode=SND_PCM_STOP_STOP;
  318. data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt();
  319. data->cparams.buf.block.frags_max=device->BufferSize / device->UpdateSize;
  320. data->cparams.buf.block.frags_min=data->cparams.buf.block.frags_max;
  321. data->cparams.format.interleave=1;
  322. data->cparams.format.rate=device->Frequency;
  323. data->cparams.format.voices=device->channelsFromFmt();
  324. data->cparams.format.format=format;
  325. if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
  326. {
  327. int original_rate=data->cparams.format.rate;
  328. int original_voices=data->cparams.format.voices;
  329. int original_format=data->cparams.format.format;
  330. int it;
  331. int jt;
  332. for (it=0; it<1; it++)
  333. {
  334. /* Check for second pass */
  335. if (it==1)
  336. {
  337. original_rate=ratelist[0].rate;
  338. original_voices=channellist[0].channels;
  339. original_format=formatlist[0].format;
  340. }
  341. do {
  342. /* At first downgrade sample format */
  343. jt=0;
  344. do {
  345. if (formatlist[jt].format==data->cparams.format.format)
  346. {
  347. data->cparams.format.format=formatlist[jt+1].format;
  348. break;
  349. }
  350. if (formatlist[jt].format==0)
  351. {
  352. data->cparams.format.format=0;
  353. break;
  354. }
  355. jt++;
  356. } while(1);
  357. if (data->cparams.format.format==0)
  358. {
  359. data->cparams.format.format=original_format;
  360. /* At secod downgrade sample rate */
  361. jt=0;
  362. do {
  363. if (ratelist[jt].rate==data->cparams.format.rate)
  364. {
  365. data->cparams.format.rate=ratelist[jt+1].rate;
  366. break;
  367. }
  368. if (ratelist[jt].rate==0)
  369. {
  370. data->cparams.format.rate=0;
  371. break;
  372. }
  373. jt++;
  374. } while(1);
  375. if (data->cparams.format.rate==0)
  376. {
  377. data->cparams.format.rate=original_rate;
  378. data->cparams.format.format=original_format;
  379. /* At third downgrade channels number */
  380. jt=0;
  381. do {
  382. if(channellist[jt].channels==data->cparams.format.voices)
  383. {
  384. data->cparams.format.voices=channellist[jt+1].channels;
  385. break;
  386. }
  387. if (channellist[jt].channels==0)
  388. {
  389. data->cparams.format.voices=0;
  390. break;
  391. }
  392. jt++;
  393. } while(1);
  394. }
  395. if (data->cparams.format.voices==0)
  396. {
  397. break;
  398. }
  399. }
  400. data->cparams.buf.block.frag_size=device->UpdateSize*
  401. data->cparams.format.voices*
  402. snd_pcm_format_width(data->cparams.format.format)/8;
  403. data->cparams.buf.block.frags_max=device->NumUpdates;
  404. data->cparams.buf.block.frags_min=device->NumUpdates;
  405. if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0)
  406. {
  407. continue;
  408. }
  409. else
  410. {
  411. break;
  412. }
  413. } while(1);
  414. if (data->cparams.format.voices!=0)
  415. {
  416. break;
  417. }
  418. }
  419. if (data->cparams.format.voices==0)
  420. {
  421. return ALC_FALSE;
  422. }
  423. }
  424. if ((snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK))<0)
  425. {
  426. return ALC_FALSE;
  427. }
  428. memset(&data->csetup, 0, sizeof(data->csetup));
  429. data->csetup.channel=SND_PCM_CHANNEL_PLAYBACK;
  430. if (snd_pcm_plugin_setup(data->pcmHandle, &data->csetup)<0)
  431. {
  432. return ALC_FALSE;
  433. }
  434. /* now fill back to the our AL device */
  435. device->Frequency=data->cparams.format.rate;
  436. switch (data->cparams.format.voices)
  437. {
  438. case 1:
  439. device->FmtChans=DevFmtMono;
  440. break;
  441. case 2:
  442. device->FmtChans=DevFmtStereo;
  443. break;
  444. case 4:
  445. device->FmtChans=DevFmtQuad;
  446. break;
  447. case 6:
  448. device->FmtChans=DevFmtX51;
  449. break;
  450. case 7:
  451. device->FmtChans=DevFmtX61;
  452. break;
  453. case 8:
  454. device->FmtChans=DevFmtX71;
  455. break;
  456. default:
  457. device->FmtChans=DevFmtMono;
  458. break;
  459. }
  460. switch (data->cparams.format.format)
  461. {
  462. case SND_PCM_SFMT_S8:
  463. device->FmtType=DevFmtByte;
  464. break;
  465. case SND_PCM_SFMT_U8:
  466. device->FmtType=DevFmtUByte;
  467. break;
  468. case SND_PCM_SFMT_S16_LE:
  469. device->FmtType=DevFmtShort;
  470. break;
  471. case SND_PCM_SFMT_U16_LE:
  472. device->FmtType=DevFmtUShort;
  473. break;
  474. case SND_PCM_SFMT_S32_LE:
  475. device->FmtType=DevFmtInt;
  476. break;
  477. case SND_PCM_SFMT_U32_LE:
  478. device->FmtType=DevFmtUInt;
  479. break;
  480. case SND_PCM_SFMT_FLOAT_LE:
  481. device->FmtType=DevFmtFloat;
  482. break;
  483. default:
  484. device->FmtType=DevFmtShort;
  485. break;
  486. }
  487. SetDefaultChannelOrder(device);
  488. device->UpdateSize=data->csetup.buf.block.frag_size / device->frameSizeFromFmt();
  489. device->NumUpdates=data->csetup.buf.block.frags;
  490. data->size=data->csetup.buf.block.frag_size;
  491. data->buffer=malloc(data->size);
  492. if (!data->buffer)
  493. {
  494. return ALC_FALSE;
  495. }
  496. return ALC_TRUE;
  497. }
  498. static ALCboolean qsa_start_playback(PlaybackWrapper *self)
  499. {
  500. qsa_data *data = self->mExtraData.get();
  501. try {
  502. data->mKillNow.store(AL_FALSE, std::memory_order_release);
  503. data->mThread = std::thread(qsa_proc_playback, self);
  504. return ALC_TRUE;
  505. }
  506. catch(std::exception& e) {
  507. ERR("Could not create playback thread: %s\n", e.what());
  508. }
  509. catch(...) {
  510. }
  511. return ALC_FALSE;
  512. }
  513. static void qsa_stop_playback(PlaybackWrapper *self)
  514. {
  515. qsa_data *data = self->mExtraData.get();
  516. if(data->mKillNow.exchange(AL_TRUE, std::memory_order_acq_rel) || !data->mThread.joinable())
  517. return;
  518. data->mThread.join();
  519. }
  520. PlaybackWrapper::~PlaybackWrapper()
  521. {
  522. if(mExtraData)
  523. qsa_close_playback(this);
  524. }
  525. ALCenum PlaybackWrapper::open(const ALCchar *name)
  526. { return qsa_open_playback(this, name); }
  527. ALCboolean PlaybackWrapper::reset()
  528. { return qsa_reset_playback(this); }
  529. ALCboolean PlaybackWrapper::start()
  530. { return qsa_start_playback(this); }
  531. void PlaybackWrapper::stop()
  532. { qsa_stop_playback(this); }
  533. /***********/
  534. /* Capture */
  535. /***********/
  536. struct CaptureWrapper final : public BackendBase {
  537. CaptureWrapper(ALCdevice *device) noexcept : BackendBase{device} { }
  538. ~CaptureWrapper() override;
  539. ALCenum open(const ALCchar *name) override;
  540. ALCboolean start() override;
  541. void stop() override;
  542. ALCenum captureSamples(void *buffer, ALCuint samples) override;
  543. ALCuint availableSamples() override;
  544. std::unique_ptr<qsa_data> mExtraData;
  545. static constexpr inline const char *CurrentPrefix() noexcept { return "CaptureWrapper::"; }
  546. DEF_NEWDEL(CaptureWrapper)
  547. };
  548. static ALCenum qsa_open_capture(CaptureWrapper *self, const ALCchar *deviceName)
  549. {
  550. ALCdevice *device = self->mDevice;
  551. int card, dev;
  552. int format=-1;
  553. int status;
  554. std::unique_ptr<qsa_data> data{new qsa_data{}};
  555. if(!deviceName)
  556. deviceName = qsaDevice;
  557. if(strcmp(deviceName, qsaDevice) == 0)
  558. status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE);
  559. else
  560. {
  561. if(CaptureNameMap.empty())
  562. deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
  563. auto iter = std::find_if(CaptureNameMap.cbegin(), CaptureNameMap.cend(),
  564. [deviceName](const DevMap &entry) -> bool
  565. { return entry.name && strcmp(deviceName, entry.name) == 0; }
  566. );
  567. if(iter == CaptureNameMap.cend())
  568. return ALC_INVALID_DEVICE;
  569. status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE);
  570. }
  571. if(status < 0)
  572. return ALC_INVALID_DEVICE;
  573. data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE);
  574. if(data->audio_fd < 0)
  575. {
  576. snd_pcm_close(data->pcmHandle);
  577. return ALC_INVALID_DEVICE;
  578. }
  579. device->DeviceName = deviceName;
  580. switch (device->FmtType)
  581. {
  582. case DevFmtByte:
  583. format=SND_PCM_SFMT_S8;
  584. break;
  585. case DevFmtUByte:
  586. format=SND_PCM_SFMT_U8;
  587. break;
  588. case DevFmtShort:
  589. format=SND_PCM_SFMT_S16_LE;
  590. break;
  591. case DevFmtUShort:
  592. format=SND_PCM_SFMT_U16_LE;
  593. break;
  594. case DevFmtInt:
  595. format=SND_PCM_SFMT_S32_LE;
  596. break;
  597. case DevFmtUInt:
  598. format=SND_PCM_SFMT_U32_LE;
  599. break;
  600. case DevFmtFloat:
  601. format=SND_PCM_SFMT_FLOAT_LE;
  602. break;
  603. }
  604. /* we actually don't want to block on reads */
  605. snd_pcm_nonblock_mode(data->pcmHandle, 1);
  606. /* Disable mmap to control data transfer to the audio device */
  607. snd_pcm_plugin_set_disable(data->pcmHandle, PLUGIN_DISABLE_MMAP);
  608. /* configure a sound channel */
  609. memset(&data->cparams, 0, sizeof(data->cparams));
  610. data->cparams.mode=SND_PCM_MODE_BLOCK;
  611. data->cparams.channel=SND_PCM_CHANNEL_CAPTURE;
  612. data->cparams.start_mode=SND_PCM_START_GO;
  613. data->cparams.stop_mode=SND_PCM_STOP_STOP;
  614. data->cparams.buf.block.frag_size=device->UpdateSize * device->frameSizeFromFmt();
  615. data->cparams.buf.block.frags_max=device->NumUpdates;
  616. data->cparams.buf.block.frags_min=device->NumUpdates;
  617. data->cparams.format.interleave=1;
  618. data->cparams.format.rate=device->Frequency;
  619. data->cparams.format.voices=device->channelsFromFmt();
  620. data->cparams.format.format=format;
  621. if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0)
  622. {
  623. snd_pcm_close(data->pcmHandle);
  624. return ALC_INVALID_VALUE;
  625. }
  626. self->mExtraData = std::move(data);
  627. return ALC_NO_ERROR;
  628. }
  629. static void qsa_close_capture(CaptureWrapper *self)
  630. {
  631. qsa_data *data = self->mExtraData.get();
  632. if (data->pcmHandle!=nullptr)
  633. snd_pcm_close(data->pcmHandle);
  634. data->pcmHandle = nullptr;
  635. self->mExtraData = nullptr;
  636. }
  637. static void qsa_start_capture(CaptureWrapper *self)
  638. {
  639. qsa_data *data = self->mExtraData.get();
  640. int rstatus;
  641. if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
  642. {
  643. ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
  644. return;
  645. }
  646. memset(&data->csetup, 0, sizeof(data->csetup));
  647. data->csetup.channel=SND_PCM_CHANNEL_CAPTURE;
  648. if ((rstatus=snd_pcm_plugin_setup(data->pcmHandle, &data->csetup))<0)
  649. {
  650. ERR("capture setup failed: %s\n", snd_strerror(rstatus));
  651. return;
  652. }
  653. snd_pcm_capture_go(data->pcmHandle);
  654. }
  655. static void qsa_stop_capture(CaptureWrapper *self)
  656. {
  657. qsa_data *data = self->mExtraData.get();
  658. snd_pcm_capture_flush(data->pcmHandle);
  659. }
  660. static ALCuint qsa_available_samples(CaptureWrapper *self)
  661. {
  662. ALCdevice *device = self->mDevice;
  663. qsa_data *data = self->mExtraData.get();
  664. snd_pcm_channel_status_t status;
  665. ALint frame_size = device->frameSizeFromFmt();
  666. ALint free_size;
  667. int rstatus;
  668. memset(&status, 0, sizeof (status));
  669. status.channel=SND_PCM_CHANNEL_CAPTURE;
  670. snd_pcm_plugin_status(data->pcmHandle, &status);
  671. if ((status.status==SND_PCM_STATUS_OVERRUN) ||
  672. (status.status==SND_PCM_STATUS_READY))
  673. {
  674. if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
  675. {
  676. ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
  677. aluHandleDisconnect(device, "Failed capture recovery: %s", snd_strerror(rstatus));
  678. return 0;
  679. }
  680. snd_pcm_capture_go(data->pcmHandle);
  681. return 0;
  682. }
  683. free_size=data->csetup.buf.block.frag_size*data->csetup.buf.block.frags;
  684. free_size-=status.free;
  685. return free_size/frame_size;
  686. }
  687. static ALCenum qsa_capture_samples(CaptureWrapper *self, ALCvoid *buffer, ALCuint samples)
  688. {
  689. ALCdevice *device = self->mDevice;
  690. qsa_data *data = self->mExtraData.get();
  691. char* read_ptr;
  692. snd_pcm_channel_status_t status;
  693. int selectret;
  694. int bytes_read;
  695. ALint frame_size=device->frameSizeFromFmt();
  696. ALint len=samples*frame_size;
  697. int rstatus;
  698. read_ptr = static_cast<char*>(buffer);
  699. while (len>0)
  700. {
  701. pollfd pollitem{};
  702. pollitem.fd = data->audio_fd;
  703. pollitem.events = POLLOUT;
  704. /* Select also works like time slice to OS */
  705. bytes_read=0;
  706. selectret = poll(&pollitem, 1, 2000);
  707. switch (selectret)
  708. {
  709. case -1:
  710. aluHandleDisconnect(device, "Failed to check capture samples");
  711. return ALC_INVALID_DEVICE;
  712. case 0:
  713. break;
  714. default:
  715. bytes_read=snd_pcm_plugin_read(data->pcmHandle, read_ptr, len);
  716. break;
  717. }
  718. if (bytes_read<=0)
  719. {
  720. if ((errno==EAGAIN) || (errno==EWOULDBLOCK))
  721. {
  722. continue;
  723. }
  724. memset(&status, 0, sizeof (status));
  725. status.channel=SND_PCM_CHANNEL_CAPTURE;
  726. snd_pcm_plugin_status(data->pcmHandle, &status);
  727. /* we need to reinitialize the sound channel if we've overrun the buffer */
  728. if ((status.status==SND_PCM_STATUS_OVERRUN) ||
  729. (status.status==SND_PCM_STATUS_READY))
  730. {
  731. if ((rstatus=snd_pcm_plugin_prepare(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE))<0)
  732. {
  733. ERR("capture prepare failed: %s\n", snd_strerror(rstatus));
  734. aluHandleDisconnect(device, "Failed capture recovery: %s",
  735. snd_strerror(rstatus));
  736. return ALC_INVALID_DEVICE;
  737. }
  738. snd_pcm_capture_go(data->pcmHandle);
  739. }
  740. }
  741. else
  742. {
  743. read_ptr+=bytes_read;
  744. len-=bytes_read;
  745. }
  746. }
  747. return ALC_NO_ERROR;
  748. }
  749. CaptureWrapper::~CaptureWrapper()
  750. {
  751. if(mExtraData)
  752. qsa_close_capture(this);
  753. }
  754. ALCenum CaptureWrapper::open(const ALCchar *name)
  755. { return qsa_open_capture(this, name); }
  756. ALCboolean CaptureWrapper::start()
  757. { qsa_start_capture(this); return ALC_TRUE; }
  758. void CaptureWrapper::stop()
  759. { qsa_stop_capture(this); }
  760. ALCenum CaptureWrapper::captureSamples(void *buffer, ALCuint samples)
  761. { return qsa_capture_samples(this, buffer, samples); }
  762. ALCuint CaptureWrapper::availableSamples()
  763. { return qsa_available_samples(this); }
  764. } // namespace
  765. bool QSABackendFactory::init()
  766. { return true; }
  767. bool QSABackendFactory::querySupport(BackendType type)
  768. { return (type == BackendType::Playback || type == BackendType::Capture); }
  769. void QSABackendFactory::probe(DevProbe type, std::string *outnames)
  770. {
  771. auto add_device = [outnames](const DevMap &entry) -> void
  772. {
  773. const char *n = entry.name;
  774. if(n && n[0])
  775. outnames->append(n, strlen(n)+1);
  776. };
  777. switch (type)
  778. {
  779. case DevProbe::Playback:
  780. deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap);
  781. std::for_each(DeviceNameMap.cbegin(), DeviceNameMap.cend(), add_device);
  782. break;
  783. case DevProbe::Capture:
  784. deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap);
  785. std::for_each(CaptureNameMap.cbegin(), CaptureNameMap.cend(), add_device);
  786. break;
  787. }
  788. }
  789. BackendPtr QSABackendFactory::createBackend(ALCdevice *device, BackendType type)
  790. {
  791. if(type == BackendType::Playback)
  792. return BackendPtr{new PlaybackWrapper{device}};
  793. if(type == BackendType::Capture)
  794. return BackendPtr{new CaptureWrapper{device}};
  795. return nullptr;
  796. }
  797. BackendFactory &QSABackendFactory::getFactory()
  798. {
  799. static QSABackendFactory factory{};
  800. return factory;
  801. }