The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

1044 lines
32KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE 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
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../juce_Config.h"
  24. #if JUCE_ALSA
  25. #include "linuxincludes.h"
  26. //==============================================================================
  27. /* Got an include error here? If so, you've either not got ALSA installed, or you've
  28. not got your paths set up correctly to find its header files.
  29. The package you need to install to get ASLA support is "libasound2-dev".
  30. If you don't have the ALSA library and don't want to build Juce with audio support,
  31. just disable the JUCE_ALSA flag in juce_Config.h
  32. */
  33. #include <alsa/asoundlib.h>
  34. //==============================================================================
  35. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  36. BEGIN_JUCE_NAMESPACE
  37. #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
  38. #include "../../../src/juce_core/threads/juce_Thread.h"
  39. #include "../../../src/juce_core/threads/juce_ScopedLock.h"
  40. #include "../../../src/juce_core/basics/juce_Time.h"
  41. #include "../../../src/juce_core/io/files/juce_File.h"
  42. #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
  43. #include "../../../src/juce_core/basics/juce_Singleton.h"
  44. #include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
  45. static const int maxNumChans = 64;
  46. //==============================================================================
  47. static void getDeviceSampleRates (snd_pcm_t* handle, Array <int>& rates)
  48. {
  49. const int ratesToTry[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
  50. snd_pcm_hw_params_t* hwParams;
  51. snd_pcm_hw_params_alloca (&hwParams);
  52. for (int i = 0; ratesToTry[i] != 0; ++i)
  53. {
  54. if (snd_pcm_hw_params_any (handle, hwParams) >= 0
  55. && snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
  56. {
  57. rates.addIfNotAlreadyThere (ratesToTry[i]);
  58. }
  59. }
  60. }
  61. static void getDeviceNumChannels (snd_pcm_t* handle, unsigned int* minChans, unsigned int* maxChans)
  62. {
  63. snd_pcm_hw_params_t *params;
  64. snd_pcm_hw_params_alloca (&params);
  65. if (snd_pcm_hw_params_any (handle, params) >= 0)
  66. {
  67. snd_pcm_hw_params_get_channels_min (params, minChans);
  68. snd_pcm_hw_params_get_channels_max (params, maxChans);
  69. }
  70. }
  71. static void getDeviceProperties (const String& id,
  72. unsigned int& minChansOut,
  73. unsigned int& maxChansOut,
  74. unsigned int& minChansIn,
  75. unsigned int& maxChansIn,
  76. Array <int>& rates)
  77. {
  78. if (id.isEmpty())
  79. return;
  80. snd_ctl_t* handle;
  81. if (snd_ctl_open (&handle, id.upToLastOccurrenceOf (T(","), false, false), SND_CTL_NONBLOCK) >= 0)
  82. {
  83. snd_pcm_info_t* info;
  84. snd_pcm_info_alloca (&info);
  85. snd_pcm_info_set_stream (info, SND_PCM_STREAM_PLAYBACK);
  86. snd_pcm_info_set_device (info, id.fromLastOccurrenceOf (T(","), false, false).getIntValue());
  87. snd_pcm_info_set_subdevice (info, 0);
  88. if (snd_ctl_pcm_info (handle, info) >= 0)
  89. {
  90. snd_pcm_t* pcmHandle;
  91. if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
  92. {
  93. getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
  94. getDeviceSampleRates (pcmHandle, rates);
  95. snd_pcm_close (pcmHandle);
  96. }
  97. }
  98. snd_pcm_info_set_stream (info, SND_PCM_STREAM_CAPTURE);
  99. if (snd_ctl_pcm_info (handle, info) >= 0)
  100. {
  101. snd_pcm_t* pcmHandle;
  102. if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
  103. {
  104. getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
  105. if (rates.size() == 0)
  106. getDeviceSampleRates (pcmHandle, rates);
  107. snd_pcm_close (pcmHandle);
  108. }
  109. }
  110. snd_ctl_close (handle);
  111. }
  112. }
  113. //==============================================================================
  114. class ALSADevice
  115. {
  116. public:
  117. ALSADevice (const String& id,
  118. const bool forInput)
  119. : handle (0),
  120. bitDepth (16),
  121. numChannelsRunning (0),
  122. isInput (forInput),
  123. sampleFormat (AudioDataConverters::int16LE)
  124. {
  125. failed (snd_pcm_open (&handle, id,
  126. forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
  127. SND_PCM_ASYNC));
  128. }
  129. ~ALSADevice()
  130. {
  131. if (handle != 0)
  132. snd_pcm_close (handle);
  133. }
  134. bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
  135. {
  136. if (handle == 0)
  137. return false;
  138. snd_pcm_hw_params_t* hwParams;
  139. snd_pcm_hw_params_alloca (&hwParams);
  140. if (failed (snd_pcm_hw_params_any (handle, hwParams)))
  141. return false;
  142. if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
  143. isInterleaved = false;
  144. else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0)
  145. isInterleaved = true;
  146. else
  147. {
  148. jassertfalse
  149. return false;
  150. }
  151. const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32, AudioDataConverters::float32LE,
  152. SND_PCM_FORMAT_FLOAT_BE, 32, AudioDataConverters::float32BE,
  153. SND_PCM_FORMAT_S32_LE, 32, AudioDataConverters::int32LE,
  154. SND_PCM_FORMAT_S32_BE, 32, AudioDataConverters::int32BE,
  155. SND_PCM_FORMAT_S24_3LE, 24, AudioDataConverters::int24LE,
  156. SND_PCM_FORMAT_S24_3BE, 24, AudioDataConverters::int24BE,
  157. SND_PCM_FORMAT_S16_LE, 16, AudioDataConverters::int16LE,
  158. SND_PCM_FORMAT_S16_BE, 16, AudioDataConverters::int16BE };
  159. bitDepth = 0;
  160. for (int i = 0; i < numElementsInArray (formatsToTry); i += 3)
  161. {
  162. if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
  163. {
  164. bitDepth = formatsToTry [i + 1];
  165. sampleFormat = (AudioDataConverters::DataFormat) formatsToTry [i + 2];
  166. break;
  167. }
  168. }
  169. if (bitDepth == 0)
  170. {
  171. error = "device doesn't support a compatible PCM format";
  172. DBG (T("ALSA error: ") + error + T("\n"));
  173. return false;
  174. }
  175. int dir = 0;
  176. unsigned int periods = 4;
  177. snd_pcm_uframes_t samplesPerPeriod = bufferSize;
  178. if (failed (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
  179. || failed (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
  180. || failed (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
  181. || failed (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
  182. || failed (snd_pcm_hw_params (handle, hwParams)))
  183. {
  184. return false;
  185. }
  186. snd_pcm_sw_params_t* swParams;
  187. snd_pcm_sw_params_alloca (&swParams);
  188. snd_pcm_uframes_t boundary;
  189. if (failed (snd_pcm_sw_params_current (handle, swParams))
  190. || failed (snd_pcm_sw_params_get_boundary (swParams, &boundary))
  191. || failed (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
  192. || failed (snd_pcm_sw_params_set_silence_size (handle, swParams, boundary))
  193. || failed (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
  194. || failed (snd_pcm_sw_params_set_stop_threshold (handle, swParams, boundary))
  195. || failed (snd_pcm_sw_params (handle, swParams)))
  196. {
  197. return false;
  198. }
  199. /*
  200. #ifdef JUCE_DEBUG
  201. // enable this to dump the config of the devices that get opened
  202. snd_output_t* out;
  203. snd_output_stdio_attach (&out, stderr, 0);
  204. snd_pcm_hw_params_dump (hwParams, out);
  205. snd_pcm_sw_params_dump (swParams, out);
  206. #endif
  207. */
  208. numChannelsRunning = numChannels;
  209. return true;
  210. }
  211. //==============================================================================
  212. bool write (float** const data, const int numSamples)
  213. {
  214. if (isInterleaved)
  215. {
  216. scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
  217. float* interleaved = (float*) scratch;
  218. AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning);
  219. AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
  220. snd_pcm_sframes_t num = snd_pcm_writei (handle, (void*) interleaved, numSamples);
  221. if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
  222. return false;
  223. }
  224. else
  225. {
  226. for (int i = 0; i < numChannelsRunning; ++i)
  227. if (data[i] != 0)
  228. AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples);
  229. snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples);
  230. if (failed (num))
  231. {
  232. if (num == -EPIPE)
  233. {
  234. if (failed (snd_pcm_prepare (handle)))
  235. return false;
  236. }
  237. else if (num != -ESTRPIPE)
  238. return false;
  239. }
  240. }
  241. return true;
  242. }
  243. bool read (float** const data, const int numSamples)
  244. {
  245. if (isInterleaved)
  246. {
  247. scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
  248. float* interleaved = (float*) scratch;
  249. snd_pcm_sframes_t num = snd_pcm_readi (handle, (void*) interleaved, numSamples);
  250. if (failed (num))
  251. {
  252. if (num == -EPIPE)
  253. {
  254. if (failed (snd_pcm_prepare (handle)))
  255. return false;
  256. }
  257. else if (num != -ESTRPIPE)
  258. return false;
  259. }
  260. AudioDataConverters::convertFormatToFloat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
  261. AudioDataConverters::deinterleaveSamples (interleaved, data, numSamples, numChannelsRunning);
  262. }
  263. else
  264. {
  265. snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
  266. if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
  267. return false;
  268. for (int i = 0; i < numChannelsRunning; ++i)
  269. if (data[i] != 0)
  270. AudioDataConverters::convertFormatToFloat (sampleFormat, data[i], data[i], numSamples);
  271. }
  272. return true;
  273. }
  274. //==============================================================================
  275. juce_UseDebuggingNewOperator
  276. snd_pcm_t* handle;
  277. String error;
  278. int bitDepth, numChannelsRunning;
  279. //==============================================================================
  280. private:
  281. const bool isInput;
  282. bool isInterleaved;
  283. MemoryBlock scratch;
  284. AudioDataConverters::DataFormat sampleFormat;
  285. //==============================================================================
  286. bool failed (const int errorNum)
  287. {
  288. if (errorNum >= 0)
  289. return false;
  290. error = snd_strerror (errorNum);
  291. DBG (T("ALSA error: ") + error + T("\n"));
  292. return true;
  293. }
  294. };
  295. //==============================================================================
  296. class ALSAThread : public Thread
  297. {
  298. public:
  299. ALSAThread (const String& inputId_,
  300. const String& outputId_)
  301. : Thread ("Juce ALSA"),
  302. sampleRate (0),
  303. bufferSize (0),
  304. callback (0),
  305. inputId (inputId_),
  306. outputId (outputId_),
  307. outputDevice (0),
  308. inputDevice (0),
  309. numCallbacks (0),
  310. totalNumInputChannels (0),
  311. totalNumOutputChannels (0)
  312. {
  313. zeromem (outputChannelData, sizeof (outputChannelData));
  314. zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
  315. zeromem (inputChannelData, sizeof (inputChannelData));
  316. zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
  317. initialiseRatesAndChannels();
  318. }
  319. ~ALSAThread()
  320. {
  321. close();
  322. }
  323. void open (const BitArray& inputChannels,
  324. const BitArray& outputChannels,
  325. const double sampleRate_,
  326. const int bufferSize_)
  327. {
  328. close();
  329. error = String::empty;
  330. sampleRate = sampleRate_;
  331. bufferSize = bufferSize_;
  332. currentInputChans.clear();
  333. currentOutputChans.clear();
  334. if (inputChannels.getHighestBit() >= 0)
  335. {
  336. for (int i = 0; i <= inputChannels.getHighestBit(); ++i)
  337. {
  338. inputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
  339. if (inputChannels[i])
  340. {
  341. inputChannelDataForCallback [totalNumInputChannels++] = inputChannelData [i];
  342. currentInputChans.setBit (i);
  343. }
  344. }
  345. }
  346. if (outputChannels.getHighestBit() >= 0)
  347. {
  348. for (int i = 0; i <= outputChannels.getHighestBit(); ++i)
  349. {
  350. outputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
  351. if (outputChannels[i])
  352. {
  353. outputChannelDataForCallback [totalNumOutputChannels++] = outputChannelData [i];
  354. currentOutputChans.setBit (i);
  355. }
  356. }
  357. }
  358. if (totalNumOutputChannels > 0 && outputId.isNotEmpty())
  359. {
  360. outputDevice = new ALSADevice (outputId, false);
  361. if (outputDevice->error.isNotEmpty())
  362. {
  363. error = outputDevice->error;
  364. deleteAndZero (outputDevice);
  365. return;
  366. }
  367. if (! outputDevice->setParameters ((unsigned int) sampleRate,
  368. jlimit ((int) minChansOut, (int) maxChansOut, currentOutputChans.getHighestBit() + 1),
  369. bufferSize))
  370. {
  371. error = outputDevice->error;
  372. deleteAndZero (outputDevice);
  373. return;
  374. }
  375. }
  376. if (totalNumInputChannels > 0 && inputId.isNotEmpty())
  377. {
  378. inputDevice = new ALSADevice (inputId, true);
  379. if (inputDevice->error.isNotEmpty())
  380. {
  381. error = inputDevice->error;
  382. deleteAndZero (inputDevice);
  383. return;
  384. }
  385. if (! inputDevice->setParameters ((unsigned int) sampleRate,
  386. jlimit ((int) minChansIn, (int) maxChansIn, currentInputChans.getHighestBit() + 1),
  387. bufferSize))
  388. {
  389. error = inputDevice->error;
  390. deleteAndZero (inputDevice);
  391. return;
  392. }
  393. }
  394. if (outputDevice == 0 && inputDevice == 0)
  395. {
  396. error = "no channels";
  397. return;
  398. }
  399. if (outputDevice != 0 && inputDevice != 0)
  400. {
  401. snd_pcm_link (outputDevice->handle, inputDevice->handle);
  402. }
  403. if (inputDevice != 0 && failed (snd_pcm_prepare (inputDevice->handle)))
  404. return;
  405. if (outputDevice != 0 && failed (snd_pcm_prepare (outputDevice->handle)))
  406. return;
  407. startThread (9);
  408. int count = 1000;
  409. while (numCallbacks == 0)
  410. {
  411. sleep (5);
  412. if (--count < 0 || ! isThreadRunning())
  413. {
  414. error = "device didn't start";
  415. break;
  416. }
  417. }
  418. }
  419. void close()
  420. {
  421. stopThread (6000);
  422. deleteAndZero (inputDevice);
  423. deleteAndZero (outputDevice);
  424. for (int i = 0; i < maxNumChans; ++i)
  425. {
  426. juce_free (inputChannelData [i]);
  427. juce_free (outputChannelData [i]);
  428. }
  429. zeromem (outputChannelData, sizeof (outputChannelData));
  430. zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
  431. zeromem (inputChannelData, sizeof (inputChannelData));
  432. zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
  433. totalNumOutputChannels = 0;
  434. totalNumInputChannels = 0;
  435. numCallbacks = 0;
  436. }
  437. void setCallback (AudioIODeviceCallback* const newCallback) throw()
  438. {
  439. const ScopedLock sl (callbackLock);
  440. callback = newCallback;
  441. }
  442. void run()
  443. {
  444. while (! threadShouldExit())
  445. {
  446. if (inputDevice != 0)
  447. {
  448. if (! inputDevice->read (inputChannelData, bufferSize))
  449. {
  450. DBG ("ALSA: read failure");
  451. break;
  452. }
  453. }
  454. if (threadShouldExit())
  455. break;
  456. {
  457. const ScopedLock sl (callbackLock);
  458. ++numCallbacks;
  459. if (callback != 0)
  460. {
  461. callback->audioDeviceIOCallback ((const float**) inputChannelDataForCallback,
  462. totalNumInputChannels,
  463. outputChannelDataForCallback,
  464. totalNumOutputChannels,
  465. bufferSize);
  466. }
  467. else
  468. {
  469. for (int i = 0; i < totalNumOutputChannels; ++i)
  470. zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
  471. }
  472. }
  473. if (outputDevice != 0)
  474. {
  475. failed (snd_pcm_wait (outputDevice->handle, 2000));
  476. if (threadShouldExit())
  477. break;
  478. failed (snd_pcm_avail_update (outputDevice->handle));
  479. if (! outputDevice->write (outputChannelData, bufferSize))
  480. {
  481. DBG ("ALSA: write failure");
  482. break;
  483. }
  484. }
  485. }
  486. }
  487. int getBitDepth() const throw()
  488. {
  489. if (outputDevice != 0)
  490. return outputDevice->bitDepth;
  491. if (inputDevice != 0)
  492. return inputDevice->bitDepth;
  493. return 16;
  494. }
  495. //==============================================================================
  496. juce_UseDebuggingNewOperator
  497. String error;
  498. double sampleRate;
  499. int bufferSize;
  500. BitArray currentInputChans, currentOutputChans;
  501. Array <int> sampleRates;
  502. StringArray channelNamesOut, channelNamesIn;
  503. AudioIODeviceCallback* callback;
  504. private:
  505. //==============================================================================
  506. const String inputId, outputId;
  507. ALSADevice* outputDevice;
  508. ALSADevice* inputDevice;
  509. int numCallbacks;
  510. CriticalSection callbackLock;
  511. float* outputChannelData [maxNumChans];
  512. float* outputChannelDataForCallback [maxNumChans];
  513. int totalNumInputChannels;
  514. float* inputChannelData [maxNumChans];
  515. float* inputChannelDataForCallback [maxNumChans];
  516. int totalNumOutputChannels;
  517. unsigned int minChansOut, maxChansOut;
  518. unsigned int minChansIn, maxChansIn;
  519. bool failed (const int errorNum) throw()
  520. {
  521. if (errorNum >= 0)
  522. return false;
  523. error = snd_strerror (errorNum);
  524. DBG (T("ALSA error: ") + error + T("\n"));
  525. return true;
  526. }
  527. void initialiseRatesAndChannels() throw()
  528. {
  529. sampleRates.clear();
  530. channelNamesOut.clear();
  531. channelNamesIn.clear();
  532. minChansOut = 0;
  533. maxChansOut = 0;
  534. minChansIn = 0;
  535. maxChansIn = 0;
  536. unsigned int dummy = 0;
  537. getDeviceProperties (inputId, dummy, dummy, minChansIn, maxChansIn, sampleRates);
  538. getDeviceProperties (outputId, minChansOut, maxChansOut, dummy, dummy, sampleRates);
  539. unsigned int i;
  540. for (i = 0; i < maxChansOut; ++i)
  541. channelNamesOut.add (T("channel ") + String ((int) i + 1));
  542. for (i = 0; i < maxChansIn; ++i)
  543. channelNamesIn.add (T("channel ") + String ((int) i + 1));
  544. }
  545. };
  546. //==============================================================================
  547. class ALSAAudioIODevice : public AudioIODevice
  548. {
  549. public:
  550. ALSAAudioIODevice (const String& deviceName,
  551. const String& inputId_,
  552. const String& outputId_)
  553. : AudioIODevice (deviceName, T("ALSA")),
  554. inputId (inputId_),
  555. outputId (outputId_),
  556. isOpen_ (false),
  557. isStarted (false),
  558. internal (0)
  559. {
  560. internal = new ALSAThread (inputId, outputId);
  561. }
  562. ~ALSAAudioIODevice()
  563. {
  564. delete internal;
  565. }
  566. const StringArray getOutputChannelNames()
  567. {
  568. return internal->channelNamesOut;
  569. }
  570. const StringArray getInputChannelNames()
  571. {
  572. return internal->channelNamesIn;
  573. }
  574. int getNumSampleRates()
  575. {
  576. return internal->sampleRates.size();
  577. }
  578. double getSampleRate (int index)
  579. {
  580. return internal->sampleRates [index];
  581. }
  582. int getNumBufferSizesAvailable()
  583. {
  584. return 50;
  585. }
  586. int getBufferSizeSamples (int index)
  587. {
  588. int n = 16;
  589. for (int i = 0; i < index; ++i)
  590. n += n < 64 ? 16
  591. : (n < 512 ? 32
  592. : (n < 1024 ? 64
  593. : (n < 2048 ? 128 : 256)));
  594. return n;
  595. }
  596. int getDefaultBufferSize()
  597. {
  598. return 512;
  599. }
  600. const String open (const BitArray& inputChannels,
  601. const BitArray& outputChannels,
  602. double sampleRate,
  603. int bufferSizeSamples)
  604. {
  605. close();
  606. if (bufferSizeSamples <= 0)
  607. bufferSizeSamples = getDefaultBufferSize();
  608. if (sampleRate <= 0)
  609. {
  610. for (int i = 0; i < getNumSampleRates(); ++i)
  611. {
  612. if (getSampleRate (i) >= 44100)
  613. {
  614. sampleRate = getSampleRate (i);
  615. break;
  616. }
  617. }
  618. }
  619. internal->open (inputChannels, outputChannels,
  620. sampleRate, bufferSizeSamples);
  621. isOpen_ = internal->error.isEmpty();
  622. return internal->error;
  623. }
  624. void close()
  625. {
  626. stop();
  627. internal->close();
  628. isOpen_ = false;
  629. }
  630. bool isOpen()
  631. {
  632. return isOpen_;
  633. }
  634. int getCurrentBufferSizeSamples()
  635. {
  636. return internal->bufferSize;
  637. }
  638. double getCurrentSampleRate()
  639. {
  640. return internal->sampleRate;
  641. }
  642. int getCurrentBitDepth()
  643. {
  644. return internal->getBitDepth();
  645. }
  646. const BitArray getActiveOutputChannels() const
  647. {
  648. return internal->currentOutputChans;
  649. }
  650. const BitArray getActiveInputChannels() const
  651. {
  652. return internal->currentInputChans;
  653. }
  654. int getOutputLatencyInSamples()
  655. {
  656. return 0;
  657. }
  658. int getInputLatencyInSamples()
  659. {
  660. return 0;
  661. }
  662. void start (AudioIODeviceCallback* callback)
  663. {
  664. if (! isOpen_)
  665. callback = 0;
  666. internal->setCallback (callback);
  667. if (callback != 0)
  668. callback->audioDeviceAboutToStart (this);
  669. isStarted = (callback != 0);
  670. }
  671. void stop()
  672. {
  673. AudioIODeviceCallback* const oldCallback = internal->callback;
  674. start (0);
  675. if (oldCallback != 0)
  676. oldCallback->audioDeviceStopped();
  677. }
  678. bool isPlaying()
  679. {
  680. return isStarted && internal->error.isEmpty();
  681. }
  682. const String getLastError()
  683. {
  684. return internal->error;
  685. }
  686. String inputId, outputId;
  687. private:
  688. bool isOpen_, isStarted;
  689. ALSAThread* internal;
  690. };
  691. //==============================================================================
  692. class ALSAAudioIODeviceType : public AudioIODeviceType
  693. {
  694. public:
  695. //==============================================================================
  696. ALSAAudioIODeviceType()
  697. : AudioIODeviceType (T("ALSA")),
  698. hasScanned (false)
  699. {
  700. }
  701. ~ALSAAudioIODeviceType()
  702. {
  703. }
  704. //==============================================================================
  705. void scanForDevices()
  706. {
  707. if (hasScanned)
  708. return;
  709. hasScanned = true;
  710. inputNames.clear();
  711. inputIds.clear();
  712. outputNames.clear();
  713. outputIds.clear();
  714. snd_ctl_t* handle;
  715. snd_ctl_card_info_t* info;
  716. snd_ctl_card_info_alloca (&info);
  717. int cardNum = -1;
  718. while (outputIds.size() + inputIds.size() <= 32)
  719. {
  720. snd_card_next (&cardNum);
  721. if (cardNum < 0)
  722. break;
  723. if (snd_ctl_open (&handle, T("hw:") + String (cardNum), SND_CTL_NONBLOCK) >= 0)
  724. {
  725. if (snd_ctl_card_info (handle, info) >= 0)
  726. {
  727. String cardId (snd_ctl_card_info_get_id (info));
  728. if (cardId.removeCharacters (T("0123456789")).isEmpty())
  729. cardId = String (cardNum);
  730. int device = -1;
  731. for (;;)
  732. {
  733. if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
  734. break;
  735. String id, name;
  736. id << "hw:" << cardId << ',' << device;
  737. bool isInput, isOutput;
  738. if (testDevice (id, isInput, isOutput))
  739. {
  740. name << snd_ctl_card_info_get_name (info);
  741. if (name.isEmpty())
  742. name = id;
  743. if (isInput)
  744. {
  745. inputNames.add (name);
  746. inputIds.add (id);
  747. }
  748. if (isOutput)
  749. {
  750. outputNames.add (name);
  751. outputIds.add (id);
  752. }
  753. }
  754. }
  755. }
  756. snd_ctl_close (handle);
  757. }
  758. }
  759. inputNames.appendNumbersToDuplicates (false, true);
  760. outputNames.appendNumbersToDuplicates (false, true);
  761. }
  762. const StringArray getDeviceNames (const bool wantInputNames) const
  763. {
  764. jassert (hasScanned); // need to call scanForDevices() before doing this
  765. return wantInputNames ? inputNames : outputNames;
  766. }
  767. int getDefaultDeviceIndex (const bool forInput) const
  768. {
  769. jassert (hasScanned); // need to call scanForDevices() before doing this
  770. return 0;
  771. }
  772. bool hasSeparateInputsAndOutputs() const { return true; }
  773. int getIndexOfDevice (AudioIODevice* device, const bool asInput) const
  774. {
  775. jassert (hasScanned); // need to call scanForDevices() before doing this
  776. ALSAAudioIODevice* const d = dynamic_cast <ALSAAudioIODevice*> (device);
  777. if (d == 0)
  778. return -1;
  779. return asInput ? inputIds.indexOf (d->inputId)
  780. : outputIds.indexOf (d->outputId);
  781. }
  782. AudioIODevice* createDevice (const String& outputDeviceName,
  783. const String& inputDeviceName)
  784. {
  785. jassert (hasScanned); // need to call scanForDevices() before doing this
  786. const int inputIndex = inputNames.indexOf (inputDeviceName);
  787. const int outputIndex = outputNames.indexOf (outputDeviceName);
  788. String deviceName (outputDeviceName);
  789. if (deviceName.isEmpty())
  790. deviceName = inputDeviceName;
  791. if (index >= 0)
  792. return new ALSAAudioIODevice (deviceName,
  793. inputIds [inputIndex],
  794. outputIds [outputIndex]);
  795. return 0;
  796. }
  797. //==============================================================================
  798. juce_UseDebuggingNewOperator
  799. private:
  800. StringArray inputNames, outputNames, inputIds, outputIds;
  801. bool hasScanned;
  802. static bool testDevice (const String& id, bool& isInput, bool& isOutput)
  803. {
  804. unsigned int minChansOut = 0, maxChansOut = 0;
  805. unsigned int minChansIn = 0, maxChansIn = 0;
  806. Array <int> rates;
  807. getDeviceProperties (id, minChansOut, maxChansOut, minChansIn, maxChansIn, rates);
  808. DBG (T("ALSA device: ") + id
  809. + T(" outs=") + String ((int) minChansOut) + T("-") + String ((int) maxChansOut)
  810. + T(" ins=") + String ((int) minChansIn) + T("-") + String ((int) maxChansIn)
  811. + T(" rates=") + String (rates.size()));
  812. isInput = maxChansIn > 0;
  813. isOutput = maxChansOut > 0;
  814. return (isInput || isOutput) && rates.size() > 0;
  815. }
  816. ALSAAudioIODeviceType (const ALSAAudioIODeviceType&);
  817. const ALSAAudioIODeviceType& operator= (const ALSAAudioIODeviceType&);
  818. };
  819. //==============================================================================
  820. AudioIODeviceType* juce_createDefaultAudioIODeviceType()
  821. {
  822. return new ALSAAudioIODeviceType();
  823. }
  824. END_JUCE_NAMESPACE
  825. //==============================================================================
  826. #else // if ALSA is turned off..
  827. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  828. BEGIN_JUCE_NAMESPACE
  829. #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
  830. AudioIODeviceType* juce_createDefaultAudioIODeviceType() { return 0; }
  831. END_JUCE_NAMESPACE
  832. #endif