| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE library.
 -    Copyright (c) 2015 - ROLI Ltd.
 - 
 -    Permission is granted to use this software under the terms of either:
 -    a) the GPL v2 (or any later version)
 -    b) the Affero GPL v3
 - 
 -    Details of these licenses can be found at: www.gnu.org/licenses
 - 
 -    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.
 - 
 -    ------------------------------------------------------------------------------
 - 
 -    To release a closed-source product which uses JUCE, commercial licenses are
 -    available: visit www.juce.com for more information.
 - 
 -   ==============================================================================
 - */
 - 
 - #undef check
 - 
 - const char* const openSLTypeName = "Android OpenSL";
 - 
 - bool isOpenSLAvailable()
 - {
 -     DynamicLibrary library;
 -     return library.open ("libOpenSLES.so");
 - }
 - 
 - //==============================================================================
 - class OpenSLAudioIODevice  : public AudioIODevice,
 -                              private Thread
 - {
 - public:
 -     OpenSLAudioIODevice (const String& deviceName)
 -         : AudioIODevice (deviceName, openSLTypeName),
 -           Thread ("OpenSL"),
 -           callback (nullptr), sampleRate (0), deviceOpen (false),
 -           inputBuffer (2, 2), outputBuffer (2, 2)
 -     {
 -         // OpenSL has piss-poor support for determining latency, so the only way I can find to
 -         // get a number for this is by asking the AudioTrack/AudioRecord classes..
 -         AndroidAudioIODevice javaDevice (deviceName);
 - 
 -         // this is a total guess about how to calculate the latency, but seems to vaguely agree
 -         // with the devices I've tested.. YMMV
 -         inputLatency  = (javaDevice.minBufferSizeIn  * 2) / 3;
 -         outputLatency = (javaDevice.minBufferSizeOut * 2) / 3;
 - 
 -         const int64 longestLatency = jmax (inputLatency, outputLatency);
 -         const int64 totalLatency = inputLatency + outputLatency;
 -         inputLatency  = (int) ((longestLatency * inputLatency)  / totalLatency) & ~15;
 -         outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15;
 -     }
 - 
 -     ~OpenSLAudioIODevice()
 -     {
 -         close();
 -     }
 - 
 -     bool openedOk() const       { return engine.outputMixObject != nullptr; }
 - 
 -     StringArray getOutputChannelNames() override
 -     {
 -         StringArray s;
 -         s.add ("Left");
 -         s.add ("Right");
 -         return s;
 -     }
 - 
 -     StringArray getInputChannelNames() override
 -     {
 -         StringArray s;
 -         s.add ("Audio Input");
 -         return s;
 -     }
 - 
 -     Array<double> getAvailableSampleRates() override
 -     {
 -         static const double rates[] = { 8000.0, 16000.0, 32000.0, 44100.0, 48000.0 };
 -         Array<double> retval (rates, numElementsInArray (rates));
 - 
 -         // make sure the native sample rate is pafrt of the list
 -         double native = getNativeSampleRate();
 -         if (native != 0.0 && ! retval.contains (native))
 -             retval.add (native);
 - 
 -         return retval;
 -     }
 - 
 -     Array<int> getAvailableBufferSizes() override
 -     {
 -         // we need to offer the lowest possible buffer size which
 -         // is the native buffer size
 -         const int defaultNumMultiples = 8;
 -         const int nativeBufferSize = getNativeBufferSize();
 - 
 -         Array<int> retval;
 -         for (int i = 1; i < defaultNumMultiples; ++i)
 -             retval.add (i * nativeBufferSize);
 - 
 -         return retval;
 -     }
 - 
 -     String open (const BigInteger& inputChannels,
 -                  const BigInteger& outputChannels,
 -                  double requestedSampleRate,
 -                  int bufferSize) override
 -     {
 -         close();
 - 
 -         lastError.clear();
 -         sampleRate = (int) requestedSampleRate;
 - 
 -         int preferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
 - 
 -         activeOutputChans = outputChannels;
 -         activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
 -         numOutputChannels = activeOutputChans.countNumberOfSetBits();
 - 
 -         activeInputChans = inputChannels;
 -         activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
 -         numInputChannels = activeInputChans.countNumberOfSetBits();
 - 
 -         actualBufferSize = preferredBufferSize;
 - 
 -         inputBuffer.setSize  (jmax (1, numInputChannels),  actualBufferSize);
 -         outputBuffer.setSize (jmax (1, numOutputChannels), actualBufferSize);
 -         outputBuffer.clear();
 - 
 -         const int audioBuffersToEnqueue = hasLowLatencyAudioPath() ? buffersToEnqueueForLowLatency
 -                                                                    : buffersToEnqueueSlowAudio;
 - 
 -         DBG ("OpenSL: numInputChannels = " << numInputChannels
 -               << ", numOutputChannels = " << numOutputChannels
 -               << ", nativeBufferSize = " << getNativeBufferSize()
 -               << ", nativeSampleRate = " << getNativeSampleRate()
 -               << ", actualBufferSize = " << actualBufferSize
 -               << ", audioBuffersToEnqueue = " << audioBuffersToEnqueue
 -               << ", sampleRate = " << sampleRate);
 - 
 -         if (numInputChannels > 0)
 -             recorder = engine.createRecorder (numInputChannels,  sampleRate,
 -                                               audioBuffersToEnqueue, actualBufferSize);
 - 
 -         if (numOutputChannels > 0)
 -             player   = engine.createPlayer   (numOutputChannels, sampleRate,
 -                                               audioBuffersToEnqueue, actualBufferSize);
 - 
 -         // pre-fill buffers
 -         for (int i = 0; i < audioBuffersToEnqueue; ++i)
 -             processBuffers();
 - 
 -         startThread (8);
 - 
 -         deviceOpen = true;
 -         return lastError;
 -     }
 - 
 -     void close() override
 -     {
 -         stop();
 -         stopThread (6000);
 -         deviceOpen = false;
 -         recorder = nullptr;
 -         player = nullptr;
 -     }
 - 
 -     int getOutputLatencyInSamples() override            { return outputLatency; }
 -     int getInputLatencyInSamples() override             { return inputLatency; }
 -     bool isOpen() override                              { return deviceOpen; }
 -     int getCurrentBufferSizeSamples() override          { return actualBufferSize; }
 -     int getCurrentBitDepth() override                   { return 16; }
 -     BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
 -     BigInteger getActiveInputChannels() const override  { return activeInputChans; }
 -     String getLastError() override                      { return lastError; }
 -     bool isPlaying() override                           { return callback != nullptr; }
 - 
 -     int getDefaultBufferSize() override
 -     {
 -         // Only on a Pro-Audio device will we set the lowest possible buffer size
 -         // by default. We need to be more conservative on other devices
 -         // as they may be low-latency, but still have a crappy CPU.
 -         return (isProAudioDevice() ? 1 : 6)
 -                  * defaultBufferSizeIsMultipleOfNative * getNativeBufferSize();
 -     }
 - 
 -     double getCurrentSampleRate() override
 -     {
 -         return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate);
 -     }
 - 
 -     void start (AudioIODeviceCallback* newCallback) override
 -     {
 -         stop();
 - 
 -         if (deviceOpen && callback != newCallback)
 -         {
 -             if (newCallback != nullptr)
 -                 newCallback->audioDeviceAboutToStart (this);
 - 
 -             setCallback (newCallback);
 -         }
 -     }
 - 
 -     void stop() override
 -     {
 -         if (AudioIODeviceCallback* const oldCallback = setCallback (nullptr))
 -             oldCallback->audioDeviceStopped();
 -     }
 - 
 -     bool setAudioPreprocessingEnabled (bool enable) override
 -     {
 -         return recorder != nullptr && recorder->setAudioPreprocessingEnabled (enable);
 -     }
 - 
 - private:
 -     //==================================================================================================
 -     CriticalSection callbackLock;
 -     AudioIODeviceCallback* callback;
 -     int actualBufferSize, sampleRate;
 -     int inputLatency, outputLatency;
 -     bool deviceOpen;
 -     String lastError;
 -     BigInteger activeOutputChans, activeInputChans;
 -     int numInputChannels, numOutputChannels;
 -     AudioSampleBuffer inputBuffer, outputBuffer;
 -     struct Player;
 -     struct Recorder;
 - 
 -     enum
 -     {
 -         // The number of buffers to enqueue needs to be at least two for the audio to use the low-latency
 -         // audio path (see "Performance" section in ndk/docs/Additional_library_docs/opensles/index.html)
 -         buffersToEnqueueForLowLatency = 2,
 -         buffersToEnqueueSlowAudio = 4,
 -         defaultBufferSizeIsMultipleOfNative = 1
 -     };
 - 
 -     //==================================================================================================
 -     static String audioManagerGetProperty (const String& property)
 -     {
 -         const LocalRef<jstring> jProperty (javaString (property));
 -         const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
 -                                                                                    jProperty.get()));
 -         if (text.get() != 0)
 -             return juceString (text);
 - 
 -         return String();
 -     }
 - 
 -     static bool androidHasSystemFeature (const String& property)
 -     {
 -         const LocalRef<jstring> jProperty (javaString (property));
 -         return android.activity.callBooleanMethod (JuceAppActivity.hasSystemFeature, jProperty.get());
 -     }
 - 
 -     static double getNativeSampleRate()
 -     {
 -         return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue();
 -     }
 - 
 -     static int getNativeBufferSize()
 -     {
 -         const int val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue();
 -         return val > 0 ? val : 512;
 -     }
 - 
 -     static bool isProAudioDevice()
 -     {
 -         return androidHasSystemFeature ("android.hardware.audio.pro");
 -     }
 - 
 -     static bool hasLowLatencyAudioPath()
 -     {
 -         return androidHasSystemFeature ("android.hardware.audio.low_latency");
 -     }
 - 
 -     //==================================================================================================
 -     AudioIODeviceCallback* setCallback (AudioIODeviceCallback* const newCallback)
 -     {
 -         const ScopedLock sl (callbackLock);
 -         AudioIODeviceCallback* const oldCallback = callback;
 -         callback = newCallback;
 -         return oldCallback;
 -     }
 - 
 -     void processBuffers()
 -     {
 -         if (recorder != nullptr)
 -             recorder->readNextBlock (inputBuffer, *this);
 - 
 -         {
 -             const ScopedLock sl (callbackLock);
 - 
 -             if (callback != nullptr)
 -                 callback->audioDeviceIOCallback (numInputChannels  > 0 ? inputBuffer.getArrayOfReadPointers()   : nullptr, numInputChannels,
 -                                                  numOutputChannels > 0 ? outputBuffer.getArrayOfWritePointers() : nullptr, numOutputChannels,
 -                                                  actualBufferSize);
 -             else
 -                 outputBuffer.clear();
 -         }
 - 
 -         if (player != nullptr)
 -             player->writeBuffer (outputBuffer, *this);
 -     }
 - 
 -     void run() override
 -     {
 -         setThreadToAudioPriority ();
 - 
 -         if (recorder != nullptr)    recorder->start();
 -         if (player != nullptr)      player->start();
 - 
 -         while (! threadShouldExit())
 -             processBuffers();
 -     }
 - 
 -     void setThreadToAudioPriority ()
 -     {
 -         // see android.os.Process.THREAD_PRIORITY_AUDIO
 -         const int THREAD_PRIORITY_AUDIO = -16;
 -         jint priority = THREAD_PRIORITY_AUDIO;
 - 
 -         if (priority != android.activity.callIntMethod (JuceAppActivity.setCurrentThreadPriority, (jint) priority))
 -             DBG ("Unable to set audio thread priority: priority is still " << priority);
 -     }
 - 
 -     //==================================================================================================
 -     struct Engine
 -     {
 -         Engine()
 -             : engineObject (nullptr), engineInterface (nullptr), outputMixObject (nullptr)
 -         {
 -             if (library.open ("libOpenSLES.so"))
 -             {
 -                 typedef SLresult (*CreateEngineFunc) (SLObjectItf*, SLuint32, const SLEngineOption*,
 -                                                       SLuint32, const SLInterfaceID*, const SLboolean*);
 - 
 -                 if (CreateEngineFunc createEngine = (CreateEngineFunc) library.getFunction ("slCreateEngine"))
 -                 {
 -                     check (createEngine (&engineObject, 0, nullptr, 0, nullptr, nullptr));
 - 
 -                     SLInterfaceID* SL_IID_ENGINE    = (SLInterfaceID*) library.getFunction ("SL_IID_ENGINE");
 -                     SL_IID_ANDROIDSIMPLEBUFFERQUEUE = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDSIMPLEBUFFERQUEUE");
 -                     SL_IID_PLAY                     = (SLInterfaceID*) library.getFunction ("SL_IID_PLAY");
 -                     SL_IID_RECORD                   = (SLInterfaceID*) library.getFunction ("SL_IID_RECORD");
 -                     SL_IID_ANDROIDCONFIGURATION     = (SLInterfaceID*) library.getFunction ("SL_IID_ANDROIDCONFIGURATION");
 - 
 -                     check ((*engineObject)->Realize (engineObject, SL_BOOLEAN_FALSE));
 -                     check ((*engineObject)->GetInterface (engineObject, *SL_IID_ENGINE, &engineInterface));
 - 
 -                     check ((*engineInterface)->CreateOutputMix (engineInterface, &outputMixObject, 0, nullptr, nullptr));
 -                     check ((*outputMixObject)->Realize (outputMixObject, SL_BOOLEAN_FALSE));
 -                 }
 -             }
 -         }
 - 
 -         ~Engine()
 -         {
 -             if (outputMixObject != nullptr) (*outputMixObject)->Destroy (outputMixObject);
 -             if (engineObject != nullptr)    (*engineObject)->Destroy (engineObject);
 -         }
 - 
 -         Player* createPlayer (const int numChannels, const int sampleRate, const int numBuffers, const int bufferSize)
 -         {
 -             if (numChannels <= 0)
 -                 return nullptr;
 - 
 -             ScopedPointer<Player> player (new Player (numChannels, sampleRate, *this, numBuffers, bufferSize));
 -             return player->openedOk() ? player.release() : nullptr;
 -         }
 - 
 -         Recorder* createRecorder (const int numChannels, const int sampleRate, const int numBuffers, const int bufferSize)
 -         {
 -             if (numChannels <= 0)
 -                 return nullptr;
 - 
 -             ScopedPointer<Recorder> recorder (new Recorder (numChannels, sampleRate, *this, numBuffers, bufferSize));
 -             return recorder->openedOk() ? recorder.release() : nullptr;
 -         }
 - 
 -         SLObjectItf engineObject;
 -         SLEngineItf engineInterface;
 -         SLObjectItf outputMixObject;
 - 
 -         SLInterfaceID* SL_IID_ANDROIDSIMPLEBUFFERQUEUE;
 -         SLInterfaceID* SL_IID_PLAY;
 -         SLInterfaceID* SL_IID_RECORD;
 -         SLInterfaceID* SL_IID_ANDROIDCONFIGURATION;
 - 
 -     private:
 -         DynamicLibrary library;
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Engine)
 -     };
 - 
 -     //==================================================================================================
 -     struct BufferList
 -     {
 -         BufferList (const int numChannels_, const int numBuffers_, const int numSamples_)
 -             : numChannels (numChannels_), numBuffers (numBuffers_), numSamples (numSamples_),
 -               bufferSpace (numChannels_ * numSamples * numBuffers), nextBlock (0)
 -         {
 -         }
 - 
 -         int16* waitForFreeBuffer (Thread& threadToCheck) noexcept
 -         {
 -             while (numBlocksOut.get() == numBuffers)
 -             {
 -                 dataArrived.wait (1);
 - 
 -                 if (threadToCheck.threadShouldExit())
 -                     return nullptr;
 -             }
 - 
 -             return getNextBuffer();
 -         }
 - 
 -         int16* getNextBuffer() noexcept
 -         {
 -             if (++nextBlock == numBuffers)
 -                 nextBlock = 0;
 - 
 -             return bufferSpace + nextBlock * numChannels * numSamples;
 -         }
 - 
 -         void bufferReturned() noexcept      { --numBlocksOut; dataArrived.signal(); }
 -         void bufferSent() noexcept          { ++numBlocksOut; dataArrived.signal(); }
 - 
 -         int getBufferSizeBytes() const noexcept     { return numChannels * numSamples * sizeof (int16); }
 - 
 -         const int numChannels, numBuffers, numSamples;
 - 
 -     private:
 -         HeapBlock<int16> bufferSpace;
 -         int nextBlock;
 -         Atomic<int> numBlocksOut;
 -         WaitableEvent dataArrived;
 -     };
 - 
 -     //==================================================================================================
 -     struct Player
 -     {
 -         Player (int numChannels, int sampleRate, Engine& engine, int playerNumBuffers, int playerBufferSize)
 -             : playerObject (nullptr), playerPlay (nullptr), playerBufferQueue (nullptr),
 -               bufferList (numChannels, playerNumBuffers, playerBufferSize)
 -         {
 -             SLDataFormat_PCM pcmFormat =
 -             {
 -                 SL_DATAFORMAT_PCM,
 -                 (SLuint32) numChannels,
 -                 (SLuint32) (sampleRate * 1000),
 -                 SL_PCMSAMPLEFORMAT_FIXED_16,
 -                 SL_PCMSAMPLEFORMAT_FIXED_16,
 -                 (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
 -                 SL_BYTEORDER_LITTLEENDIAN
 -             };
 - 
 -             SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
 -                                                                    static_cast<SLuint32> (bufferList.numBuffers) };
 -             SLDataSource audioSrc = { &bufferQueue, &pcmFormat };
 - 
 -             SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, engine.outputMixObject };
 -             SLDataSink audioSink = { &outputMix, nullptr };
 - 
 -             // (SL_IID_BUFFERQUEUE is not guaranteed to remain future-proof, so use SL_IID_ANDROIDSIMPLEBUFFERQUEUE)
 -             const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
 -             const SLboolean flags[] = { SL_BOOLEAN_TRUE };
 - 
 -             check ((*engine.engineInterface)->CreateAudioPlayer (engine.engineInterface, &playerObject, &audioSrc, &audioSink,
 -                                                                  1, interfaceIDs, flags));
 - 
 -             check ((*playerObject)->Realize (playerObject, SL_BOOLEAN_FALSE));
 -             check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_PLAY, &playerPlay));
 -             check ((*playerObject)->GetInterface (playerObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &playerBufferQueue));
 -             check ((*playerBufferQueue)->RegisterCallback (playerBufferQueue, staticCallback, this));
 -         }
 - 
 -         ~Player()
 -         {
 -             if (playerPlay != nullptr)
 -                 check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_STOPPED));
 - 
 -             if (playerBufferQueue != nullptr)
 -                 check ((*playerBufferQueue)->Clear (playerBufferQueue));
 - 
 -             if (playerObject != nullptr)
 -                 (*playerObject)->Destroy (playerObject);
 -         }
 - 
 -         bool openedOk() const noexcept      { return playerBufferQueue != nullptr; }
 - 
 -         void start()
 -         {
 -             jassert (openedOk());
 - 
 -             check ((*playerPlay)->SetPlayState (playerPlay, SL_PLAYSTATE_PLAYING));
 -         }
 - 
 -         void writeBuffer (const AudioSampleBuffer& buffer, Thread& thread) noexcept
 -         {
 -             jassert (buffer.getNumChannels() == bufferList.numChannels);
 -             jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
 - 
 -             int offset = 0;
 -             int numSamples = buffer.getNumSamples();
 - 
 -             while (numSamples > 0)
 -             {
 -                 if (int16* const destBuffer = bufferList.waitForFreeBuffer (thread))
 -                 {
 -                     for (int i = 0; i < bufferList.numChannels; ++i)
 -                     {
 -                         typedef AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst> DstSampleType;
 -                         typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SrcSampleType;
 - 
 -                         DstSampleType dstData (destBuffer + i, bufferList.numChannels);
 -                         SrcSampleType srcData (buffer.getReadPointer (i, offset));
 -                         dstData.convertSamples (srcData, bufferList.numSamples);
 -                     }
 - 
 -                     enqueueBuffer (destBuffer);
 - 
 -                     numSamples -= bufferList.numSamples;
 -                     offset += bufferList.numSamples;
 -                 }
 -                 else
 -                 {
 -                     break;
 -                 }
 -             }
 -         }
 - 
 -     private:
 -         SLObjectItf playerObject;
 -         SLPlayItf playerPlay;
 -         SLAndroidSimpleBufferQueueItf playerBufferQueue;
 - 
 -         BufferList bufferList;
 - 
 -         void enqueueBuffer (int16* buffer) noexcept
 -         {
 -             check ((*playerBufferQueue)->Enqueue (playerBufferQueue, buffer, bufferList.getBufferSizeBytes()));
 -             bufferList.bufferSent();
 -         }
 - 
 -         static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context) noexcept
 -         {
 -             jassert (queue == static_cast<Player*> (context)->playerBufferQueue); ignoreUnused (queue);
 -             static_cast<Player*> (context)->bufferList.bufferReturned();
 -         }
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Player)
 -     };
 - 
 -     //==================================================================================================
 -     struct Recorder
 -     {
 -         Recorder (int numChannels, int sampleRate, Engine& engine, const int numBuffers, const int numSamples)
 -             : recorderObject (nullptr), recorderRecord (nullptr),
 -               recorderBufferQueue (nullptr), configObject (nullptr),
 -               bufferList (numChannels, numBuffers, numSamples)
 -         {
 -             SLDataFormat_PCM pcmFormat =
 -             {
 -                 SL_DATAFORMAT_PCM,
 -                 (SLuint32) numChannels,
 -                 (SLuint32) (sampleRate * 1000), // (sample rate units are millihertz)
 -                 SL_PCMSAMPLEFORMAT_FIXED_16,
 -                 SL_PCMSAMPLEFORMAT_FIXED_16,
 -                 (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER : (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT),
 -                 SL_BYTEORDER_LITTLEENDIAN
 -             };
 - 
 -             SLDataLocator_IODevice ioDevice = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
 -             SLDataSource audioSrc = { &ioDevice, nullptr };
 - 
 -             SLDataLocator_AndroidSimpleBufferQueue bufferQueue = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
 -                                                                    static_cast<SLuint32> (bufferList.numBuffers) };
 -             SLDataSink audioSink = { &bufferQueue, &pcmFormat };
 - 
 -             const SLInterfaceID interfaceIDs[] = { *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
 -             const SLboolean flags[] = { SL_BOOLEAN_TRUE };
 - 
 -             if (check ((*engine.engineInterface)->CreateAudioRecorder (engine.engineInterface, &recorderObject, &audioSrc,
 -                                                                        &audioSink, 1, interfaceIDs, flags)))
 -             {
 -                 if (check ((*recorderObject)->Realize (recorderObject, SL_BOOLEAN_FALSE)))
 -                 {
 -                     check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_RECORD, &recorderRecord));
 -                     check ((*recorderObject)->GetInterface (recorderObject, *engine.SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue));
 -                     // not all android versions seem to have a config object
 -                     SLresult result = (*recorderObject)->GetInterface (recorderObject,
 -                                                                        *engine.SL_IID_ANDROIDCONFIGURATION, &configObject);
 -                     if (result != SL_RESULT_SUCCESS)
 -                         configObject = nullptr;
 - 
 -                     check ((*recorderBufferQueue)->RegisterCallback (recorderBufferQueue, staticCallback, this));
 -                     check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
 -                 }
 -             }
 -         }
 - 
 -         ~Recorder()
 -         {
 -             if (recorderRecord != nullptr)
 -                 check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_STOPPED));
 - 
 -             if (recorderBufferQueue != nullptr)
 -                 check ((*recorderBufferQueue)->Clear (recorderBufferQueue));
 - 
 -             if (recorderObject != nullptr)
 -                 (*recorderObject)->Destroy (recorderObject);
 -         }
 - 
 -         bool openedOk() const noexcept      { return recorderBufferQueue != nullptr; }
 - 
 -         void start()
 -         {
 -             jassert (openedOk());
 -             check ((*recorderRecord)->SetRecordState (recorderRecord, SL_RECORDSTATE_RECORDING));
 -         }
 - 
 -         void readNextBlock (AudioSampleBuffer& buffer, Thread& thread)
 -         {
 -             jassert (buffer.getNumChannels() == bufferList.numChannels);
 -             jassert (buffer.getNumSamples() < bufferList.numSamples * bufferList.numBuffers);
 -             jassert ((buffer.getNumSamples() % bufferList.numSamples) == 0);
 - 
 -             int offset = 0;
 -             int numSamples = buffer.getNumSamples();
 - 
 -             while (numSamples > 0)
 -             {
 -                 if (int16* const srcBuffer = bufferList.waitForFreeBuffer (thread))
 -                 {
 -                     for (int i = 0; i < bufferList.numChannels; ++i)
 -                     {
 -                         typedef AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DstSampleType;
 -                         typedef AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved, AudioData::Const> SrcSampleType;
 - 
 -                         DstSampleType dstData (buffer.getWritePointer (i, offset));
 -                         SrcSampleType srcData (srcBuffer + i, bufferList.numChannels);
 -                         dstData.convertSamples (srcData, bufferList.numSamples);
 -                     }
 - 
 -                     enqueueBuffer (srcBuffer);
 - 
 -                     numSamples -= bufferList.numSamples;
 -                     offset += bufferList.numSamples;
 -                 }
 -                 else
 -                 {
 -                     break;
 -                 }
 -             }
 -         }
 - 
 -         bool setAudioPreprocessingEnabled (bool enable)
 -         {
 -             SLuint32 mode = enable ? SL_ANDROID_RECORDING_PRESET_GENERIC
 -                                    : SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
 - 
 -             return configObject != nullptr
 -                      && check ((*configObject)->SetConfiguration (configObject, SL_ANDROID_KEY_RECORDING_PRESET, &mode, sizeof (mode)));
 -         }
 - 
 -     private:
 -         SLObjectItf recorderObject;
 -         SLRecordItf recorderRecord;
 -         SLAndroidSimpleBufferQueueItf recorderBufferQueue;
 -         SLAndroidConfigurationItf configObject;
 - 
 -         BufferList bufferList;
 - 
 -         void enqueueBuffer (int16* buffer) noexcept
 -         {
 -             check ((*recorderBufferQueue)->Enqueue (recorderBufferQueue, buffer, bufferList.getBufferSizeBytes()));
 -             bufferList.bufferSent();
 -         }
 - 
 -         static void staticCallback (SLAndroidSimpleBufferQueueItf queue, void* context) noexcept
 -         {
 -             jassert (queue == static_cast<Recorder*> (context)->recorderBufferQueue); ignoreUnused (queue);
 -             static_cast<Recorder*> (context)->bufferList.bufferReturned();
 -         }
 - 
 -         JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Recorder)
 -     };
 - 
 - 
 -     //==============================================================================
 -     Engine engine;
 - 
 -     ScopedPointer<Player> player;
 -     ScopedPointer<Recorder> recorder;
 - 
 -     //==============================================================================
 -     static bool check (const SLresult result) noexcept
 -     {
 -         jassert (result == SL_RESULT_SUCCESS);
 -         return result == SL_RESULT_SUCCESS;
 -     }
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
 - };
 - 
 - 
 - //==============================================================================
 - class OpenSLAudioDeviceType  : public AudioIODeviceType
 - {
 - public:
 -     OpenSLAudioDeviceType()  : AudioIODeviceType (openSLTypeName) {}
 - 
 -     //==============================================================================
 -     void scanForDevices() override {}
 -     StringArray getDeviceNames (bool wantInputNames) const override              { return StringArray (openSLTypeName); }
 -     int getDefaultDeviceIndex (bool forInput) const override                     { return 0; }
 -     int getIndexOfDevice (AudioIODevice* device, bool asInput) const override    { return device != nullptr ? 0 : -1; }
 -     bool hasSeparateInputsAndOutputs() const override                            { return false; }
 - 
 -     AudioIODevice* createDevice (const String& outputDeviceName,
 -                                  const String& inputDeviceName) override
 -     {
 -         ScopedPointer<OpenSLAudioIODevice> dev;
 - 
 -         if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
 -         {
 -             dev = new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
 -                                                                          : inputDeviceName);
 -             if (! dev->openedOk())
 -                 dev = nullptr;
 -         }
 - 
 -         return dev.release();
 -     }
 - 
 - private:
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
 - };
 - 
 - 
 - //==============================================================================
 - AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
 - {
 -     return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
 - }
 
 
  |