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.

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