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.

1010 lines
31KB

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