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.

1016 lines
31KB

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