1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
26 #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
27 DECLARE_JNI_CLASS (AndroidAudioManager, "android/media/AudioManager")
28 #undef JNI_CLASS_MEMBERS
29 
30 //==============================================================================
31 #ifndef SL_ANDROID_DATAFORMAT_PCM_EX
32  #define SL_ANDROID_DATAFORMAT_PCM_EX                   ((SLuint32) 0x00000004)
33 #endif
34 
35 #ifndef SL_ANDROID_PCM_REPRESENTATION_FLOAT
36  #define SL_ANDROID_PCM_REPRESENTATION_FLOAT            ((SLuint32) 0x00000003)
37 #endif
38 
39 #ifndef SL_ANDROID_RECORDING_PRESET_UNPROCESSED
40  #define SL_ANDROID_RECORDING_PRESET_UNPROCESSED        ((SLuint32) 0x00000005)
41 #endif
42 
43 //==============================================================================
44 struct PCMDataFormatEx : SLDataFormat_PCM
45 {
46     SLuint32 representation;
47 };
48 
49 //==============================================================================
50 template <typename T> struct IntfIID;
51 template <> struct IntfIID<SLObjectItf_>                   { static SLInterfaceID_ iid; };
52 template <> struct IntfIID<SLEngineItf_>                   { static SLInterfaceID_ iid; };
53 template <> struct IntfIID<SLOutputMixItf_>                { static SLInterfaceID_ iid; };
54 template <> struct IntfIID<SLPlayItf_>                     { static SLInterfaceID_ iid; };
55 template <> struct IntfIID<SLRecordItf_>                   { static SLInterfaceID_ iid; };
56 template <> struct IntfIID<SLAndroidSimpleBufferQueueItf_> { static SLInterfaceID_ iid; };
57 template <> struct IntfIID<SLAndroidConfigurationItf_>     { static SLInterfaceID_ iid; };
58 
59 SLInterfaceID_ IntfIID<SLObjectItf_>::iid                   = { 0x79216360, 0xddd7, 0x11db, 0xac16, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
60 SLInterfaceID_ IntfIID<SLEngineItf_>::iid                   = { 0x8d97c260, 0xddd4, 0x11db, 0x958f, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
61 SLInterfaceID_ IntfIID<SLOutputMixItf_>::iid                = { 0x97750f60, 0xddd7, 0x11db, 0x92b1, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
62 SLInterfaceID_ IntfIID<SLPlayItf_>::iid                     = { 0xef0bd9c0, 0xddd7, 0x11db, 0xbf49, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
63 SLInterfaceID_ IntfIID<SLRecordItf_>::iid                   = { 0xc5657aa0, 0xdddb, 0x11db, 0x82f7, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
64 SLInterfaceID_ IntfIID<SLAndroidSimpleBufferQueueItf_>::iid = { 0x198e4940, 0xc5d7, 0x11df, 0xa2a6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
65 SLInterfaceID_ IntfIID<SLAndroidConfigurationItf_>::iid     = { 0x89f6a7e0, 0xbeac, 0x11df, 0x8b5c, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
66 
67 template <typename SLObjectType>
destroyObject(SLObjectType object)68 static void destroyObject (SLObjectType object)
69 {
70     if (object != nullptr && *object != nullptr)
71         (*object)->Destroy (object);
72 }
73 
74 struct SLObjectItfFree
75 {
operator ()juce::SLObjectItfFree76     void operator() (SLObjectItf obj) const noexcept
77     {
78         destroyObject (obj);
79     }
80 };
81 
82 //==============================================================================
83 // Some life-time and type management of OpenSL objects
84 class SlObjectRef
85 {
86 public:
87     //==============================================================================
SlObjectRef()88     SlObjectRef() noexcept {}
SlObjectRef(const SlObjectRef & obj)89     SlObjectRef (const SlObjectRef& obj) noexcept : cb (obj.cb) {}
SlObjectRef(SlObjectRef && obj)90     SlObjectRef (SlObjectRef&& obj) noexcept : cb (std::move (obj.cb)) { obj.cb = nullptr; }
SlObjectRef(SLObjectItf o)91     explicit SlObjectRef (SLObjectItf o) : cb (new ControlBlock (o)) {}
92 
93     //==============================================================================
operator =(const SlObjectRef & r)94     SlObjectRef& operator= (const SlObjectRef& r) noexcept  { cb = r.cb; return *this; }
operator =(SlObjectRef && r)95     SlObjectRef& operator= (SlObjectRef&& r) noexcept       { cb = std::move (r.cb); r.cb = nullptr; return *this; }
operator =(std::nullptr_t)96     SlObjectRef& operator= (std::nullptr_t) noexcept        { cb = nullptr; return *this; }
97 
98     //==============================================================================
operator *()99     const SLObjectItf_* operator*() noexcept                { return *cb->ptr.get(); }
operator ->()100     SLObjectItf operator->() noexcept                       { return (cb == nullptr ? nullptr :  cb->ptr.get()); }
operator SLObjectItf()101     operator SLObjectItf() noexcept                         { return (cb == nullptr ? nullptr :  cb->ptr.get()); }
102 
103     //==============================================================================
operator ==(nullptr_t) const104     bool operator== (nullptr_t) const noexcept              { return (cb == nullptr || cb->ptr == nullptr); }
operator !=(nullptr_t) const105     bool operator!= (nullptr_t) const noexcept              { return (cb != nullptr && cb->ptr != nullptr); }
106 
107 private:
108     //==============================================================================
109     struct ControlBlock : ReferenceCountedObject
110     {
111         ControlBlock() = default;
ControlBlockjuce::SlObjectRef::ControlBlock112         ControlBlock (SLObjectItf o) : ptr (o) {}
113 
114         std::unique_ptr<const SLObjectItf_* const, SLObjectItfFree> ptr;
115     };
116 
117     ReferenceCountedObjectPtr<ControlBlock> cb;
118 };
119 
120 template <typename T>
121 class SlRef : public SlObjectRef
122 {
123 public:
124     //==============================================================================
SlRef()125     SlRef() noexcept {}
SlRef(const SlRef & r)126     SlRef (const SlRef& r) noexcept : SlObjectRef (r), type (r.type) {}
SlRef(SlRef && r)127     SlRef (SlRef&& r) noexcept : SlObjectRef (std::move (r)), type (r.type) { r.type = nullptr; }
128 
129     //==============================================================================
operator =(const SlRef & r)130     SlRef& operator= (const SlRef& r)  noexcept { SlObjectRef::operator= (r); type = r.type; return *this; }
operator =(SlRef && r)131     SlRef& operator= (SlRef&& r) noexcept       { SlObjectRef::operator= (std::move (r)); type = r.type; r.type = nullptr; return *this; }
operator =(std::nullptr_t)132     SlRef& operator= (std::nullptr_t) noexcept  { SlObjectRef::operator= (nullptr); type = nullptr; return *this; }
133 
134     //==============================================================================
operator *()135     T* const operator*() noexcept               { return *type; }
operator ->()136     T* const* operator->() noexcept             { return type; }
operator T*const*()137     operator T* const*() noexcept               { return type; }
138 
139     //==============================================================================
cast(SlObjectRef & base)140     static SlRef cast (SlObjectRef&  base)      { return SlRef (base); }
cast(SlObjectRef && base)141     static SlRef cast (SlObjectRef&& base)      { return SlRef (std::move (base)); }
142 
143 private:
SlRef(SlObjectRef & base)144     SlRef (SlObjectRef& base) : SlObjectRef (base)
145     {
146         if (auto obj = SlObjectRef::operator->())
147         {
148             auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
149 
150             if (type != nullptr && err == SL_RESULT_SUCCESS)
151                 return;
152         }
153 
154         *this = nullptr;
155     }
156 
SlRef(SlObjectRef && base)157     SlRef (SlObjectRef&& base) : SlObjectRef (std::move (base))
158     {
159         if (auto obj = SlObjectRef::operator->())
160         {
161             auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
162             base = nullptr;
163 
164             if (type != nullptr && err == SL_RESULT_SUCCESS)
165                 return;
166         }
167 
168         *this = nullptr;
169     }
170 
171     T* const* type = nullptr;
172 };
173 
174 //==============================================================================
175 template <typename T> struct BufferHelpers {};
176 
177 template <>
178 struct BufferHelpers<int16>
179 {
180     enum { isFloatingPoint = 0 };
181 
initPCMDataFormatjuce::BufferHelpers182     static void initPCMDataFormat (PCMDataFormatEx& dataFormat, int numChannels, double sampleRate)
183     {
184         dataFormat.formatType     = SL_DATAFORMAT_PCM;
185         dataFormat.numChannels    = (SLuint32) numChannels;
186         dataFormat.samplesPerSec  = (SLuint32) (sampleRate * 1000);
187         dataFormat.bitsPerSample  = SL_PCMSAMPLEFORMAT_FIXED_16;
188         dataFormat.containerSize  = SL_PCMSAMPLEFORMAT_FIXED_16;
189         dataFormat.channelMask    = (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER :
190                                                         (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
191         dataFormat.endianness     = SL_BYTEORDER_LITTLEENDIAN;
192         dataFormat.representation = 0;
193     }
194 
prepareCallbackBufferjuce::BufferHelpers195     static void prepareCallbackBuffer (AudioBuffer<float>&, int16*) {}
196 
convertFromOpenSLjuce::BufferHelpers197     static void convertFromOpenSL (const int16* srcInterleaved, AudioBuffer<float>& audioBuffer)
198     {
199         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
200         {
201             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
202             using SrcSampleType = AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved,    AudioData::Const>;
203 
204             DstSampleType dstData (audioBuffer.getWritePointer (i));
205             SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels());
206             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
207         }
208     }
209 
convertToOpenSLjuce::BufferHelpers210     static void convertToOpenSL (const AudioBuffer<float>& audioBuffer, int16* dstInterleaved)
211     {
212         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
213         {
214             using DstSampleType = AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst>;
215             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
216 
217             DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels());
218             SrcSampleType srcData (audioBuffer.getReadPointer (i));
219 
220             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
221         }
222     }
223 
224 };
225 
226 template <>
227 struct BufferHelpers<float>
228 {
229     enum { isFloatingPoint = 1 };
230 
initPCMDataFormatjuce::BufferHelpers231     static void initPCMDataFormat (PCMDataFormatEx& dataFormat, int numChannels, double sampleRate)
232     {
233         dataFormat.formatType     = SL_ANDROID_DATAFORMAT_PCM_EX;
234         dataFormat.numChannels    = (SLuint32) numChannels;
235         dataFormat.samplesPerSec  = (SLuint32) (sampleRate * 1000);
236         dataFormat.bitsPerSample  = 32;
237         dataFormat.containerSize  = 32;
238         dataFormat.channelMask    = (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER :
239                                                         (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
240         dataFormat.endianness     = SL_BYTEORDER_LITTLEENDIAN;
241         dataFormat.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
242     }
243 
prepareCallbackBufferjuce::BufferHelpers244     static void prepareCallbackBuffer (AudioBuffer<float>& audioBuffer, float* native)
245     {
246         if (audioBuffer.getNumChannels() == 1)
247             audioBuffer.setDataToReferTo (&native, 1, audioBuffer.getNumSamples());
248     }
249 
convertFromOpenSLjuce::BufferHelpers250     static void convertFromOpenSL (const float* srcInterleaved, AudioBuffer<float>& audioBuffer)
251     {
252         if (audioBuffer.getNumChannels() == 1)
253         {
254             jassert (srcInterleaved == audioBuffer.getWritePointer (0));
255             return;
256         }
257 
258         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
259         {
260             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
261             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved,    AudioData::Const>;
262 
263             DstSampleType dstData (audioBuffer.getWritePointer (i));
264             SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels());
265             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
266         }
267     }
268 
convertToOpenSLjuce::BufferHelpers269     static void convertToOpenSL (const AudioBuffer<float>& audioBuffer, float* dstInterleaved)
270     {
271         if (audioBuffer.getNumChannels() == 1)
272         {
273             jassert (dstInterleaved == audioBuffer.getReadPointer (0));
274             return;
275         }
276 
277         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
278         {
279             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved,    AudioData::NonConst>;
280             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
281 
282             DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels());
283             SrcSampleType srcData (audioBuffer.getReadPointer (i));
284 
285             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
286         }
287     }
288 };
289 
290 //==============================================================================
291 using CreateEngineFunc = SLresult (*) (SLObjectItf*, SLuint32, const SLEngineOption*,
292                                        SLuint32, const SLInterfaceID*, const SLboolean*);
293 
294 struct OpenSLEngineHolder
295 {
OpenSLEngineHolderjuce::OpenSLEngineHolder296     OpenSLEngineHolder()
297     {
298         if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine"))
299         {
300             SLObjectItf obj = nullptr;
301             auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
302 
303             if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
304                 || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
305             {
306                 destroyObject (obj);
307             }
308 
309             engine = SlRef<SLEngineItf_>::cast (SlObjectRef (obj));
310         }
311     }
312 
313     DynamicLibrary slLibrary { "libOpenSLES.so" };
314     SlRef<SLEngineItf_> engine;
315 };
316 
getEngineHolder()317 OpenSLEngineHolder& getEngineHolder()
318 {
319     static OpenSLEngineHolder holder;
320     return holder;
321 }
322 
323 //==============================================================================
324 class SLRealtimeThread;
325 
326 //==============================================================================
327 class OpenSLAudioIODevice  : public AudioIODevice
328 {
329 public:
330     //==============================================================================
331     template <typename T>
332     class OpenSLSessionT;
333 
334     //==============================================================================
335     // CRTP
336     template <typename T, class Child, typename RunnerObjectType>
337     struct OpenSLQueueRunner
338     {
OpenSLQueueRunnerjuce::OpenSLAudioIODevice::OpenSLQueueRunner339         OpenSLQueueRunner (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
340             : owner (sessionToUse),
341               numChannels (numChannelsToUse),
342               nativeBuffer (static_cast<size_t> (numChannels * owner.bufferSize * owner.numBuffers)),
343               scratchBuffer (numChannelsToUse, owner.bufferSize),
344               sampleBuffer (scratchBuffer.getArrayOfWritePointers(), numChannelsToUse, owner.bufferSize)
345         {}
346 
~OpenSLQueueRunnerjuce::OpenSLAudioIODevice::OpenSLQueueRunner347         ~OpenSLQueueRunner()
348         {
349             if (config != nullptr && javaProxy != nullptr)
350             {
351                 javaProxy.clear();
352                 (*config)->ReleaseJavaProxy (config, /*SL_ANDROID_JAVA_PROXY_ROUTING*/1);
353             }
354         }
355 
initjuce::OpenSLAudioIODevice::OpenSLQueueRunner356         bool init()
357         {
358             runner = crtp().createPlayerOrRecorder();
359 
360             if (runner == nullptr)
361                 return false;
362 
363             const bool supportsJavaProxy = (getAndroidSDKVersion() >= 24);
364 
365             if (supportsJavaProxy)
366             {
367                 // may return nullptr on some platforms - that's ok
368                 config = SlRef<SLAndroidConfigurationItf_>::cast (runner);
369 
370                 if (config != nullptr)
371                 {
372                     jobject audioRoutingJni;
373                     auto status = (*config)->AcquireJavaProxy (config, /*SL_ANDROID_JAVA_PROXY_ROUTING*/1,
374                                                                &audioRoutingJni);
375 
376                     if (status == SL_RESULT_SUCCESS && audioRoutingJni != nullptr)
377                         javaProxy = GlobalRef (LocalRef<jobject>(getEnv()->NewLocalRef (audioRoutingJni)));
378                 }
379             }
380 
381             queue = SlRef<SLAndroidSimpleBufferQueueItf_>::cast (runner);
382 
383             if (queue == nullptr)
384                 return false;
385 
386             return ((*queue)->RegisterCallback (queue, staticFinished, this) == SL_RESULT_SUCCESS);
387         }
388 
clearjuce::OpenSLAudioIODevice::OpenSLQueueRunner389         void clear()
390         {
391             nextBlock.set (0);
392             numBlocksOut.set (0);
393 
394             zeromem (nativeBuffer.get(), static_cast<size_t> (owner.bufferSize * numChannels * owner.numBuffers) * sizeof (T));
395             scratchBuffer.clear();
396             (*queue)->Clear (queue);
397         }
398 
enqueueBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner399         void enqueueBuffer()
400         {
401             (*queue)->Enqueue (queue, getCurrentBuffer(), static_cast<SLuint32> (getBufferSizeInSamples() * sizeof (T)));
402             ++numBlocksOut;
403         }
404 
isBufferAvailablejuce::OpenSLAudioIODevice::OpenSLQueueRunner405         bool isBufferAvailable() const         { return (numBlocksOut.get() < owner.numBuffers); }
getNextBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner406         T* getNextBuffer()                     { nextBlock.set((nextBlock.get() + 1) % owner.numBuffers); return getCurrentBuffer(); }
getCurrentBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner407         T* getCurrentBuffer()                  { return nativeBuffer.get() + (static_cast<size_t> (nextBlock.get()) * getBufferSizeInSamples()); }
getBufferSizeInSamplesjuce::OpenSLAudioIODevice::OpenSLQueueRunner408         size_t getBufferSizeInSamples() const  { return static_cast<size_t> (owner.bufferSize * numChannels); }
409 
finishedjuce::OpenSLAudioIODevice::OpenSLQueueRunner410         void finished (SLAndroidSimpleBufferQueueItf)
411         {
412             --numBlocksOut;
413             owner.doSomeWorkOnAudioThread();
414         }
415 
staticFinishedjuce::OpenSLAudioIODevice::OpenSLQueueRunner416         static void staticFinished (SLAndroidSimpleBufferQueueItf caller, void *pContext)
417         {
418             reinterpret_cast<OpenSLQueueRunner*> (pContext)->finished (caller);
419         }
420 
421         // get the "this" pointer for CRTP
crtpjuce::OpenSLAudioIODevice::OpenSLQueueRunner422         Child&       crtp()       { return * ((Child*) this); }
crtpjuce::OpenSLAudioIODevice::OpenSLQueueRunner423         const Child& crtp() const { return * ((Child*) this); }
424 
425         OpenSLSessionT<T>& owner;
426 
427         SlRef<RunnerObjectType> runner;
428         SlRef<SLAndroidSimpleBufferQueueItf_> queue;
429         SlRef<SLAndroidConfigurationItf_> config;
430         GlobalRef javaProxy;
431 
432         int numChannels;
433 
434         HeapBlock<T> nativeBuffer;
435         AudioBuffer<float> scratchBuffer, sampleBuffer;
436 
437         Atomic<int> nextBlock { 0 }, numBlocksOut { 0 };
438     };
439 
440     //==============================================================================
441     template <typename T>
442     struct OpenSLQueueRunnerPlayer      : OpenSLQueueRunner<T, OpenSLQueueRunnerPlayer<T>, SLPlayItf_>
443     {
444         using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerPlayer<T>, SLPlayItf_>;
445 
OpenSLQueueRunnerPlayerjuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer446         OpenSLQueueRunnerPlayer (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
447             : Base (sessionToUse, numChannelsToUse)
448         {}
449 
createPlayerOrRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer450         SlRef<SLPlayItf_> createPlayerOrRecorder()
451         {
452             SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
453             SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, Base::owner.outputMix };
454 
455             PCMDataFormatEx dataFormat;
456             BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
457 
458             SLDataSource source = { &queueLocator, &dataFormat };
459             SLDataSink   sink   = { &outputMix,    nullptr };
460 
461             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
462             SLboolean interfaceRequired[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE};
463 
464             SLObjectItf obj = nullptr;
465 
466             auto& holder = getEngineHolder();
467 
468             if (auto e = *holder.engine)
469             {
470                 auto status = e->CreateAudioPlayer (holder.engine, &obj, &source, &sink, 2,
471                                                     queueInterfaces, interfaceRequired);
472 
473                 if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize(obj, 0) != SL_RESULT_SUCCESS)
474                 {
475                     destroyObject (obj);
476                     return {};
477                 }
478             }
479 
480             return SlRef<SLPlayItf_>::cast (SlObjectRef (obj));
481         }
482 
setStatejuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer483         void setState (bool running)    { (*Base::runner)->SetPlayState (Base::runner, running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED); }
484     };
485 
486     template <typename T>
487     struct OpenSLQueueRunnerRecorder  : public OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>
488     {
489         using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>;
490 
OpenSLQueueRunnerRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder491         OpenSLQueueRunnerRecorder (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
492             : Base (sessionToUse, numChannelsToUse)
493         {}
494 
createPlayerOrRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder495         SlRef<SLRecordItf_> createPlayerOrRecorder()
496         {
497             SLDataLocator_IODevice ioDeviceLocator = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
498             SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
499 
500             PCMDataFormatEx dataFormat;
501             BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
502 
503             SLDataSource source = { &ioDeviceLocator, nullptr };
504             SLDataSink   sink   = { &queueLocator,    &dataFormat };
505 
506             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
507             SLboolean interfaceRequired[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };
508 
509             SLObjectItf obj = nullptr;
510 
511             auto& holder = getEngineHolder();
512 
513             if (auto e = *holder.engine)
514             {
515                 auto status = e->CreateAudioRecorder (holder.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired);
516 
517                 if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
518                 {
519                     destroyObject (obj);
520                     return {};
521                 }
522             }
523 
524             return SlRef<SLRecordItf_>::cast (SlObjectRef (obj));
525         }
526 
setAudioPreprocessingEnabledjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder527         bool setAudioPreprocessingEnabled (bool shouldEnable)
528         {
529             if (Base::config != nullptr)
530             {
531                 const bool supportsUnprocessed = (getAndroidSDKVersion() >= 25);
532                 const SLuint32 recordingPresetValue
533                     = (shouldEnable ? SL_ANDROID_RECORDING_PRESET_GENERIC
534                                     : (supportsUnprocessed ? SL_ANDROID_RECORDING_PRESET_UNPROCESSED
535                                                            : SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION));
536 
537                 auto status = (*Base::config)->SetConfiguration (Base::config, SL_ANDROID_KEY_RECORDING_PRESET,
538                                                                  &recordingPresetValue, sizeof (recordingPresetValue));
539 
540                 return (status == SL_RESULT_SUCCESS);
541             }
542 
543             return false;
544         }
545 
setStatejuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder546         void setState (bool running)    { (*Base::runner)->SetRecordState (Base::runner, running ? SL_RECORDSTATE_RECORDING
547                                                                                                  : SL_RECORDSTATE_STOPPED); }
548     };
549 
550     //==============================================================================
551     class OpenSLSession
552     {
553     public:
OpenSLSession(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)554         OpenSLSession (int numInputChannels, int numOutputChannels,
555                        double samleRateToUse, int bufferSizeToUse,
556                        int numBuffersToUse)
557             : inputChannels (numInputChannels), outputChannels (numOutputChannels),
558               sampleRate (samleRateToUse), bufferSize (bufferSizeToUse), numBuffers (numBuffersToUse)
559         {
560             jassert (numInputChannels > 0 || numOutputChannels > 0);
561 
562             if (outputChannels > 0)
563             {
564                 auto& holder = getEngineHolder();
565                 SLObjectItf obj = nullptr;
566 
567                 auto err = (*holder.engine)->CreateOutputMix (holder.engine, &obj, 0, nullptr, nullptr);
568 
569                 if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
570                      || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
571                 {
572                     destroyObject (obj);
573                     return;
574                 }
575 
576                 outputMix = SlRef<SLOutputMixItf_>::cast (SlObjectRef (obj));
577             }
578         }
579 
~OpenSLSession()580         virtual ~OpenSLSession() {}
581 
openedOK() const582         virtual bool openedOK() const    { return (outputChannels == 0 || outputMix != nullptr); }
start()583         virtual void start()             { stop(); jassert (callback.get() != nullptr); running = true; }
stop()584         virtual void stop()              { running = false; }
585 
586         virtual bool setAudioPreprocessingEnabled (bool shouldEnable) = 0;
587         virtual bool supportsFloatingPoint() const noexcept = 0;
588         virtual int getXRunCount() const noexcept = 0;
589 
setCallback(AudioIODeviceCallback * callbackToUse)590         void setCallback (AudioIODeviceCallback* callbackToUse)
591         {
592             if (! running)
593             {
594                 callback.set (callbackToUse);
595                 return;
596             }
597 
598             // don't set callback to null! stop the playback instead!
599             jassert (callbackToUse != nullptr);
600 
601             // spin-lock until we can set the callback
602             for (;;)
603             {
604                 auto old = callback.get();
605 
606                 if (old == callbackToUse)
607                     break;
608 
609                 if (callback.compareAndSetBool (callbackToUse, old))
610                     break;
611 
612                 Thread::sleep (1);
613             }
614         }
615 
process(const float ** inputChannelData,float ** outputChannelData)616         void process (const float** inputChannelData, float** outputChannelData)
617         {
618             if (auto* cb = callback.exchange (nullptr))
619             {
620                 cb->audioDeviceIOCallback (inputChannelData, inputChannels, outputChannelData, outputChannels, bufferSize);
621                 callback.set (cb);
622             }
623             else
624             {
625                 for (int i = 0; i < outputChannels; ++i)
626                     zeromem (outputChannelData[i], sizeof(float) * static_cast<size_t> (bufferSize));
627             }
628         }
629 
630         static OpenSLSession* create (int numInputChannels, int numOutputChannels,
631                                       double samleRateToUse, int bufferSizeToUse,
632                                       int numBuffersToUse);
633 
634         //==============================================================================
635         int inputChannels, outputChannels;
636         double sampleRate;
637         int bufferSize, numBuffers;
638         bool running = false, audioProcessingEnabled = true;
639 
640         SlRef<SLOutputMixItf_> outputMix;
641 
642         Atomic<AudioIODeviceCallback*> callback { nullptr };
643     };
644 
645     template <typename T>
646     class OpenSLSessionT : public OpenSLSession
647     {
648     public:
OpenSLSessionT(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)649         OpenSLSessionT (int numInputChannels, int numOutputChannels,
650                         double samleRateToUse, int bufferSizeToUse,
651                         int numBuffersToUse)
652             : OpenSLSession (numInputChannels, numOutputChannels,
653                              samleRateToUse, bufferSizeToUse, numBuffersToUse)
654         {
655             jassert (numInputChannels > 0 || numOutputChannels > 0);
656 
657             if (OpenSLSession::openedOK())
658             {
659                 if (inputChannels > 0)
660                 {
661                     recorder.reset (new OpenSLQueueRunnerRecorder<T> (*this, inputChannels));
662 
663                     if (! recorder->init())
664                     {
665                         recorder = nullptr;
666                         return;
667                     }
668                 }
669 
670                 if (outputChannels > 0)
671                 {
672                     player.reset (new OpenSLQueueRunnerPlayer<T> (*this, outputChannels));
673 
674                     if (! player->init())
675                     {
676                         player = nullptr;
677                         return;
678                     }
679 
680                     const bool supportsUnderrunCount = (getAndroidSDKVersion() >= 24);
681                     getUnderrunCount = supportsUnderrunCount ? getEnv()->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : nullptr;
682                 }
683             }
684         }
685 
openedOK() const686         bool openedOK() const override
687         {
688             return OpenSLSession::openedOK() && (inputChannels == 0  || recorder != nullptr)
689                                              && (outputChannels == 0 || player   != nullptr);
690         }
691 
start()692         void start() override
693         {
694             OpenSLSession::start();
695 
696             guard.set (0);
697 
698             if (inputChannels > 0)
699                 recorder->clear();
700 
701             if (outputChannels > 0)
702                 player->clear();
703 
704             // first enqueue all buffers
705             for (int i = 0; i < numBuffers; ++i)
706                 doSomeWorkOnAudioThread();
707 
708             if (inputChannels > 0)
709                 recorder->setState (true);
710 
711             if (outputChannels > 0)
712                 player->setState (true);
713         }
714 
stop()715         void stop() override
716         {
717             OpenSLSession::stop();
718 
719             while (! guard.compareAndSetBool (1, 0))
720                 Thread::sleep (1);
721 
722             if (inputChannels > 0)
723                 recorder->setState (false);
724 
725             if (outputChannels > 0)
726                 player->setState (false);
727 
728             guard.set (0);
729         }
730 
setAudioPreprocessingEnabled(bool shouldEnable)731         bool setAudioPreprocessingEnabled (bool shouldEnable) override
732         {
733             if (shouldEnable != audioProcessingEnabled)
734             {
735                 audioProcessingEnabled = shouldEnable;
736 
737                 if (recorder != nullptr)
738                     return recorder->setAudioPreprocessingEnabled (audioProcessingEnabled);
739             }
740 
741             return true;
742         }
743 
getXRunCount() const744         int getXRunCount() const noexcept override
745         {
746             if (player != nullptr && player->javaProxy != nullptr && getUnderrunCount != nullptr)
747                 return getEnv()->CallIntMethod (player->javaProxy, getUnderrunCount);
748 
749             return -1;
750         }
751 
supportsFloatingPoint() const752         bool supportsFloatingPoint() const noexcept override          { return (BufferHelpers<T>::isFloatingPoint != 0); }
753 
doSomeWorkOnAudioThread()754         void doSomeWorkOnAudioThread()
755         {
756             // only the player or the recorder should enter this section at any time
757             if (guard.compareAndSetBool (1, 0))
758             {
759                 // are there enough buffers available to process some audio
760                 if ((inputChannels == 0 || recorder->isBufferAvailable()) && (outputChannels == 0 || player->isBufferAvailable()))
761                 {
762                     T* recorderBuffer = (inputChannels  > 0 ? recorder->getNextBuffer() : nullptr);
763                     T* playerBuffer   = (outputChannels > 0 ? player->getNextBuffer()   : nullptr);
764 
765                     const float** inputChannelData = nullptr;
766                     float** outputChannelData = nullptr;
767 
768                     if (recorderBuffer != nullptr)
769                     {
770                         BufferHelpers<T>::prepareCallbackBuffer (recorder->sampleBuffer, recorderBuffer);
771                         BufferHelpers<T>::convertFromOpenSL (recorderBuffer, recorder->sampleBuffer);
772 
773                         inputChannelData = recorder->sampleBuffer.getArrayOfReadPointers();
774                     }
775 
776                     if (playerBuffer != nullptr)
777                     {
778                         BufferHelpers<T>::prepareCallbackBuffer (player->sampleBuffer, playerBuffer);
779                         outputChannelData = player->sampleBuffer.getArrayOfWritePointers();
780                     }
781 
782                     process (inputChannelData, outputChannelData);
783 
784                     if (recorderBuffer != nullptr)
785                         recorder->enqueueBuffer();
786 
787                     if (playerBuffer != nullptr)
788                     {
789                         BufferHelpers<T>::convertToOpenSL (player->sampleBuffer, playerBuffer);
790                         player->enqueueBuffer();
791                     }
792                 }
793 
794                 guard.set (0);
795             }
796         }
797 
798         //==============================================================================
799         std::unique_ptr<OpenSLQueueRunnerPlayer<T>> player;
800         std::unique_ptr<OpenSLQueueRunnerRecorder<T>> recorder;
801         Atomic<int> guard;
802         jmethodID getUnderrunCount = nullptr;
803     };
804 
805     //==============================================================================
OpenSLAudioIODevice(const String & deviceName)806     OpenSLAudioIODevice (const String& deviceName)  : AudioIODevice (deviceName, openSLTypeName)
807     {
808         // OpenSL has piss-poor support for determining latency, so the only way I can find to
809         // get a number for this is by asking the AudioTrack/AudioRecord classes..
810         AndroidAudioIODevice javaDevice (deviceName);
811 
812         // this is a total guess about how to calculate the latency, but seems to vaguely agree
813         // with the devices I've tested.. YMMV
814         inputLatency  = (javaDevice.minBufferSizeIn  * 2) / 3;
815         outputLatency = (javaDevice.minBufferSizeOut * 2) / 3;
816 
817         const int64 longestLatency = jmax (inputLatency, outputLatency);
818         const int64 totalLatency = inputLatency + outputLatency;
819         inputLatency  = (int) ((longestLatency * inputLatency)  / totalLatency) & ~15;
820         outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15;
821 
822         // You can only create this class if you are sure that your hardware supports OpenSL
823         jassert (getEngineHolder().slLibrary.getNativeHandle() != nullptr);
824     }
825 
~OpenSLAudioIODevice()826     ~OpenSLAudioIODevice() override
827     {
828         close();
829     }
830 
openedOk() const831     bool openedOk() const       { return session != nullptr; }
832 
getOutputChannelNames()833     StringArray getOutputChannelNames() override
834     {
835         StringArray s;
836         s.add ("Left");
837         s.add ("Right");
838         return s;
839     }
840 
getInputChannelNames()841     StringArray getInputChannelNames() override
842     {
843         StringArray s;
844         s.add ("Audio Input");
845         return s;
846     }
847 
getAvailableSampleRates()848     Array<double> getAvailableSampleRates() override
849     {
850         // see https://developer.android.com/ndk/guides/audio/opensl-for-android.html
851 
852         static const double rates[] = { 8000.0, 11025.0, 12000.0, 16000.0,
853                                         22050.0, 24000.0, 32000.0, 44100.0, 48000.0 };
854 
855         Array<double> retval (rates, numElementsInArray (rates));
856 
857         // make sure the native sample rate is part of the list
858         double native = AndroidHighPerformanceAudioHelpers::getNativeSampleRate();
859 
860         if (native != 0.0 && ! retval.contains (native))
861             retval.add (native);
862 
863         return retval;
864     }
865 
getAvailableBufferSizes()866     Array<int> getAvailableBufferSizes() override
867     {
868         return AndroidHighPerformanceAudioHelpers::getAvailableBufferSizes (AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(),
869                                                                             getAvailableSampleRates());
870     }
871 
open(const BigInteger & inputChannels,const BigInteger & outputChannels,double requestedSampleRate,int bufferSize)872     String open (const BigInteger& inputChannels,
873                  const BigInteger& outputChannels,
874                  double requestedSampleRate,
875                  int bufferSize) override
876     {
877         close();
878 
879         lastError.clear();
880 
881         sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : AndroidHighPerformanceAudioHelpers::getNativeSampleRate());
882         auto preferredBufferSize = (bufferSize > 0) ? bufferSize : getDefaultBufferSize();
883 
884         audioBuffersToEnqueue = [this, preferredBufferSize]
885         {
886             using namespace AndroidHighPerformanceAudioHelpers;
887 
888             auto nativeBufferSize = getNativeBufferSizeHint();
889 
890             if (canUseHighPerformanceAudioPath (nativeBufferSize, preferredBufferSize, sampleRate))
891                 return preferredBufferSize / nativeBufferSize;
892 
893 
894             return 1;
895         }();
896 
897         actualBufferSize = preferredBufferSize / audioBuffersToEnqueue;
898 
899         jassert ((actualBufferSize * audioBuffersToEnqueue) == preferredBufferSize);
900 
901         activeOutputChans = outputChannels;
902         activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
903         auto numOutputChannels = activeOutputChans.countNumberOfSetBits();
904 
905         activeInputChans = inputChannels;
906         activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
907         auto numInputChannels = activeInputChans.countNumberOfSetBits();
908 
909         if (numInputChannels > 0 && (! RuntimePermissions::isGranted (RuntimePermissions::recordAudio)))
910         {
911             // If you hit this assert, you probably forgot to get RuntimePermissions::recordAudio
912             // before trying to open an audio input device. This is not going to work!
913             jassertfalse;
914             lastError = "Error opening OpenSL input device: the app was not granted android.permission.RECORD_AUDIO";
915         }
916 
917         session.reset (OpenSLSession::create (numInputChannels, numOutputChannels,
918                                               sampleRate, actualBufferSize, audioBuffersToEnqueue));
919         if (session != nullptr)
920         {
921             session->setAudioPreprocessingEnabled (audioProcessingEnabled);
922         }
923         else
924         {
925             if (numInputChannels > 0 && numOutputChannels > 0 && RuntimePermissions::isGranted (RuntimePermissions::recordAudio))
926             {
927                 // New versions of the Android emulator do not seem to support audio input anymore on OS X
928                 activeInputChans = BigInteger(0);
929                 numInputChannels = 0;
930 
931                 session.reset (OpenSLSession::create (numInputChannels, numOutputChannels,
932                                                       sampleRate, actualBufferSize, audioBuffersToEnqueue));
933             }
934         }
935 
936         DBG ("OpenSL: numInputChannels = " << numInputChannels
937              << ", numOutputChannels = " << numOutputChannels
938              << ", nativeBufferSize = " << AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint()
939              << ", nativeSampleRate = " << AndroidHighPerformanceAudioHelpers::getNativeSampleRate()
940              << ", actualBufferSize = " << actualBufferSize
941              << ", audioBuffersToEnqueue = " << audioBuffersToEnqueue
942              << ", sampleRate = " << sampleRate
943              << ", supportsFloatingPoint = " << (session != nullptr && session->supportsFloatingPoint() ? "true" : "false"));
944 
945         if (session == nullptr)
946             lastError = "Unknown error initializing opensl session";
947 
948         deviceOpen = (session != nullptr);
949         return lastError;
950     }
951 
close()952     void close() override
953     {
954         stop();
955         session = nullptr;
956         callback = nullptr;
957     }
958 
getOutputLatencyInSamples()959     int getOutputLatencyInSamples() override            { return outputLatency; }
getInputLatencyInSamples()960     int getInputLatencyInSamples() override             { return inputLatency; }
isOpen()961     bool isOpen() override                              { return deviceOpen; }
getCurrentBufferSizeSamples()962     int getCurrentBufferSizeSamples() override          { return actualBufferSize * audioBuffersToEnqueue; }
getCurrentBitDepth()963     int getCurrentBitDepth() override                   { return (session != nullptr && session->supportsFloatingPoint() ? 32 : 16); }
getActiveOutputChannels() const964     BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
getActiveInputChannels() const965     BigInteger getActiveInputChannels() const override  { return activeInputChans; }
getLastError()966     String getLastError() override                      { return lastError; }
isPlaying()967     bool isPlaying() override                           { return callback != nullptr; }
getXRunCount() const968     int getXRunCount() const noexcept override          { return (session != nullptr ? session->getXRunCount() : -1); }
969 
getDefaultBufferSize()970     int getDefaultBufferSize() override
971     {
972         return AndroidHighPerformanceAudioHelpers::getDefaultBufferSize (AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint(),
973                                                                          getCurrentSampleRate());
974     }
975 
getCurrentSampleRate()976     double getCurrentSampleRate() override
977     {
978         return (sampleRate == 0.0 ? AndroidHighPerformanceAudioHelpers::getNativeSampleRate() : sampleRate);
979     }
980 
start(AudioIODeviceCallback * newCallback)981     void start (AudioIODeviceCallback* newCallback) override
982     {
983         if (session != nullptr && callback != newCallback)
984         {
985             auto oldCallback = callback;
986 
987             if (newCallback != nullptr)
988                 newCallback->audioDeviceAboutToStart (this);
989 
990             if (oldCallback != nullptr)
991             {
992                 // already running
993                 if (newCallback == nullptr)
994                     stop();
995                 else
996                     session->setCallback (newCallback);
997 
998                 oldCallback->audioDeviceStopped();
999             }
1000             else
1001             {
1002                 jassert (newCallback != nullptr);
1003 
1004                 // session hasn't started yet
1005                 session->setCallback (newCallback);
1006                 session->start();
1007             }
1008 
1009             callback = newCallback;
1010         }
1011     }
1012 
stop()1013     void stop() override
1014     {
1015         if (session != nullptr && callback != nullptr)
1016         {
1017             callback = nullptr;
1018             session->stop();
1019             session->setCallback (nullptr);
1020         }
1021     }
1022 
setAudioPreprocessingEnabled(bool shouldAudioProcessingBeEnabled)1023     bool setAudioPreprocessingEnabled (bool shouldAudioProcessingBeEnabled) override
1024     {
1025         audioProcessingEnabled = shouldAudioProcessingBeEnabled;
1026 
1027         if (session != nullptr)
1028             session->setAudioPreprocessingEnabled (audioProcessingEnabled);
1029 
1030         return true;
1031     }
1032 
1033     static const char* const openSLTypeName;
1034 
1035 private:
1036     //==============================================================================
1037     friend class SLRealtimeThread;
1038 
1039     //==============================================================================
1040     int actualBufferSize = 0, sampleRate = 0, audioBuffersToEnqueue = 0;
1041     int inputLatency, outputLatency;
1042     bool deviceOpen = false, audioProcessingEnabled = true;
1043     String lastError;
1044     BigInteger activeOutputChans, activeInputChans;
1045     AudioIODeviceCallback* callback = nullptr;
1046 
1047     std::unique_ptr<OpenSLSession> session;
1048 
1049     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
1050 };
1051 
create(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)1052 OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create (int numInputChannels, int numOutputChannels,
1053                                                                                 double samleRateToUse, int bufferSizeToUse,
1054                                                                                 int numBuffersToUse)
1055 {
1056     std::unique_ptr<OpenSLSession> retval;
1057     auto sdkVersion = getAndroidSDKVersion();
1058 
1059     // SDK versions 21 and higher should natively support floating point...
1060     if (sdkVersion >= 21)
1061     {
1062         retval.reset (new OpenSLSessionT<float> (numInputChannels, numOutputChannels, samleRateToUse,
1063                                                  bufferSizeToUse, numBuffersToUse));
1064 
1065         // ...however, some devices lie so re-try without floating point
1066         if (retval != nullptr && (! retval->openedOK()))
1067             retval = nullptr;
1068     }
1069 
1070     if (retval == nullptr)
1071     {
1072         retval.reset (new OpenSLSessionT<int16> (numInputChannels, numOutputChannels, samleRateToUse,
1073                                                  bufferSizeToUse, numBuffersToUse));
1074 
1075         if (retval != nullptr && (! retval->openedOK()))
1076             retval = nullptr;
1077     }
1078 
1079     return retval.release();
1080 }
1081 
1082 //==============================================================================
1083 class OpenSLAudioDeviceType  : public AudioIODeviceType
1084 {
1085 public:
OpenSLAudioDeviceType()1086     OpenSLAudioDeviceType()  : AudioIODeviceType (OpenSLAudioIODevice::openSLTypeName) {}
1087 
1088     //==============================================================================
scanForDevices()1089     void scanForDevices() override {}
1090 
getDeviceNames(bool) const1091     StringArray getDeviceNames (bool) const override                             { return StringArray (OpenSLAudioIODevice::openSLTypeName); }
getDefaultDeviceIndex(bool) const1092     int getDefaultDeviceIndex (bool) const override                              { return 0; }
getIndexOfDevice(AudioIODevice * device,bool) const1093     int getIndexOfDevice (AudioIODevice* device, bool) const override            { return device != nullptr ? 0 : -1; }
hasSeparateInputsAndOutputs() const1094     bool hasSeparateInputsAndOutputs() const override                            { return false; }
1095 
createDevice(const String & outputDeviceName,const String & inputDeviceName)1096     AudioIODevice* createDevice (const String& outputDeviceName,
1097                                  const String& inputDeviceName) override
1098     {
1099         std::unique_ptr<OpenSLAudioIODevice> dev;
1100 
1101         if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
1102             dev.reset (new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
1103                                                                               : inputDeviceName));
1104 
1105         return dev.release();
1106     }
1107 
isOpenSLAvailable()1108     static bool isOpenSLAvailable()
1109     {
1110         DynamicLibrary library;
1111         return library.open ("libOpenSLES.so");
1112     }
1113 
1114     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
1115 };
1116 
1117 const char* const OpenSLAudioIODevice::openSLTypeName = "Android OpenSL";
1118 
1119 
1120 //==============================================================================
isOpenSLAvailable()1121 bool isOpenSLAvailable()  { return OpenSLAudioDeviceType::isOpenSLAvailable(); }
1122 
1123 //==============================================================================
1124 class SLRealtimeThread
1125 {
1126 public:
1127     static constexpr int numBuffers = 4;
1128 
SLRealtimeThread()1129     SLRealtimeThread()
1130     {
1131         if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine"))
1132         {
1133             SLObjectItf obj = nullptr;
1134             auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
1135 
1136             if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr)
1137                 return;
1138 
1139             if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1140             {
1141                 destroyObject (obj);
1142                 return;
1143             }
1144 
1145             engine = SlRef<SLEngineItf_>::cast (SlObjectRef (obj));
1146 
1147             if (engine == nullptr)
1148             {
1149                 destroyObject (obj);
1150                 return;
1151             }
1152 
1153             obj = nullptr;
1154             err = (*engine)->CreateOutputMix (engine, &obj, 0, nullptr, nullptr);
1155 
1156             if (err != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1157             {
1158                 destroyObject (obj);
1159                 return;
1160             }
1161 
1162             outputMix = SlRef<SLOutputMixItf_>::cast (SlObjectRef (obj));
1163 
1164             if (outputMix == nullptr)
1165             {
1166                 destroyObject (obj);
1167                 return;
1168             }
1169 
1170             SLDataLocator_AndroidSimpleBufferQueue queueLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (numBuffers)};
1171             SLDataLocator_OutputMix outputMixLocator = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
1172 
1173             PCMDataFormatEx dataFormat;
1174             BufferHelpers<int16>::initPCMDataFormat (dataFormat, 1, AndroidHighPerformanceAudioHelpers::getNativeSampleRate());
1175 
1176             SLDataSource source = { &queueLocator, &dataFormat };
1177             SLDataSink   sink   = { &outputMixLocator, nullptr };
1178 
1179             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid };
1180             SLboolean trueFlag = SL_BOOLEAN_TRUE;
1181 
1182             obj = nullptr;
1183             err = (*engine)->CreateAudioPlayer (engine, &obj, &source, &sink, 1, queueInterfaces, &trueFlag);
1184 
1185             if (err != SL_RESULT_SUCCESS || obj == nullptr)
1186                 return;
1187 
1188             if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1189             {
1190                 destroyObject (obj);
1191                 return;
1192             }
1193 
1194             player = SlRef<SLPlayItf_>::cast (SlObjectRef (obj));
1195 
1196             if (player == nullptr)
1197             {
1198                 destroyObject (obj);
1199                 return;
1200             }
1201 
1202             queue = SlRef<SLAndroidSimpleBufferQueueItf_>::cast (player);
1203             if (queue == nullptr)
1204                 return;
1205 
1206             if ((*queue)->RegisterCallback (queue, staticFinished, this) != SL_RESULT_SUCCESS)
1207             {
1208                 queue = nullptr;
1209                 return;
1210             }
1211 
1212             pthread_cond_init (&threadReady, nullptr);
1213             pthread_mutex_init (&threadReadyMutex, nullptr);
1214         }
1215     }
1216 
isOk() const1217     bool isOk() const      { return queue != nullptr; }
1218 
startThread(void * (* entry)(void *),void * userPtr)1219     pthread_t startThread (void* (*entry) (void*), void* userPtr)
1220     {
1221         memset (buffer.get(), 0, static_cast<size_t> (sizeof (int16) * static_cast<size_t> (bufferSize * numBuffers)));
1222 
1223         for (int i = 0; i < numBuffers; ++i)
1224         {
1225             int16* dst = buffer.get() + (bufferSize * i);
1226             (*queue)->Enqueue (queue, dst, static_cast<SLuint32> (static_cast<size_t> (bufferSize) * sizeof (int16)));
1227         }
1228 
1229         pthread_mutex_lock (&threadReadyMutex);
1230 
1231         threadEntryProc = entry;
1232         threadUserPtr  = userPtr;
1233 
1234         (*player)->SetPlayState (player, SL_PLAYSTATE_PLAYING);
1235 
1236         pthread_cond_wait (&threadReady, &threadReadyMutex);
1237         pthread_mutex_unlock (&threadReadyMutex);
1238 
1239         return threadID;
1240     }
1241 
finished()1242     void finished()
1243     {
1244         if (threadEntryProc != nullptr)
1245         {
1246             pthread_mutex_lock (&threadReadyMutex);
1247 
1248             threadID = pthread_self();
1249 
1250             pthread_cond_signal (&threadReady);
1251             pthread_mutex_unlock (&threadReadyMutex);
1252 
1253             threadEntryProc (threadUserPtr);
1254             threadEntryProc = nullptr;
1255 
1256             (*player)->SetPlayState (player, SL_PLAYSTATE_STOPPED);
1257             MessageManager::callAsync ([this]() { delete this; });
1258         }
1259     }
1260 
1261 private:
1262     //==============================================================================
staticFinished(SLAndroidSimpleBufferQueueItf,void * context)1263     static void staticFinished (SLAndroidSimpleBufferQueueItf, void* context)
1264     {
1265         static_cast<SLRealtimeThread*> (context)->finished();
1266     }
1267 
1268     //==============================================================================
1269     DynamicLibrary slLibrary { "libOpenSLES.so" };
1270 
1271     SlRef<SLEngineItf_>    engine;
1272     SlRef<SLOutputMixItf_> outputMix;
1273     SlRef<SLPlayItf_>      player;
1274     SlRef<SLAndroidSimpleBufferQueueItf_> queue;
1275 
1276     int bufferSize = AndroidHighPerformanceAudioHelpers::getNativeBufferSizeHint();
1277     HeapBlock<int16> buffer { HeapBlock<int16> (static_cast<size_t> (1 * bufferSize * numBuffers)) };
1278 
1279     void* (*threadEntryProc) (void*) = nullptr;
1280     void* threadUserPtr              = nullptr;
1281 
1282     pthread_cond_t  threadReady;
1283     pthread_mutex_t threadReadyMutex;
1284     pthread_t       threadID;
1285 };
1286 
1287 //==============================================================================
juce_createRealtimeAudioThread(void * (* entry)(void *),void * userPtr)1288 pthread_t juce_createRealtimeAudioThread (void* (*entry) (void*), void* userPtr)
1289 {
1290     auto thread = std::make_unique<SLRealtimeThread>();
1291 
1292     if (! thread->isOk())
1293         return {};
1294 
1295     auto threadID = thread->startThread (entry, userPtr);
1296 
1297     // the thread will de-allocate itself
1298     thread.release();
1299 
1300     return threadID;
1301 }
1302 
1303 } // namespace juce
1304