qsa.cpp 27 KB

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