|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-7 by Raw Material Software ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the
- GNU General Public License, as published by the Free Software Foundation;
- either version 2 of the License, or (at your option) any later version.
-
- JUCE is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with JUCE; if not, visit www.gnu.org/licenses or write to the
- Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- Boston, MA 02111-1307 USA
-
- ------------------------------------------------------------------------------
-
- If you'd like to release a closed-source product which uses JUCE, commercial
- licenses are also available: visit www.rawmaterialsoftware.com/juce for
- more information.
-
- ==============================================================================
- */
-
- #include "../../../juce_Config.h"
- #if JUCE_BUILD_GUI_CLASSES
-
- #if JUCE_ALSA
-
- #include "linuxincludes.h"
-
- //==============================================================================
- /* Got an include error here? If so, you've either not got ALSA installed, or you've
- not got your paths set up correctly to find its header files.
-
- The package you need to install to get ASLA support is "libasound2-dev".
-
- If you don't have the ALSA library and don't want to build Juce with audio support,
- just disable the JUCE_ALSA flag in juce_Config.h
- */
- #include <alsa/asoundlib.h>
-
-
- //==============================================================================
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
- #include "../../../src/juce_core/threads/juce_Thread.h"
- #include "../../../src/juce_core/threads/juce_ScopedLock.h"
- #include "../../../src/juce_core/basics/juce_Time.h"
- #include "../../../src/juce_core/io/files/juce_File.h"
- #include "../../../src/juce_core/io/files/juce_FileInputStream.h"
- #include "../../../src/juce_core/basics/juce_Singleton.h"
- #include "../../../src/juce_appframework/audio/dsp/juce_AudioDataConverters.h"
-
- static const int maxNumChans = 64;
-
-
- //==============================================================================
- static void getDeviceSampleRates (snd_pcm_t* handle, Array <int>& rates)
- {
- const int ratesToTry[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 };
-
- snd_pcm_hw_params_t* hwParams;
- snd_pcm_hw_params_alloca (&hwParams);
-
- for (int i = 0; ratesToTry[i] != 0; ++i)
- {
- if (snd_pcm_hw_params_any (handle, hwParams) >= 0
- && snd_pcm_hw_params_test_rate (handle, hwParams, ratesToTry[i], 0) == 0)
- {
- rates.add (ratesToTry[i]);
- }
- }
- }
-
- static void getDeviceNumChannels (snd_pcm_t* handle, unsigned int* minChans, unsigned int* maxChans)
- {
- snd_pcm_hw_params_t *params;
- snd_pcm_hw_params_alloca (¶ms);
-
- if (snd_pcm_hw_params_any (handle, params) >= 0)
- {
- snd_pcm_hw_params_get_channels_min (params, minChans);
- snd_pcm_hw_params_get_channels_max (params, maxChans);
- }
- }
-
- static void getDeviceProperties (const String& id,
- unsigned int& minChansOut,
- unsigned int& maxChansOut,
- unsigned int& minChansIn,
- unsigned int& maxChansIn,
- Array <int>& rates)
- {
- snd_ctl_t* handle;
-
- if (snd_ctl_open (&handle, id.upToLastOccurrenceOf (T(","), false, false), SND_CTL_NONBLOCK) >= 0)
- {
- snd_pcm_info_t* info;
- snd_pcm_info_alloca (&info);
-
- snd_pcm_info_set_stream (info, SND_PCM_STREAM_PLAYBACK);
- snd_pcm_info_set_device (info, id.fromLastOccurrenceOf (T(","), false, false).getIntValue());
- snd_pcm_info_set_subdevice (info, 0);
-
- if (snd_ctl_pcm_info (handle, info) >= 0)
- {
- snd_pcm_t* pcmHandle;
- if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_PLAYBACK, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
- {
- getDeviceNumChannels (pcmHandle, &minChansOut, &maxChansOut);
- getDeviceSampleRates (pcmHandle, rates);
-
- snd_pcm_close (pcmHandle);
- }
- }
-
- snd_pcm_info_set_stream (info, SND_PCM_STREAM_CAPTURE);
-
- if (snd_ctl_pcm_info (handle, info) >= 0)
- {
- snd_pcm_t* pcmHandle;
- if (snd_pcm_open (&pcmHandle, id, SND_PCM_STREAM_CAPTURE, SND_PCM_ASYNC | SND_PCM_NONBLOCK ) >= 0)
- {
- getDeviceNumChannels (pcmHandle, &minChansIn, &maxChansIn);
-
- if (rates.size() == 0)
- getDeviceSampleRates (pcmHandle, rates);
-
- snd_pcm_close (pcmHandle);
- }
- }
-
- snd_ctl_close (handle);
- }
- }
-
- //==============================================================================
- class ALSADevice
- {
- public:
- ALSADevice (const String& deviceName,
- const bool forInput)
- : handle (0),
- bitDepth (16),
- numChannelsRunning (0),
- isInput (forInput),
- sampleFormat (AudioDataConverters::int16LE)
- {
- failed (snd_pcm_open (&handle, deviceName,
- forInput ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
- SND_PCM_ASYNC));
- }
-
- ~ALSADevice()
- {
- if (handle != 0)
- snd_pcm_close (handle);
- }
-
- bool setParameters (unsigned int sampleRate, int numChannels, int bufferSize)
- {
- if (handle == 0)
- return false;
-
- snd_pcm_hw_params_t* hwParams;
- snd_pcm_hw_params_alloca (&hwParams);
-
- if (failed (snd_pcm_hw_params_any (handle, hwParams)))
- return false;
-
- if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_NONINTERLEAVED) >= 0)
- isInterleaved = false;
- else if (snd_pcm_hw_params_set_access (handle, hwParams, SND_PCM_ACCESS_RW_INTERLEAVED) >= 0)
- isInterleaved = true;
- else
- {
- jassertfalse
- return false;
- }
-
- const int formatsToTry[] = { SND_PCM_FORMAT_FLOAT_LE, 32, AudioDataConverters::float32LE,
- SND_PCM_FORMAT_FLOAT_BE, 32, AudioDataConverters::float32BE,
- SND_PCM_FORMAT_S32_LE, 32, AudioDataConverters::int32LE,
- SND_PCM_FORMAT_S32_BE, 32, AudioDataConverters::int32BE,
- SND_PCM_FORMAT_S24_LE, 24, AudioDataConverters::int24LE,
- SND_PCM_FORMAT_S24_BE, 24, AudioDataConverters::int24BE,
- SND_PCM_FORMAT_S16_LE, 16, AudioDataConverters::int16LE,
- SND_PCM_FORMAT_S16_BE, 16, AudioDataConverters::int16BE };
- bitDepth = 0;
-
- for (int i = 0; i < numElementsInArray (formatsToTry); i += 3)
- {
- if (snd_pcm_hw_params_set_format (handle, hwParams, (_snd_pcm_format) formatsToTry [i]) >= 0)
- {
- bitDepth = formatsToTry [i + 1];
- sampleFormat = (AudioDataConverters::DataFormat) formatsToTry [i + 2];
- break;
- }
- }
-
- if (bitDepth == 0)
- {
- error = "device doesn't support a compatible PCM format";
- DBG (T("ALSA error: ") + error + T("\n"));
- return false;
- }
-
- int dir = 0;
- unsigned int periods = 4;
- snd_pcm_uframes_t samplesPerPeriod = bufferSize;
-
- if (failed (snd_pcm_hw_params_set_rate_near (handle, hwParams, &sampleRate, 0))
- || failed (snd_pcm_hw_params_set_channels (handle, hwParams, numChannels))
- || failed (snd_pcm_hw_params_set_periods_near (handle, hwParams, &periods, &dir))
- || failed (snd_pcm_hw_params_set_period_size_near (handle, hwParams, &samplesPerPeriod, &dir))
- || failed (snd_pcm_hw_params (handle, hwParams)))
- {
- return false;
- }
-
- snd_pcm_sw_params_t* swParams;
- snd_pcm_sw_params_alloca (&swParams);
-
- if (failed (snd_pcm_sw_params_current (handle, swParams))
- || failed (snd_pcm_sw_params_set_silence_threshold (handle, swParams, 0))
- || failed (snd_pcm_sw_params_set_silence_size (handle, swParams, INT_MAX))
- || failed (snd_pcm_sw_params_set_start_threshold (handle, swParams, samplesPerPeriod))
- || failed (snd_pcm_sw_params_set_stop_threshold (handle, swParams, INT_MAX))
- || failed (snd_pcm_sw_params (handle, swParams)))
- {
- return false;
- }
-
- /*
- #ifdef JUCE_DEBUG
- // enable this to dump the config of the devices that get opened
- snd_output_t* out;
- snd_output_stdio_attach (&out, stderr, 0);
- snd_pcm_hw_params_dump (hwParams, out);
- snd_pcm_sw_params_dump (swParams, out);
- #endif
- */
-
- numChannelsRunning = numChannels;
-
- return true;
- }
-
- //==============================================================================
- bool write (float** const data, const int numSamples)
- {
- if (isInterleaved)
- {
- scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
- float* interleaved = (float*) scratch;
-
- AudioDataConverters::interleaveSamples ((const float**) data, interleaved, numSamples, numChannelsRunning);
- AudioDataConverters::convertFloatToFormat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
-
- snd_pcm_sframes_t num = snd_pcm_writei (handle, (void*) interleaved, numSamples);
-
- if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
- return false;
- }
- else
- {
- for (int i = 0; i < numChannelsRunning; ++i)
- if (data[i] != 0)
- AudioDataConverters::convertFloatToFormat (sampleFormat, data[i], data[i], numSamples);
-
- snd_pcm_sframes_t num = snd_pcm_writen (handle, (void**) data, numSamples);
-
- if (failed (num))
- {
- if (num == -EPIPE)
- {
- if (failed (snd_pcm_prepare (handle)))
- return false;
- }
- else if (num != -ESTRPIPE)
- return false;
- }
- }
-
- return true;
- }
-
- bool read (float** const data, const int numSamples)
- {
- if (isInterleaved)
- {
- scratch.ensureSize (sizeof (float) * numSamples * numChannelsRunning, false);
- float* interleaved = (float*) scratch;
-
- snd_pcm_sframes_t num = snd_pcm_readi (handle, (void*) interleaved, numSamples);
-
- if (failed (num))
- {
- if (num == -EPIPE)
- {
- if (failed (snd_pcm_prepare (handle)))
- return false;
- }
- else if (num != -ESTRPIPE)
- return false;
- }
-
- AudioDataConverters::convertFormatToFloat (sampleFormat, interleaved, interleaved, numSamples * numChannelsRunning);
- AudioDataConverters::deinterleaveSamples (interleaved, data, numSamples, numChannelsRunning);
- }
- else
- {
- snd_pcm_sframes_t num = snd_pcm_readn (handle, (void**) data, numSamples);
-
- if (failed (num) && num != -EPIPE && num != -ESTRPIPE)
- return false;
-
- for (int i = 0; i < numChannelsRunning; ++i)
- if (data[i] != 0)
- AudioDataConverters::convertFormatToFloat (sampleFormat, data[i], data[i], numSamples);
- }
-
- return true;
- }
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
- snd_pcm_t* handle;
- String error;
- int bitDepth, numChannelsRunning;
-
- //==============================================================================
- private:
- const bool isInput;
- bool isInterleaved;
- MemoryBlock scratch;
- AudioDataConverters::DataFormat sampleFormat;
-
- //==============================================================================
- bool failed (const int errorNum)
- {
- if (errorNum >= 0)
- return false;
-
- error = snd_strerror (errorNum);
- DBG (T("ALSA error: ") + error + T("\n"));
- return true;
- }
- };
-
- //==============================================================================
- class ALSAThread : public Thread
- {
- public:
- ALSAThread (const String& deviceName_)
- : Thread ("Juce ALSA"),
- sampleRate (0),
- bufferSize (0),
- callback (0),
- deviceName (deviceName_),
- outputDevice (0),
- inputDevice (0),
- numCallbacks (0),
- totalNumInputChannels (0),
- totalNumOutputChannels (0)
- {
- zeromem (outputChannelData, sizeof (outputChannelData));
- zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
- zeromem (inputChannelData, sizeof (inputChannelData));
- zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
-
- initialiseRatesAndChannels();
- }
-
- ~ALSAThread()
- {
- close();
- }
-
- void open (const BitArray& inputChannels,
- const BitArray& outputChannels,
- const double sampleRate_,
- const int bufferSize_)
- {
- close();
-
- error = String::empty;
- sampleRate = sampleRate_;
- bufferSize = bufferSize_;
- currentInputChans.clear();
- currentOutputChans.clear();
-
- numChannelsRunning = jmax (inputChannels.getHighestBit(),
- outputChannels.getHighestBit()) + 1;
-
- numChannelsRunning = jmin (maxNumChans, jlimit ((int) minChansIn,
- (int) maxChansIn,
- numChannelsRunning));
-
- if (inputChannels.getHighestBit() >= 0)
- {
- for (int i = 0; i < numChannelsRunning; ++i)
- {
- inputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
-
- if (inputChannels[i])
- {
- inputChannelDataForCallback [totalNumInputChannels++] = inputChannelData [i];
- currentInputChans.setBit (i);
- }
- }
- }
-
- if (outputChannels.getHighestBit() >= 0)
- {
- for (int i = 0; i < numChannelsRunning; ++i)
- {
- outputChannelData [i] = (float*) juce_calloc (sizeof (float) * bufferSize);
-
- if (outputChannels[i])
- {
- outputChannelDataForCallback [totalNumOutputChannels++] = outputChannelData [i];
- currentOutputChans.setBit (i);
- }
- }
- }
-
- if (totalNumOutputChannels > 0)
- {
- outputDevice = new ALSADevice (deviceName, false);
-
- if (outputDevice->error.isNotEmpty())
- {
- error = outputDevice->error;
- deleteAndZero (outputDevice);
- return;
- }
-
- if (! outputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
- {
- error = outputDevice->error;
- deleteAndZero (outputDevice);
- return;
- }
- }
-
- if (totalNumInputChannels > 0)
- {
- inputDevice = new ALSADevice (deviceName, true);
-
- if (inputDevice->error.isNotEmpty())
- {
- error = inputDevice->error;
- deleteAndZero (inputDevice);
- return;
- }
-
- if (! inputDevice->setParameters ((unsigned int) sampleRate, numChannelsRunning, bufferSize))
- {
- error = inputDevice->error;
- deleteAndZero (inputDevice);
- return;
- }
- }
-
- if (outputDevice == 0 && inputDevice == 0)
- {
- error = "no channels";
- return;
- }
-
- if (outputDevice != 0 && inputDevice != 0)
- {
- snd_pcm_link (outputDevice->handle, inputDevice->handle);
- }
-
- if (inputDevice != 0 && failed (snd_pcm_prepare (inputDevice->handle)))
- return;
-
- if (outputDevice != 0 && failed (snd_pcm_prepare (outputDevice->handle)))
- return;
-
- startThread (9);
-
- int count = 1000;
-
- while (numCallbacks == 0)
- {
- sleep (5);
-
- if (--count < 0 || ! isThreadRunning())
- {
- error = "device didn't start";
- break;
- }
- }
- }
-
- void close()
- {
- stopThread (6000);
-
- deleteAndZero (inputDevice);
- deleteAndZero (outputDevice);
-
- for (int i = 0; i < maxNumChans; ++i)
- {
- juce_free (inputChannelData [i]);
- juce_free (outputChannelData [i]);
- }
-
- zeromem (outputChannelData, sizeof (outputChannelData));
- zeromem (outputChannelDataForCallback, sizeof (outputChannelDataForCallback));
- zeromem (inputChannelData, sizeof (inputChannelData));
- zeromem (inputChannelDataForCallback, sizeof (inputChannelDataForCallback));
- totalNumOutputChannels = 0;
- totalNumInputChannels = 0;
- numChannelsRunning = 0;
-
- numCallbacks = 0;
- }
-
- void setCallback (AudioIODeviceCallback* const newCallback) throw()
- {
- const ScopedLock sl (callbackLock);
- callback = newCallback;
- }
-
- void run()
- {
- while (! threadShouldExit())
- {
- if (inputDevice != 0)
- {
- jassert (numChannelsRunning >= inputDevice->numChannelsRunning);
-
- if (! inputDevice->read (inputChannelData, bufferSize))
- {
- DBG ("ALSA: read failure");
- break;
- }
- }
-
- if (threadShouldExit())
- break;
-
- {
- const ScopedLock sl (callbackLock);
- ++numCallbacks;
-
- if (callback != 0)
- {
- callback->audioDeviceIOCallback ((const float**) inputChannelDataForCallback,
- totalNumInputChannels,
- outputChannelDataForCallback,
- totalNumOutputChannels,
- bufferSize);
- }
- else
- {
- for (int i = 0; i < totalNumOutputChannels; ++i)
- zeromem (outputChannelDataForCallback[i], sizeof (float) * bufferSize);
- }
- }
-
- if (outputDevice != 0)
- {
- failed (snd_pcm_wait (outputDevice->handle, 2000));
-
- if (threadShouldExit())
- break;
-
- failed (snd_pcm_avail_update (outputDevice->handle));
-
- jassert (numChannelsRunning >= outputDevice->numChannelsRunning);
- if (! outputDevice->write (outputChannelData, bufferSize))
- {
- DBG ("ALSA: write failure");
- break;
- }
- }
- }
- }
-
- int getBitDepth() const throw()
- {
- if (outputDevice != 0)
- return outputDevice->bitDepth;
-
- if (inputDevice != 0)
- return inputDevice->bitDepth;
-
- return 16;
- }
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
- String error;
- double sampleRate;
- int bufferSize;
- BitArray currentInputChans, currentOutputChans;
-
- Array <int> sampleRates;
- StringArray channelNamesOut, channelNamesIn;
- AudioIODeviceCallback* callback;
-
- private:
- //==============================================================================
- const String deviceName;
- ALSADevice* outputDevice;
- ALSADevice* inputDevice;
- int numCallbacks;
-
- CriticalSection callbackLock;
-
- float* outputChannelData [maxNumChans];
- float* outputChannelDataForCallback [maxNumChans];
- int totalNumInputChannels;
- float* inputChannelData [maxNumChans];
- float* inputChannelDataForCallback [maxNumChans];
- int totalNumOutputChannels;
- int numChannelsRunning;
-
- unsigned int minChansOut, maxChansOut;
- unsigned int minChansIn, maxChansIn;
-
- bool failed (const int errorNum) throw()
- {
- if (errorNum >= 0)
- return false;
-
- error = snd_strerror (errorNum);
- DBG (T("ALSA error: ") + error + T("\n"));
- return true;
- }
-
- void initialiseRatesAndChannels() throw()
- {
- sampleRates.clear();
- channelNamesOut.clear();
- channelNamesIn.clear();
- minChansOut = 0;
- maxChansOut = 0;
- minChansIn = 0;
- maxChansIn = 0;
-
- getDeviceProperties (deviceName, minChansOut, maxChansOut, minChansIn, maxChansIn, sampleRates);
-
- unsigned int i;
- for (i = 0; i < maxChansOut; ++i)
- channelNamesOut.add (T("channel ") + String ((int) i + 1));
-
- for (i = 0; i < maxChansIn; ++i)
- channelNamesIn.add (T("channel ") + String ((int) i + 1));
- }
- };
-
-
- //==============================================================================
- class ALSAAudioIODevice : public AudioIODevice
- {
- public:
- ALSAAudioIODevice (const String& deviceName,
- const String& deviceId)
- : AudioIODevice (deviceName, T("ALSA")),
- isOpen_ (false),
- isStarted (false),
- internal (0)
- {
- internal = new ALSAThread (deviceId);
- }
-
- ~ALSAAudioIODevice()
- {
- delete internal;
- }
-
- const StringArray getOutputChannelNames()
- {
- return internal->channelNamesOut;
- }
-
- const StringArray getInputChannelNames()
- {
- return internal->channelNamesIn;
- }
-
- int getNumSampleRates()
- {
- return internal->sampleRates.size();
- }
-
- double getSampleRate (int index)
- {
- return internal->sampleRates [index];
- }
-
- int getNumBufferSizesAvailable()
- {
- return 50;
- }
-
- int getBufferSizeSamples (int index)
- {
- int n = 16;
- for (int i = 0; i < index; ++i)
- n += n < 64 ? 16
- : (n < 512 ? 32
- : (n < 1024 ? 64
- : (n < 2048 ? 128 : 256)));
-
- return n;
- }
-
- int getDefaultBufferSize()
- {
- return 512;
- }
-
- const String open (const BitArray& inputChannels,
- const BitArray& outputChannels,
- double sampleRate,
- int bufferSizeSamples)
- {
- close();
-
- if (bufferSizeSamples <= 0)
- bufferSizeSamples = getDefaultBufferSize();
-
- if (sampleRate <= 0)
- {
- for (int i = 0; i < getNumSampleRates(); ++i)
- {
- if (getSampleRate (i) >= 44100)
- {
- sampleRate = getSampleRate (i);
- break;
- }
- }
- }
-
- internal->open (inputChannels, outputChannels,
- sampleRate, bufferSizeSamples);
-
- isOpen_ = internal->error.isEmpty();
- return internal->error;
- }
-
- void close()
- {
- stop();
- internal->close();
- isOpen_ = false;
- }
-
- bool isOpen()
- {
- return isOpen_;
- }
-
- int getCurrentBufferSizeSamples()
- {
- return internal->bufferSize;
- }
-
- double getCurrentSampleRate()
- {
- return internal->sampleRate;
- }
-
- int getCurrentBitDepth()
- {
- return internal->getBitDepth();
- }
-
- const BitArray getActiveOutputChannels() const
- {
- return internal->currentOutputChans;
- }
-
- const BitArray getActiveInputChannels() const
- {
- return internal->currentInputChans;
- }
-
- int getOutputLatencyInSamples()
- {
- return 0;
- }
-
- int getInputLatencyInSamples()
- {
- return 0;
- }
-
- void start (AudioIODeviceCallback* callback)
- {
- if (! isOpen_)
- callback = 0;
-
- internal->setCallback (callback);
-
- if (callback != 0)
- callback->audioDeviceAboutToStart (internal->sampleRate,
- internal->bufferSize);
-
- isStarted = (callback != 0);
- }
-
- void stop()
- {
- AudioIODeviceCallback* const oldCallback = internal->callback;
-
- start (0);
-
- if (oldCallback != 0)
- oldCallback->audioDeviceStopped();
- }
-
- bool isPlaying()
- {
- return isStarted && internal->error.isEmpty();
- }
-
- const String getLastError()
- {
- return internal->error;
- }
-
- private:
- bool isOpen_, isStarted;
- ALSAThread* internal;
- };
-
-
- //==============================================================================
- class ALSAAudioIODeviceType : public AudioIODeviceType
- {
- public:
- //==============================================================================
- ALSAAudioIODeviceType()
- : AudioIODeviceType (T("ALSA")),
- hasScanned (false)
- {
- }
-
- ~ALSAAudioIODeviceType()
- {
- }
-
- //==============================================================================
- void scanForDevices()
- {
- hasScanned = true;
-
- names.clear();
- ids.clear();
-
- snd_ctl_t* handle;
- snd_ctl_card_info_t* info;
- snd_ctl_card_info_alloca (&info);
-
- int cardNum = -1;
-
- while (ids.size() <= 24)
- {
- snd_card_next (&cardNum);
-
- if (cardNum < 0)
- break;
-
- if (snd_ctl_open (&handle, T("hw:") + String (cardNum), SND_CTL_NONBLOCK) >= 0)
- {
- if (snd_ctl_card_info (handle, info) >= 0)
- {
- String cardId (snd_ctl_card_info_get_id (info));
-
- if (cardId.removeCharacters (T("0123456789")).isEmpty())
- cardId = String (cardNum);
-
- int device = -1;
-
- for (;;)
- {
- if (snd_ctl_pcm_next_device (handle, &device) < 0 || device < 0)
- break;
-
- String id, name;
- id << "hw:" << cardId << ',' << device;
-
- if (testDevice (id))
- {
- name << snd_ctl_card_info_get_name (info);
-
- if (name.isEmpty())
- name = id;
-
- if (device > 0)
- name << " (" << (device + 1) << ')';
-
- ids.add (id);
- names.add (name);
- }
- }
- }
-
- snd_ctl_close (handle);
- }
- }
- }
-
- const StringArray getDeviceNames (const bool /*preferInputNames*/) const
- {
- jassert (hasScanned); // need to call scanForDevices() before doing this
-
- StringArray namesCopy (names);
- namesCopy.removeDuplicates (true);
-
- return namesCopy;
- }
-
- const String getDefaultDeviceName (const bool /*preferInputNames*/,
- const int /*numInputChannelsNeeded*/,
- const int /*numOutputChannelsNeeded*/) const
- {
- jassert (hasScanned); // need to call scanForDevices() before doing this
-
- return names[0];
- }
-
- AudioIODevice* createDevice (const String& deviceName)
- {
- jassert (hasScanned); // need to call scanForDevices() before doing this
-
- const int index = names.indexOf (deviceName);
-
- if (index >= 0)
- return new ALSAAudioIODevice (deviceName, ids [index]);
-
- return 0;
- }
-
- //==============================================================================
- juce_UseDebuggingNewOperator
-
- private:
- StringArray names, ids;
- bool hasScanned;
-
- static bool testDevice (const String& id)
- {
- unsigned int minChansOut = 0, maxChansOut = 0;
- unsigned int minChansIn = 0, maxChansIn = 0;
- Array <int> rates;
-
- getDeviceProperties (id, minChansOut, maxChansOut, minChansIn, maxChansIn, rates);
-
- DBG (T("ALSA device: ") + id
- + T(" outs=") + String ((int) minChansOut) + T("-") + String ((int) maxChansOut)
- + T(" ins=") + String ((int) minChansIn) + T("-") + String ((int) maxChansIn)
- + T(" rates=") + String (rates.size()));
-
- return (maxChansOut > 0 || maxChansIn > 0) && rates.size() > 0;
- }
-
- ALSAAudioIODeviceType (const ALSAAudioIODeviceType&);
- const ALSAAudioIODeviceType& operator= (const ALSAAudioIODeviceType&);
- };
-
- //==============================================================================
- AudioIODeviceType* juce_createDefaultAudioIODeviceType()
- {
- return new ALSAAudioIODeviceType();
- }
-
-
- END_JUCE_NAMESPACE
-
-
- //==============================================================================
- #else // if ALSA is turned off..
-
- #include "../../../src/juce_core/basics/juce_StandardHeader.h"
-
- BEGIN_JUCE_NAMESPACE
-
- #include "../../../src/juce_appframework/audio/devices/juce_AudioIODeviceType.h"
- AudioIODeviceType* juce_createDefaultAudioIODeviceType() { return 0; }
-
- END_JUCE_NAMESPACE
-
- #endif
-
- #endif
|