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

497 lines
13 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include "backends/sndio.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <thread>
  26. #include <functional>
  27. #include "alMain.h"
  28. #include "alu.h"
  29. #include "threads.h"
  30. #include "vector.h"
  31. #include "ringbuffer.h"
  32. #include <sndio.h>
  33. namespace {
  34. static const ALCchar sndio_device[] = "SndIO Default";
  35. struct SndioPlayback final : public BackendBase {
  36. SndioPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
  37. ~SndioPlayback() override;
  38. int mixerProc();
  39. ALCenum open(const ALCchar *name) override;
  40. ALCboolean reset() override;
  41. ALCboolean start() override;
  42. void stop() override;
  43. sio_hdl *mSndHandle{nullptr};
  44. al::vector<ALubyte> mBuffer;
  45. std::atomic<bool> mKillNow{true};
  46. std::thread mThread;
  47. static constexpr inline const char *CurrentPrefix() noexcept { return "SndioPlayback::"; }
  48. DEF_NEWDEL(SndioPlayback)
  49. };
  50. SndioPlayback::~SndioPlayback()
  51. {
  52. if(mSndHandle)
  53. sio_close(mSndHandle);
  54. mSndHandle = nullptr;
  55. }
  56. int SndioPlayback::mixerProc()
  57. {
  58. SetRTPriority();
  59. althrd_setname(MIXER_THREAD_NAME);
  60. const ALsizei frameSize{mDevice->frameSizeFromFmt()};
  61. while(!mKillNow.load(std::memory_order_acquire) &&
  62. mDevice->Connected.load(std::memory_order_acquire))
  63. {
  64. auto WritePtr = static_cast<ALubyte*>(mBuffer.data());
  65. size_t len{mBuffer.size()};
  66. lock();
  67. aluMixData(mDevice, WritePtr, len/frameSize);
  68. unlock();
  69. while(len > 0 && !mKillNow.load(std::memory_order_acquire))
  70. {
  71. size_t wrote{sio_write(mSndHandle, WritePtr, len)};
  72. if(wrote == 0)
  73. {
  74. ERR("sio_write failed\n");
  75. aluHandleDisconnect(mDevice, "Failed to write playback samples");
  76. break;
  77. }
  78. len -= wrote;
  79. WritePtr += wrote;
  80. }
  81. }
  82. return 0;
  83. }
  84. ALCenum SndioPlayback::open(const ALCchar *name)
  85. {
  86. if(!name)
  87. name = sndio_device;
  88. else if(strcmp(name, sndio_device) != 0)
  89. return ALC_INVALID_VALUE;
  90. mSndHandle = sio_open(nullptr, SIO_PLAY, 0);
  91. if(mSndHandle == nullptr)
  92. {
  93. ERR("Could not open device\n");
  94. return ALC_INVALID_VALUE;
  95. }
  96. mDevice->DeviceName = name;
  97. return ALC_NO_ERROR;
  98. }
  99. ALCboolean SndioPlayback::reset()
  100. {
  101. sio_par par;
  102. sio_initpar(&par);
  103. par.rate = mDevice->Frequency;
  104. par.pchan = ((mDevice->FmtChans != DevFmtMono) ? 2 : 1);
  105. switch(mDevice->FmtType)
  106. {
  107. case DevFmtByte:
  108. par.bits = 8;
  109. par.sig = 1;
  110. break;
  111. case DevFmtUByte:
  112. par.bits = 8;
  113. par.sig = 0;
  114. break;
  115. case DevFmtFloat:
  116. case DevFmtShort:
  117. par.bits = 16;
  118. par.sig = 1;
  119. break;
  120. case DevFmtUShort:
  121. par.bits = 16;
  122. par.sig = 0;
  123. break;
  124. case DevFmtInt:
  125. par.bits = 32;
  126. par.sig = 1;
  127. break;
  128. case DevFmtUInt:
  129. par.bits = 32;
  130. par.sig = 0;
  131. break;
  132. }
  133. par.le = SIO_LE_NATIVE;
  134. par.round = mDevice->UpdateSize;
  135. par.appbufsz = mDevice->BufferSize - mDevice->UpdateSize;
  136. if(!par.appbufsz) par.appbufsz = mDevice->UpdateSize;
  137. if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par))
  138. {
  139. ERR("Failed to set device parameters\n");
  140. return ALC_FALSE;
  141. }
  142. if(par.bits != par.bps*8)
  143. {
  144. ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
  145. return ALC_FALSE;
  146. }
  147. mDevice->Frequency = par.rate;
  148. mDevice->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo);
  149. if(par.bits == 8 && par.sig == 1)
  150. mDevice->FmtType = DevFmtByte;
  151. else if(par.bits == 8 && par.sig == 0)
  152. mDevice->FmtType = DevFmtUByte;
  153. else if(par.bits == 16 && par.sig == 1)
  154. mDevice->FmtType = DevFmtShort;
  155. else if(par.bits == 16 && par.sig == 0)
  156. mDevice->FmtType = DevFmtUShort;
  157. else if(par.bits == 32 && par.sig == 1)
  158. mDevice->FmtType = DevFmtInt;
  159. else if(par.bits == 32 && par.sig == 0)
  160. mDevice->FmtType = DevFmtUInt;
  161. else
  162. {
  163. ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits);
  164. return ALC_FALSE;
  165. }
  166. SetDefaultChannelOrder(mDevice);
  167. mDevice->UpdateSize = par.round;
  168. mDevice->BufferSize = par.bufsz + par.round;
  169. mBuffer.resize(mDevice->UpdateSize * mDevice->frameSizeFromFmt());
  170. std::fill(mBuffer.begin(), mBuffer.end(), 0);
  171. return ALC_TRUE;
  172. }
  173. ALCboolean SndioPlayback::start()
  174. {
  175. if(!sio_start(mSndHandle))
  176. {
  177. ERR("Error starting playback\n");
  178. return ALC_FALSE;
  179. }
  180. try {
  181. mKillNow.store(false, std::memory_order_release);
  182. mThread = std::thread{std::mem_fn(&SndioPlayback::mixerProc), this};
  183. return ALC_TRUE;
  184. }
  185. catch(std::exception& e) {
  186. ERR("Could not create playback thread: %s\n", e.what());
  187. }
  188. catch(...) {
  189. }
  190. sio_stop(mSndHandle);
  191. return ALC_FALSE;
  192. }
  193. void SndioPlayback::stop()
  194. {
  195. if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
  196. return;
  197. mThread.join();
  198. if(!sio_stop(mSndHandle))
  199. ERR("Error stopping device\n");
  200. }
  201. struct SndioCapture final : public BackendBase {
  202. SndioCapture(ALCdevice *device) noexcept : BackendBase{device} { }
  203. ~SndioCapture() override;
  204. int recordProc();
  205. ALCenum open(const ALCchar *name) override;
  206. ALCboolean start() override;
  207. void stop() override;
  208. ALCenum captureSamples(void *buffer, ALCuint samples) override;
  209. ALCuint availableSamples() override;
  210. sio_hdl *mSndHandle{nullptr};
  211. RingBufferPtr mRing;
  212. std::atomic<bool> mKillNow{true};
  213. std::thread mThread;
  214. static constexpr inline const char *CurrentPrefix() noexcept { return "SndioCapture::"; }
  215. DEF_NEWDEL(SndioCapture)
  216. };
  217. SndioCapture::~SndioCapture()
  218. {
  219. if(mSndHandle)
  220. sio_close(mSndHandle);
  221. mSndHandle = nullptr;
  222. }
  223. int SndioCapture::recordProc()
  224. {
  225. SetRTPriority();
  226. althrd_setname(RECORD_THREAD_NAME);
  227. const ALsizei frameSize{mDevice->frameSizeFromFmt()};
  228. while(!mKillNow.load(std::memory_order_acquire) &&
  229. mDevice->Connected.load(std::memory_order_acquire))
  230. {
  231. auto data = mRing->getWriteVector();
  232. size_t todo{data.first.len + data.second.len};
  233. if(todo == 0)
  234. {
  235. static char junk[4096];
  236. sio_read(mSndHandle, junk,
  237. minz(sizeof(junk)/frameSize, mDevice->UpdateSize)*frameSize);
  238. continue;
  239. }
  240. size_t total{0u};
  241. data.first.len *= frameSize;
  242. data.second.len *= frameSize;
  243. todo = minz(todo, mDevice->UpdateSize) * frameSize;
  244. while(total < todo)
  245. {
  246. if(!data.first.len)
  247. data.first = data.second;
  248. size_t got{sio_read(mSndHandle, data.first.buf, minz(todo-total, data.first.len))};
  249. if(!got)
  250. {
  251. aluHandleDisconnect(mDevice, "Failed to read capture samples");
  252. break;
  253. }
  254. data.first.buf += got;
  255. data.first.len -= got;
  256. total += got;
  257. }
  258. mRing->writeAdvance(total / frameSize);
  259. }
  260. return 0;
  261. }
  262. ALCenum SndioCapture::open(const ALCchar *name)
  263. {
  264. if(!name)
  265. name = sndio_device;
  266. else if(strcmp(name, sndio_device) != 0)
  267. return ALC_INVALID_VALUE;
  268. mSndHandle = sio_open(nullptr, SIO_REC, 0);
  269. if(mSndHandle == nullptr)
  270. {
  271. ERR("Could not open device\n");
  272. return ALC_INVALID_VALUE;
  273. }
  274. sio_par par;
  275. sio_initpar(&par);
  276. switch(mDevice->FmtType)
  277. {
  278. case DevFmtByte:
  279. par.bps = 1;
  280. par.sig = 1;
  281. break;
  282. case DevFmtUByte:
  283. par.bps = 1;
  284. par.sig = 0;
  285. break;
  286. case DevFmtShort:
  287. par.bps = 2;
  288. par.sig = 1;
  289. break;
  290. case DevFmtUShort:
  291. par.bps = 2;
  292. par.sig = 0;
  293. break;
  294. case DevFmtInt:
  295. par.bps = 4;
  296. par.sig = 1;
  297. break;
  298. case DevFmtUInt:
  299. par.bps = 4;
  300. par.sig = 0;
  301. break;
  302. case DevFmtFloat:
  303. ERR("%s capture samples not supported\n", DevFmtTypeString(mDevice->FmtType));
  304. return ALC_INVALID_VALUE;
  305. }
  306. par.bits = par.bps * 8;
  307. par.le = SIO_LE_NATIVE;
  308. par.msb = SIO_LE_NATIVE ? 0 : 1;
  309. par.rchan = mDevice->channelsFromFmt();
  310. par.rate = mDevice->Frequency;
  311. par.appbufsz = maxu(mDevice->BufferSize, mDevice->Frequency/10);
  312. par.round = minu(par.appbufsz, mDevice->Frequency/40);
  313. mDevice->UpdateSize = par.round;
  314. mDevice->BufferSize = par.appbufsz;
  315. if(!sio_setpar(mSndHandle, &par) || !sio_getpar(mSndHandle, &par))
  316. {
  317. ERR("Failed to set device parameters\n");
  318. return ALC_INVALID_VALUE;
  319. }
  320. if(par.bits != par.bps*8)
  321. {
  322. ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8);
  323. return ALC_INVALID_VALUE;
  324. }
  325. if(!((mDevice->FmtType == DevFmtByte && par.bits == 8 && par.sig != 0) ||
  326. (mDevice->FmtType == DevFmtUByte && par.bits == 8 && par.sig == 0) ||
  327. (mDevice->FmtType == DevFmtShort && par.bits == 16 && par.sig != 0) ||
  328. (mDevice->FmtType == DevFmtUShort && par.bits == 16 && par.sig == 0) ||
  329. (mDevice->FmtType == DevFmtInt && par.bits == 32 && par.sig != 0) ||
  330. (mDevice->FmtType == DevFmtUInt && par.bits == 32 && par.sig == 0)) ||
  331. mDevice->channelsFromFmt() != (ALsizei)par.rchan ||
  332. mDevice->Frequency != par.rate)
  333. {
  334. ERR("Failed to set format %s %s %uhz, got %c%u %u-channel %uhz instead\n",
  335. DevFmtTypeString(mDevice->FmtType), DevFmtChannelsString(mDevice->FmtChans),
  336. mDevice->Frequency, par.sig?'s':'u', par.bits, par.rchan, par.rate);
  337. return ALC_INVALID_VALUE;
  338. }
  339. mRing = CreateRingBuffer(mDevice->BufferSize, par.bps*par.rchan, false);
  340. if(!mRing)
  341. {
  342. ERR("Failed to allocate %u-byte ringbuffer\n", mDevice->BufferSize*par.bps*par.rchan);
  343. return ALC_OUT_OF_MEMORY;
  344. }
  345. SetDefaultChannelOrder(mDevice);
  346. mDevice->DeviceName = name;
  347. return ALC_NO_ERROR;
  348. }
  349. ALCboolean SndioCapture::start()
  350. {
  351. if(!sio_start(mSndHandle))
  352. {
  353. ERR("Error starting playback\n");
  354. return ALC_FALSE;
  355. }
  356. try {
  357. mKillNow.store(false, std::memory_order_release);
  358. mThread = std::thread{std::mem_fn(&SndioCapture::recordProc), this};
  359. return ALC_TRUE;
  360. }
  361. catch(std::exception& e) {
  362. ERR("Could not create record thread: %s\n", e.what());
  363. }
  364. catch(...) {
  365. }
  366. sio_stop(mSndHandle);
  367. return ALC_FALSE;
  368. }
  369. void SndioCapture::stop()
  370. {
  371. if(mKillNow.exchange(true, std::memory_order_acq_rel) || !mThread.joinable())
  372. return;
  373. mThread.join();
  374. if(!sio_stop(mSndHandle))
  375. ERR("Error stopping device\n");
  376. }
  377. ALCenum SndioCapture::captureSamples(void *buffer, ALCuint samples)
  378. {
  379. mRing->read(buffer, samples);
  380. return ALC_NO_ERROR;
  381. }
  382. ALCuint SndioCapture::availableSamples()
  383. { return mRing->readSpace(); }
  384. } // namespace
  385. BackendFactory &SndIOBackendFactory::getFactory()
  386. {
  387. static SndIOBackendFactory factory{};
  388. return factory;
  389. }
  390. bool SndIOBackendFactory::init()
  391. { return true; }
  392. bool SndIOBackendFactory::querySupport(BackendType type)
  393. { return (type == BackendType::Playback || type == BackendType::Capture); }
  394. void SndIOBackendFactory::probe(DevProbe type, std::string *outnames)
  395. {
  396. switch(type)
  397. {
  398. case DevProbe::Playback:
  399. case DevProbe::Capture:
  400. /* Includes null char. */
  401. outnames->append(sndio_device, sizeof(sndio_device));
  402. break;
  403. }
  404. }
  405. BackendPtr SndIOBackendFactory::createBackend(ALCdevice *device, BackendType type)
  406. {
  407. if(type == BackendType::Playback)
  408. return BackendPtr{new SndioPlayback{device}};
  409. if(type == BackendType::Capture)
  410. return BackendPtr{new SndioCapture{device}};
  411. return nullptr;
  412. }