1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2017 - ROLI Ltd.
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 template <>
75 struct ContainerDeletePolicy<const SLObjectItf_* const>
76 {
destroyjuce::ContainerDeletePolicy77     static void destroy (SLObjectItf object)
78     {
79         destroyObject (object);
80     }
81 };
82 
83 //==============================================================================
84 // Some life-time and type management of OpenSL objects
85 class SlObjectRef
86 {
87 public:
88     //==============================================================================
SlObjectRef()89     SlObjectRef() noexcept {}
SlObjectRef(const SlObjectRef & obj)90     SlObjectRef (const SlObjectRef& obj) noexcept : cb (obj.cb) {}
SlObjectRef(SlObjectRef && obj)91     SlObjectRef (SlObjectRef&& obj) noexcept : cb (std::move (obj.cb)) { obj.cb = nullptr; }
SlObjectRef(SLObjectItf o)92     explicit SlObjectRef (SLObjectItf o) : cb (new ControlBlock (o)) {}
93 
94     //==============================================================================
operator =(const SlObjectRef & r)95     SlObjectRef& operator= (const SlObjectRef& r) noexcept  { cb = r.cb; return *this; }
operator =(SlObjectRef && r)96     SlObjectRef& operator= (SlObjectRef&& r) noexcept       { cb = std::move (r.cb); r.cb = nullptr; return *this; }
operator =(std::nullptr_t)97     SlObjectRef& operator= (std::nullptr_t) noexcept        { cb = nullptr; return *this; }
98 
99     //==============================================================================
operator *()100     const SLObjectItf_* operator*() noexcept                { return *cb->ptr.get(); }
operator ->()101     SLObjectItf operator->() noexcept                       { return (cb == nullptr ? nullptr :  cb->ptr.get()); }
operator SLObjectItf()102     operator SLObjectItf() noexcept                         { return (cb == nullptr ? nullptr :  cb->ptr.get()); }
103 
104     //==============================================================================
operator ==(nullptr_t) const105     bool operator== (nullptr_t) const noexcept              { return (cb == nullptr || cb->ptr == nullptr); }
operator !=(nullptr_t) const106     bool operator!= (nullptr_t) const noexcept              { return (cb != nullptr && cb->ptr != nullptr); }
107 
108 private:
109     //==============================================================================
110     struct ControlBlock : ReferenceCountedObject
111     {
112         ControlBlock() = default;
ControlBlockjuce::SlObjectRef::ControlBlock113         ControlBlock (SLObjectItf o) : ptr (o) {}
114 
115         std::unique_ptr<const SLObjectItf_* const> ptr;
116     };
117 
118     ReferenceCountedObjectPtr<ControlBlock> cb;
119 };
120 
121 template <typename T>
122 class SlRef : public SlObjectRef
123 {
124 public:
125     //==============================================================================
SlRef()126     SlRef() noexcept {}
SlRef(const SlRef & r)127     SlRef (const SlRef& r) noexcept : SlObjectRef (r), type (r.type) {}
SlRef(SlRef && r)128     SlRef (SlRef&& r) noexcept : SlObjectRef (std::move (r)), type (r.type) { r.type = nullptr; }
129 
130     //==============================================================================
operator =(const SlRef & r)131     SlRef& operator= (const SlRef& r)  noexcept { SlObjectRef::operator= (r); type = r.type; return *this; }
operator =(SlRef && r)132     SlRef& operator= (SlRef&& r) noexcept       { SlObjectRef::operator= (std::move (r)); type = r.type; r.type = nullptr; return *this; }
operator =(std::nullptr_t)133     SlRef& operator= (std::nullptr_t) noexcept  { SlObjectRef::operator= (nullptr); type = nullptr; return *this; }
134 
135     //==============================================================================
operator *()136     T* const operator*() noexcept               { return *type; }
operator ->()137     T* const* operator->() noexcept             { return type; }
operator T*const*()138     operator T* const*() noexcept               { return type; }
139 
140     //==============================================================================
cast(SlObjectRef & base)141     static SlRef cast (SlObjectRef&  base)      { return SlRef (base); }
cast(SlObjectRef && base)142     static SlRef cast (SlObjectRef&& base)      { return SlRef (std::move (base)); }
143 
144 private:
SlRef(SlObjectRef & base)145     SlRef (SlObjectRef& base) : SlObjectRef (base)
146     {
147         if (auto obj = SlObjectRef::operator->())
148         {
149             auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
150 
151             if (type != nullptr && err == SL_RESULT_SUCCESS)
152                 return;
153         }
154 
155         *this = nullptr;
156     }
157 
SlRef(SlObjectRef && base)158     SlRef (SlObjectRef&& base) : SlObjectRef (std::move (base))
159     {
160         if (auto obj = SlObjectRef::operator->())
161         {
162             auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
163             base = nullptr;
164 
165             if (type != nullptr && err == SL_RESULT_SUCCESS)
166                 return;
167         }
168 
169         *this = nullptr;
170     }
171 
172     T* const* type = nullptr;
173 };
174 
175 //==============================================================================
176 template <typename T> struct BufferHelpers {};
177 
178 template <>
179 struct BufferHelpers<int16>
180 {
181     enum { isFloatingPoint = 0 };
182 
initPCMDataFormatjuce::BufferHelpers183     static void initPCMDataFormat (PCMDataFormatEx& dataFormat, int numChannels, double sampleRate)
184     {
185         dataFormat.formatType     = SL_DATAFORMAT_PCM;
186         dataFormat.numChannels    = (SLuint32) numChannels;
187         dataFormat.samplesPerSec  = (SLuint32) (sampleRate * 1000);
188         dataFormat.bitsPerSample  = SL_PCMSAMPLEFORMAT_FIXED_16;
189         dataFormat.containerSize  = SL_PCMSAMPLEFORMAT_FIXED_16;
190         dataFormat.channelMask    = (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER :
191                                                         (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
192         dataFormat.endianness     = SL_BYTEORDER_LITTLEENDIAN;
193         dataFormat.representation = 0;
194     }
195 
prepareCallbackBufferjuce::BufferHelpers196     static void prepareCallbackBuffer (AudioBuffer<float>&, int16*) {}
197 
convertFromOpenSLjuce::BufferHelpers198     static void convertFromOpenSL (const int16* srcInterleaved, AudioBuffer<float>& audioBuffer)
199     {
200         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
201         {
202             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
203             using SrcSampleType = AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved,    AudioData::Const>;
204 
205             DstSampleType dstData (audioBuffer.getWritePointer (i));
206             SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels());
207             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
208         }
209     }
210 
convertToOpenSLjuce::BufferHelpers211     static void convertToOpenSL (const AudioBuffer<float>& audioBuffer, int16* dstInterleaved)
212     {
213         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
214         {
215             using DstSampleType = AudioData::Pointer<AudioData::Int16,   AudioData::LittleEndian, AudioData::Interleaved, AudioData::NonConst>;
216             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
217 
218             DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels());
219             SrcSampleType srcData (audioBuffer.getReadPointer (i));
220 
221             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
222         }
223     }
224 
225 };
226 
227 template <>
228 struct BufferHelpers<float>
229 {
230     enum { isFloatingPoint = 1 };
231 
initPCMDataFormatjuce::BufferHelpers232     static void initPCMDataFormat (PCMDataFormatEx& dataFormat, int numChannels, double sampleRate)
233     {
234         dataFormat.formatType     = SL_ANDROID_DATAFORMAT_PCM_EX;
235         dataFormat.numChannels    = (SLuint32) numChannels;
236         dataFormat.samplesPerSec  = (SLuint32) (sampleRate * 1000);
237         dataFormat.bitsPerSample  = 32;
238         dataFormat.containerSize  = 32;
239         dataFormat.channelMask    = (numChannels == 1) ? SL_SPEAKER_FRONT_CENTER :
240                                                         (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
241         dataFormat.endianness     = SL_BYTEORDER_LITTLEENDIAN;
242         dataFormat.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
243     }
244 
prepareCallbackBufferjuce::BufferHelpers245     static void prepareCallbackBuffer (AudioBuffer<float>& audioBuffer, float* native)
246     {
247         if (audioBuffer.getNumChannels() == 1)
248             audioBuffer.setDataToReferTo (&native, 1, audioBuffer.getNumSamples());
249     }
250 
convertFromOpenSLjuce::BufferHelpers251     static void convertFromOpenSL (const float* srcInterleaved, AudioBuffer<float>& audioBuffer)
252     {
253         if (audioBuffer.getNumChannels() == 1)
254         {
255             jassert (srcInterleaved == audioBuffer.getWritePointer (0));
256             return;
257         }
258 
259         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
260         {
261             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
262             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved,    AudioData::Const>;
263 
264             DstSampleType dstData (audioBuffer.getWritePointer (i));
265             SrcSampleType srcData (srcInterleaved + i, audioBuffer.getNumChannels());
266             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
267         }
268     }
269 
convertToOpenSLjuce::BufferHelpers270     static void convertToOpenSL (const AudioBuffer<float>& audioBuffer, float* dstInterleaved)
271     {
272         if (audioBuffer.getNumChannels() == 1)
273         {
274             jassert (dstInterleaved == audioBuffer.getReadPointer (0));
275             return;
276         }
277 
278         for (int i = 0; i < audioBuffer.getNumChannels(); ++i)
279         {
280             using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::LittleEndian, AudioData::Interleaved,    AudioData::NonConst>;
281             using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
282 
283             DstSampleType dstData (dstInterleaved + i, audioBuffer.getNumChannels());
284             SrcSampleType srcData (audioBuffer.getReadPointer (i));
285 
286             dstData.convertSamples (srcData, audioBuffer.getNumSamples());
287         }
288     }
289 };
290 
291 //==============================================================================
292 using CreateEngineFunc = SLresult (*) (SLObjectItf*, SLuint32, const SLEngineOption*,
293                                        SLuint32, const SLInterfaceID*, const SLboolean*);
294 
295 struct OpenSLEngineHolder
296 {
OpenSLEngineHolderjuce::OpenSLEngineHolder297     OpenSLEngineHolder()
298     {
299         if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine"))
300         {
301             SLObjectItf obj = nullptr;
302             auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
303 
304             if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
305                 || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
306             {
307                 destroyObject (obj);
308             }
309 
310             engine = SlRef<SLEngineItf_>::cast (SlObjectRef (obj));
311         }
312     }
313 
314     DynamicLibrary slLibrary { "libOpenSLES.so" };
315     SlRef<SLEngineItf_> engine;
316 };
317 
getEngineHolder()318 OpenSLEngineHolder& getEngineHolder()
319 {
320     static OpenSLEngineHolder holder;
321     return holder;
322 }
323 
324 //==============================================================================
325 class SLRealtimeThread;
326 
327 //==============================================================================
328 class OpenSLAudioIODevice  : public AudioIODevice
329 {
330 public:
331     //==============================================================================
332     template <typename T>
333     class OpenSLSessionT;
334 
335     //==============================================================================
336     // CRTP
337     template <typename T, class Child, typename RunnerObjectType>
338     struct OpenSLQueueRunner
339     {
OpenSLQueueRunnerjuce::OpenSLAudioIODevice::OpenSLQueueRunner340         OpenSLQueueRunner (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
341             : owner (sessionToUse),
342               numChannels (numChannelsToUse),
343               nativeBuffer (static_cast<size_t> (numChannels * owner.bufferSize * owner.numBuffers)),
344               scratchBuffer (numChannelsToUse, owner.bufferSize),
345               sampleBuffer (scratchBuffer.getArrayOfWritePointers(), numChannelsToUse, owner.bufferSize)
346         {}
347 
~OpenSLQueueRunnerjuce::OpenSLAudioIODevice::OpenSLQueueRunner348         ~OpenSLQueueRunner()
349         {
350             if (config != nullptr && javaProxy != nullptr)
351             {
352                 javaProxy.clear();
353                 (*config)->ReleaseJavaProxy (config, /*SL_ANDROID_JAVA_PROXY_ROUTING*/1);
354             }
355         }
356 
initjuce::OpenSLAudioIODevice::OpenSLQueueRunner357         bool init()
358         {
359             runner = crtp().createPlayerOrRecorder();
360 
361             if (runner == nullptr)
362                 return false;
363 
364             const bool supportsJavaProxy = (getAndroidSDKVersion() >= 24);
365 
366             if (supportsJavaProxy)
367             {
368                 // may return nullptr on some platforms - that's ok
369                 config = SlRef<SLAndroidConfigurationItf_>::cast (runner);
370 
371                 if (config != nullptr)
372                 {
373                     jobject audioRoutingJni;
374                     auto status = (*config)->AcquireJavaProxy (config, /*SL_ANDROID_JAVA_PROXY_ROUTING*/1,
375                                                                &audioRoutingJni);
376 
377                     if (status == SL_RESULT_SUCCESS && audioRoutingJni != nullptr)
378                         javaProxy = GlobalRef (LocalRef<jobject>(getEnv()->NewLocalRef (audioRoutingJni)));
379                 }
380             }
381 
382             queue = SlRef<SLAndroidSimpleBufferQueueItf_>::cast (runner);
383 
384             if (queue == nullptr)
385                 return false;
386 
387             return ((*queue)->RegisterCallback (queue, staticFinished, this) == SL_RESULT_SUCCESS);
388         }
389 
clearjuce::OpenSLAudioIODevice::OpenSLQueueRunner390         void clear()
391         {
392             nextBlock.set (0);
393             numBlocksOut.set (0);
394 
395             zeromem (nativeBuffer.get(), static_cast<size_t> (owner.bufferSize * numChannels * owner.numBuffers) * sizeof (T));
396             scratchBuffer.clear();
397             (*queue)->Clear (queue);
398         }
399 
enqueueBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner400         void enqueueBuffer()
401         {
402             (*queue)->Enqueue (queue, getCurrentBuffer(), static_cast<SLuint32> (getBufferSizeInSamples() * sizeof (T)));
403             ++numBlocksOut;
404         }
405 
isBufferAvailablejuce::OpenSLAudioIODevice::OpenSLQueueRunner406         bool isBufferAvailable() const         { return (numBlocksOut.get() < owner.numBuffers); }
getNextBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner407         T* getNextBuffer()                     { nextBlock.set((nextBlock.get() + 1) % owner.numBuffers); return getCurrentBuffer(); }
getCurrentBufferjuce::OpenSLAudioIODevice::OpenSLQueueRunner408         T* getCurrentBuffer()                  { return nativeBuffer.get() + (static_cast<size_t> (nextBlock.get()) * getBufferSizeInSamples()); }
getBufferSizeInSamplesjuce::OpenSLAudioIODevice::OpenSLQueueRunner409         size_t getBufferSizeInSamples() const  { return static_cast<size_t> (owner.bufferSize * numChannels); }
410 
finishedjuce::OpenSLAudioIODevice::OpenSLQueueRunner411         void finished (SLAndroidSimpleBufferQueueItf)
412         {
413             --numBlocksOut;
414             owner.doSomeWorkOnAudioThread();
415         }
416 
staticFinishedjuce::OpenSLAudioIODevice::OpenSLQueueRunner417         static void staticFinished (SLAndroidSimpleBufferQueueItf caller, void *pContext)
418         {
419             reinterpret_cast<OpenSLQueueRunner*> (pContext)->finished (caller);
420         }
421 
422         // get the "this" pointer for CRTP
crtpjuce::OpenSLAudioIODevice::OpenSLQueueRunner423         Child&       crtp()       { return * ((Child*) this); }
crtpjuce::OpenSLAudioIODevice::OpenSLQueueRunner424         const Child& crtp() const { return * ((Child*) this); }
425 
426         OpenSLSessionT<T>& owner;
427 
428         SlRef<RunnerObjectType> runner;
429         SlRef<SLAndroidSimpleBufferQueueItf_> queue;
430         SlRef<SLAndroidConfigurationItf_> config;
431         GlobalRef javaProxy;
432 
433         int numChannels;
434 
435         HeapBlock<T> nativeBuffer;
436         AudioBuffer<float> scratchBuffer, sampleBuffer;
437 
438         Atomic<int> nextBlock { 0 }, numBlocksOut { 0 };
439     };
440 
441     //==============================================================================
442     template <typename T>
443     struct OpenSLQueueRunnerPlayer      : OpenSLQueueRunner<T, OpenSLQueueRunnerPlayer<T>, SLPlayItf_>
444     {
445         using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerPlayer<T>, SLPlayItf_>;
446 
OpenSLQueueRunnerPlayerjuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer447         OpenSLQueueRunnerPlayer (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
448             : Base (sessionToUse, numChannelsToUse)
449         {}
450 
createPlayerOrRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer451         SlRef<SLPlayItf_> createPlayerOrRecorder()
452         {
453             SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
454             SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, Base::owner.outputMix };
455 
456             PCMDataFormatEx dataFormat;
457             BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
458 
459             SLDataSource source = { &queueLocator, &dataFormat };
460             SLDataSink   sink   = { &outputMix,    nullptr };
461 
462             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
463             SLboolean interfaceRequired[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE};
464 
465             SLObjectItf obj = nullptr;
466 
467             auto& holder = getEngineHolder();
468 
469             if (auto e = *holder.engine)
470             {
471                 auto status = e->CreateAudioPlayer (holder.engine, &obj, &source, &sink, 2,
472                                                     queueInterfaces, interfaceRequired);
473 
474                 if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize(obj, 0) != SL_RESULT_SUCCESS)
475                 {
476                     destroyObject (obj);
477                     return {};
478                 }
479             }
480 
481             return SlRef<SLPlayItf_>::cast (SlObjectRef (obj));
482         }
483 
setStatejuce::OpenSLAudioIODevice::OpenSLQueueRunnerPlayer484         void setState (bool running)    { (*Base::runner)->SetPlayState (Base::runner, running ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED); }
485     };
486 
487     template <typename T>
488     struct OpenSLQueueRunnerRecorder  : public OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>
489     {
490         using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>;
491 
OpenSLQueueRunnerRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder492         OpenSLQueueRunnerRecorder (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
493             : Base (sessionToUse, numChannelsToUse)
494         {}
495 
createPlayerOrRecorderjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder496         SlRef<SLRecordItf_> createPlayerOrRecorder()
497         {
498             SLDataLocator_IODevice ioDeviceLocator = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
499             SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
500 
501             PCMDataFormatEx dataFormat;
502             BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
503 
504             SLDataSource source = { &ioDeviceLocator, nullptr };
505             SLDataSink   sink   = { &queueLocator,    &dataFormat };
506 
507             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
508             SLboolean interfaceRequired[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };
509 
510             SLObjectItf obj = nullptr;
511 
512             auto& holder = getEngineHolder();
513 
514             if (auto e = *holder.engine)
515             {
516                 auto status = e->CreateAudioRecorder (holder.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired);
517 
518                 if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
519                 {
520                     destroyObject (obj);
521                     return {};
522                 }
523             }
524 
525             return SlRef<SLRecordItf_>::cast (SlObjectRef (obj));
526         }
527 
setAudioPreprocessingEnabledjuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder528         bool setAudioPreprocessingEnabled (bool shouldEnable)
529         {
530             if (Base::config != nullptr)
531             {
532                 const bool supportsUnprocessed = (getAndroidSDKVersion() >= 25);
533                 const SLuint32 recordingPresetValue
534                     = (shouldEnable ? SL_ANDROID_RECORDING_PRESET_GENERIC
535                                     : (supportsUnprocessed ? SL_ANDROID_RECORDING_PRESET_UNPROCESSED
536                                                            : SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION));
537 
538                 auto status = (*Base::config)->SetConfiguration (Base::config, SL_ANDROID_KEY_RECORDING_PRESET,
539                                                                  &recordingPresetValue, sizeof (recordingPresetValue));
540 
541                 return (status == SL_RESULT_SUCCESS);
542             }
543 
544             return false;
545         }
546 
setStatejuce::OpenSLAudioIODevice::OpenSLQueueRunnerRecorder547         void setState (bool running)    { (*Base::runner)->SetRecordState (Base::runner, running ? SL_RECORDSTATE_RECORDING
548                                                                                                  : SL_RECORDSTATE_STOPPED); }
549     };
550 
551     //==============================================================================
552     class OpenSLSession
553     {
554     public:
OpenSLSession(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)555         OpenSLSession (int numInputChannels, int numOutputChannels,
556                        double samleRateToUse, int bufferSizeToUse,
557                        int numBuffersToUse)
558             : inputChannels (numInputChannels), outputChannels (numOutputChannels),
559               sampleRate (samleRateToUse), bufferSize (bufferSizeToUse), numBuffers (numBuffersToUse)
560         {
561             jassert (numInputChannels > 0 || numOutputChannels > 0);
562 
563             if (outputChannels > 0)
564             {
565                 auto& holder = getEngineHolder();
566                 SLObjectItf obj = nullptr;
567 
568                 auto err = (*holder.engine)->CreateOutputMix (holder.engine, &obj, 0, nullptr, nullptr);
569 
570                 if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
571                      || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
572                 {
573                     destroyObject (obj);
574                     return;
575                 }
576 
577                 outputMix = SlRef<SLOutputMixItf_>::cast (SlObjectRef (obj));
578             }
579         }
580 
~OpenSLSession()581         virtual ~OpenSLSession() {}
582 
openedOK() const583         virtual bool openedOK() const    { return (outputChannels == 0 || outputMix != nullptr); }
start()584         virtual void start()             { stop(); jassert (callback.get() != nullptr); running = true; }
stop()585         virtual void stop()              { running = false; }
586 
587         virtual bool setAudioPreprocessingEnabled (bool shouldEnable) = 0;
588         virtual bool supportsFloatingPoint() const noexcept = 0;
589         virtual int getXRunCount() const noexcept = 0;
590 
setCallback(AudioIODeviceCallback * callbackToUse)591         void setCallback (AudioIODeviceCallback* callbackToUse)
592         {
593             if (! running)
594             {
595                 callback.set (callbackToUse);
596                 return;
597             }
598 
599             // don't set callback to null! stop the playback instead!
600             jassert (callbackToUse != nullptr);
601 
602             // spin-lock until we can set the callback
603             for (;;)
604             {
605                 auto old = callback.get();
606 
607                 if (old == callbackToUse)
608                     break;
609 
610                 if (callback.compareAndSetBool (callbackToUse, old))
611                     break;
612 
613                 Thread::sleep (1);
614             }
615         }
616 
process(const float ** inputChannelData,float ** outputChannelData)617         void process (const float** inputChannelData, float** outputChannelData)
618         {
619             if (auto* cb = callback.exchange (nullptr))
620             {
621                 cb->audioDeviceIOCallback (inputChannelData, inputChannels, outputChannelData, outputChannels, bufferSize);
622                 callback.set (cb);
623             }
624             else
625             {
626                 for (int i = 0; i < outputChannels; ++i)
627                     zeromem (outputChannelData[i], sizeof(float) * static_cast<size_t> (bufferSize));
628             }
629         }
630 
631         static OpenSLSession* create (int numInputChannels, int numOutputChannels,
632                                       double samleRateToUse, int bufferSizeToUse,
633                                       int numBuffersToUse);
634 
635         //==============================================================================
636         int inputChannels, outputChannels;
637         double sampleRate;
638         int bufferSize, numBuffers;
639         bool running = false, audioProcessingEnabled = true;
640 
641         SlRef<SLOutputMixItf_> outputMix;
642 
643         Atomic<AudioIODeviceCallback*> callback { nullptr };
644     };
645 
646     template <typename T>
647     class OpenSLSessionT : public OpenSLSession
648     {
649     public:
OpenSLSessionT(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)650         OpenSLSessionT (int numInputChannels, int numOutputChannels,
651                         double samleRateToUse, int bufferSizeToUse,
652                         int numBuffersToUse)
653             : OpenSLSession (numInputChannels, numOutputChannels,
654                              samleRateToUse, bufferSizeToUse, numBuffersToUse)
655         {
656             jassert (numInputChannels > 0 || numOutputChannels > 0);
657 
658             if (OpenSLSession::openedOK())
659             {
660                 if (inputChannels > 0)
661                 {
662                     recorder.reset (new OpenSLQueueRunnerRecorder<T> (*this, inputChannels));
663 
664                     if (! recorder->init())
665                     {
666                         recorder = nullptr;
667                         return;
668                     }
669                 }
670 
671                 if (outputChannels > 0)
672                 {
673                     player.reset (new OpenSLQueueRunnerPlayer<T> (*this, outputChannels));
674 
675                     if (! player->init())
676                     {
677                         player = nullptr;
678                         return;
679                     }
680 
681                     const bool supportsUnderrunCount = (getAndroidSDKVersion() >= 24);
682                     getUnderrunCount = supportsUnderrunCount ? getEnv()->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : nullptr;
683                 }
684             }
685         }
686 
openedOK() const687         bool openedOK() const override
688         {
689             return OpenSLSession::openedOK() && (inputChannels == 0  || recorder != nullptr)
690                                              && (outputChannels == 0 || player   != nullptr);
691         }
692 
start()693         void start() override
694         {
695             OpenSLSession::start();
696 
697             guard.set (0);
698 
699             if (inputChannels > 0)
700                 recorder->clear();
701 
702             if (outputChannels > 0)
703                 player->clear();
704 
705             // first enqueue all buffers
706             for (int i = 0; i < numBuffers; ++i)
707                 doSomeWorkOnAudioThread();
708 
709             if (inputChannels > 0)
710                 recorder->setState (true);
711 
712             if (outputChannels > 0)
713                 player->setState (true);
714         }
715 
stop()716         void stop() override
717         {
718             OpenSLSession::stop();
719 
720             while (! guard.compareAndSetBool (1, 0))
721                 Thread::sleep (1);
722 
723             if (inputChannels > 0)
724                 recorder->setState (false);
725 
726             if (outputChannels > 0)
727                 player->setState (false);
728 
729             guard.set (0);
730         }
731 
setAudioPreprocessingEnabled(bool shouldEnable)732         bool setAudioPreprocessingEnabled (bool shouldEnable) override
733         {
734             if (shouldEnable != audioProcessingEnabled)
735             {
736                 audioProcessingEnabled = shouldEnable;
737 
738                 if (recorder != nullptr)
739                     return recorder->setAudioPreprocessingEnabled (audioProcessingEnabled);
740             }
741 
742             return true;
743         }
744 
getXRunCount() const745         int getXRunCount() const noexcept override
746         {
747             if (player != nullptr && player->javaProxy != nullptr && getUnderrunCount != nullptr)
748                 return getEnv()->CallIntMethod (player->javaProxy, getUnderrunCount);
749 
750             return -1;
751         }
752 
supportsFloatingPoint() const753         bool supportsFloatingPoint() const noexcept override          { return (BufferHelpers<T>::isFloatingPoint != 0); }
754 
doSomeWorkOnAudioThread()755         void doSomeWorkOnAudioThread()
756         {
757             // only the player or the recorder should enter this section at any time
758             if (guard.compareAndSetBool (1, 0))
759             {
760                 // are there enough buffers available to process some audio
761                 if ((inputChannels == 0 || recorder->isBufferAvailable()) && (outputChannels == 0 || player->isBufferAvailable()))
762                 {
763                     T* recorderBuffer = (inputChannels  > 0 ? recorder->getNextBuffer() : nullptr);
764                     T* playerBuffer   = (outputChannels > 0 ? player->getNextBuffer()   : nullptr);
765 
766                     const float** inputChannelData = nullptr;
767                     float** outputChannelData = nullptr;
768 
769                     if (recorderBuffer != nullptr)
770                     {
771                         BufferHelpers<T>::prepareCallbackBuffer (recorder->sampleBuffer, recorderBuffer);
772                         BufferHelpers<T>::convertFromOpenSL (recorderBuffer, recorder->sampleBuffer);
773 
774                         inputChannelData = recorder->sampleBuffer.getArrayOfReadPointers();
775                     }
776 
777                     if (playerBuffer != nullptr)
778                     {
779                         BufferHelpers<T>::prepareCallbackBuffer (player->sampleBuffer, playerBuffer);
780                         outputChannelData = player->sampleBuffer.getArrayOfWritePointers();
781                     }
782 
783                     process (inputChannelData, outputChannelData);
784 
785                     if (recorderBuffer != nullptr)
786                         recorder->enqueueBuffer();
787 
788                     if (playerBuffer != nullptr)
789                     {
790                         BufferHelpers<T>::convertToOpenSL (player->sampleBuffer, playerBuffer);
791                         player->enqueueBuffer();
792                     }
793                 }
794 
795                 guard.set (0);
796             }
797         }
798 
799         //==============================================================================
800         std::unique_ptr<OpenSLQueueRunnerPlayer<T>> player;
801         std::unique_ptr<OpenSLQueueRunnerRecorder<T>> recorder;
802         Atomic<int> guard;
803         jmethodID getUnderrunCount = nullptr;
804     };
805 
806     //==============================================================================
OpenSLAudioIODevice(const String & deviceName)807     OpenSLAudioIODevice (const String& deviceName)  : AudioIODevice (deviceName, openSLTypeName)
808     {
809         // OpenSL has piss-poor support for determining latency, so the only way I can find to
810         // get a number for this is by asking the AudioTrack/AudioRecord classes..
811         AndroidAudioIODevice javaDevice (deviceName);
812 
813         // this is a total guess about how to calculate the latency, but seems to vaguely agree
814         // with the devices I've tested.. YMMV
815         inputLatency  = (javaDevice.minBufferSizeIn  * 2) / 3;
816         outputLatency = (javaDevice.minBufferSizeOut * 2) / 3;
817 
818         const int64 longestLatency = jmax (inputLatency, outputLatency);
819         const int64 totalLatency = inputLatency + outputLatency;
820         inputLatency  = (int) ((longestLatency * inputLatency)  / totalLatency) & ~15;
821         outputLatency = (int) ((longestLatency * outputLatency) / totalLatency) & ~15;
822 
823         // You can only create this class if you are sure that your hardware supports OpenSL
824         jassert (getEngineHolder().slLibrary.getNativeHandle() != nullptr);
825     }
826 
~OpenSLAudioIODevice()827     ~OpenSLAudioIODevice() override
828     {
829         close();
830     }
831 
openedOk() const832     bool openedOk() const       { return session != nullptr; }
833 
getOutputChannelNames()834     StringArray getOutputChannelNames() override
835     {
836         StringArray s;
837         s.add ("Left");
838         s.add ("Right");
839         return s;
840     }
841 
getInputChannelNames()842     StringArray getInputChannelNames() override
843     {
844         StringArray s;
845         s.add ("Audio Input");
846         return s;
847     }
848 
getAvailableSampleRates()849     Array<double> getAvailableSampleRates() override
850     {
851         // see https://developer.android.com/ndk/guides/audio/opensl-for-android.html
852 
853         static const double rates[] = { 8000.0, 11025.0, 12000.0, 16000.0,
854                                         22050.0, 24000.0, 32000.0, 44100.0, 48000.0 };
855         Array<double> retval (rates, numElementsInArray (rates));
856 
857         // make sure the native sample rate is part of the list
858         double native = 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         // we need to offer the lowest possible buffer size which
869         // is the native buffer size
870         auto nativeBufferSize  = getNativeBufferSize();
871         auto minBuffersToQueue = getMinimumBuffersToEnqueue();
872         auto maxBuffersToQueue = getMaximumBuffersToEnqueue();
873 
874         Array<int> retval;
875         for (int i = minBuffersToQueue; i <= maxBuffersToQueue; ++i)
876             retval.add (i * nativeBufferSize);
877 
878         return retval;
879     }
880 
open(const BigInteger & inputChannels,const BigInteger & outputChannels,double requestedSampleRate,int bufferSize)881     String open (const BigInteger& inputChannels,
882                  const BigInteger& outputChannels,
883                  double requestedSampleRate,
884                  int bufferSize) override
885     {
886         close();
887 
888         lastError.clear();
889 
890         sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : getNativeSampleRate());
891 
892         auto totalPreferredBufferSize    = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
893         auto nativeBufferSize            = getNativeBufferSize();
894         bool useHighPerformanceAudioPath = canUseHighPerformanceAudioPath (totalPreferredBufferSize, sampleRate);
895 
896         audioBuffersToEnqueue = useHighPerformanceAudioPath ? (totalPreferredBufferSize / nativeBufferSize) : 1;
897         actualBufferSize = totalPreferredBufferSize / audioBuffersToEnqueue;
898         jassert ((actualBufferSize * audioBuffersToEnqueue) == totalPreferredBufferSize);
899 
900         activeOutputChans = outputChannels;
901         activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
902         auto numOutputChannels = activeOutputChans.countNumberOfSetBits();
903 
904         activeInputChans = inputChannels;
905         activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
906         auto numInputChannels = activeInputChans.countNumberOfSetBits();
907 
908         if (numInputChannels > 0 && (! RuntimePermissions::isGranted (RuntimePermissions::recordAudio)))
909         {
910             // If you hit this assert, you probably forgot to get RuntimePermissions::recordAudio
911             // before trying to open an audio input device. This is not going to work!
912             jassertfalse;
913             lastError = "Error opening OpenSL input device: the app was not granted android.permission.RECORD_AUDIO";
914         }
915 
916         session.reset (OpenSLSession::create (numInputChannels, numOutputChannels,
917                                               sampleRate, actualBufferSize, audioBuffersToEnqueue));
918         if (session != nullptr)
919         {
920             session->setAudioPreprocessingEnabled (audioProcessingEnabled);
921         }
922         else
923         {
924             if (numInputChannels > 0 && numOutputChannels > 0 && RuntimePermissions::isGranted (RuntimePermissions::recordAudio))
925             {
926                 // New versions of the Android emulator do not seem to support audio input anymore on OS X
927                 activeInputChans = BigInteger(0);
928                 numInputChannels = 0;
929 
930                 session.reset (OpenSLSession::create (numInputChannels, numOutputChannels,
931                                                       sampleRate, actualBufferSize, audioBuffersToEnqueue));
932             }
933         }
934 
935         DBG ("OpenSL: numInputChannels = " << numInputChannels
936              << ", numOutputChannels = " << numOutputChannels
937              << ", nativeBufferSize = " << getNativeBufferSize()
938              << ", nativeSampleRate = " << getNativeSampleRate()
939              << ", actualBufferSize = " << actualBufferSize
940              << ", audioBuffersToEnqueue = " << audioBuffersToEnqueue
941              << ", sampleRate = " << sampleRate
942              << ", supportsFloatingPoint = " << (session != nullptr && session->supportsFloatingPoint() ? "true" : "false"));
943 
944         if (session == nullptr)
945             lastError = "Unknown error initializing opensl session";
946 
947         deviceOpen = (session != nullptr);
948         return lastError;
949     }
950 
close()951     void close() override
952     {
953         stop();
954         session = nullptr;
955         callback = nullptr;
956     }
957 
getOutputLatencyInSamples()958     int getOutputLatencyInSamples() override            { return outputLatency; }
getInputLatencyInSamples()959     int getInputLatencyInSamples() override             { return inputLatency; }
isOpen()960     bool isOpen() override                              { return deviceOpen; }
getCurrentBufferSizeSamples()961     int getCurrentBufferSizeSamples() override          { return actualBufferSize * audioBuffersToEnqueue; }
getCurrentBitDepth()962     int getCurrentBitDepth() override                   { return (session != nullptr && session->supportsFloatingPoint() ? 32 : 16); }
getActiveOutputChannels() const963     BigInteger getActiveOutputChannels() const override { return activeOutputChans; }
getActiveInputChannels() const964     BigInteger getActiveInputChannels() const override  { return activeInputChans; }
getLastError()965     String getLastError() override                      { return lastError; }
isPlaying()966     bool isPlaying() override                           { return callback != nullptr; }
getXRunCount() const967     int getXRunCount() const noexcept override          { return (session != nullptr ? session->getXRunCount() : -1); }
968 
getDefaultBufferSize()969     int getDefaultBufferSize() override
970     {
971         auto defaultBufferLength = (hasLowLatencyAudioPath() ? defaultBufferSizeForLowLatencyDeviceMs
972                                                              : defaultBufferSizeForStandardLatencyDeviceMs);
973 
974         auto defaultBuffersToEnqueue = buffersToQueueForBufferDuration (defaultBufferLength, getCurrentSampleRate());
975         return defaultBuffersToEnqueue * getNativeBufferSize();
976     }
977 
getCurrentSampleRate()978     double getCurrentSampleRate() override
979     {
980         return (sampleRate == 0.0 ? getNativeSampleRate() : sampleRate);
981     }
982 
start(AudioIODeviceCallback * newCallback)983     void start (AudioIODeviceCallback* newCallback) override
984     {
985         if (session != nullptr && callback != newCallback)
986         {
987             auto oldCallback = callback;
988 
989             if (newCallback != nullptr)
990                 newCallback->audioDeviceAboutToStart (this);
991 
992             if (oldCallback != nullptr)
993             {
994                 // already running
995                 if (newCallback == nullptr)
996                     stop();
997                 else
998                     session->setCallback (newCallback);
999 
1000                 oldCallback->audioDeviceStopped();
1001             }
1002             else
1003             {
1004                 jassert (newCallback != nullptr);
1005 
1006                 // session hasn't started yet
1007                 session->setCallback (newCallback);
1008                 session->start();
1009             }
1010 
1011             callback = newCallback;
1012         }
1013     }
1014 
stop()1015     void stop() override
1016     {
1017         if (session != nullptr && callback != nullptr)
1018         {
1019             callback = nullptr;
1020             session->stop();
1021             session->setCallback (nullptr);
1022         }
1023     }
1024 
setAudioPreprocessingEnabled(bool shouldAudioProcessingBeEnabled)1025     bool setAudioPreprocessingEnabled (bool shouldAudioProcessingBeEnabled) override
1026     {
1027         audioProcessingEnabled = shouldAudioProcessingBeEnabled;
1028 
1029         if (session != nullptr)
1030             session->setAudioPreprocessingEnabled (audioProcessingEnabled);
1031 
1032         return true;
1033     }
1034 
1035     static const char* const openSLTypeName;
1036 
1037 private:
1038     //==============================================================================
1039     friend class SLRealtimeThread;
1040 
1041     //==============================================================================
1042     int actualBufferSize = 0, sampleRate = 0, audioBuffersToEnqueue = 0;
1043     int inputLatency, outputLatency;
1044     bool deviceOpen = false, audioProcessingEnabled = true;
1045     String lastError;
1046     BigInteger activeOutputChans, activeInputChans;
1047     AudioIODeviceCallback* callback = nullptr;
1048 
1049     std::unique_ptr<OpenSLSession> session;
1050 
1051     enum
1052     {
1053         defaultBufferSizeForLowLatencyDeviceMs = 40,
1054         defaultBufferSizeForStandardLatencyDeviceMs = 100
1055     };
1056 
getMinimumBuffersToEnqueue(double sampleRateToCheck=getNativeSampleRate ())1057     static int getMinimumBuffersToEnqueue (double sampleRateToCheck = getNativeSampleRate())
1058     {
1059         if (canUseHighPerformanceAudioPath (getNativeBufferSize(), (int) sampleRateToCheck))
1060         {
1061             // see https://developer.android.com/ndk/guides/audio/opensl/opensl-prog-notes.html#sandp
1062             // "For Android 4.2 (API level 17) and earlier, a buffer count of two or more is required
1063             //  for lower latency. Beginning with Android 4.3 (API level 18), a buffer count of one
1064             //  is sufficient for lower latency."
1065             return (getAndroidSDKVersion() >= 18 ? 1 : 2);
1066         }
1067 
1068         // we will not use the low-latency path so we can use the absolute minimum number of buffers
1069         // to queue
1070         return 1;
1071     }
1072 
getMaximumBuffersToEnqueue()1073     int getMaximumBuffersToEnqueue() noexcept
1074     {
1075         constexpr auto maxBufferSizeMs = 200;
1076 
1077         auto availableSampleRates = getAvailableSampleRates();
1078         auto maximumSampleRate = findMaximum(availableSampleRates.getRawDataPointer(), availableSampleRates.size());
1079 
1080         // ensure we don't return something crazy small
1081         return jmax (8, buffersToQueueForBufferDuration (maxBufferSizeMs, maximumSampleRate));
1082     }
1083 
buffersToQueueForBufferDuration(int bufferDurationInMs,double sampleRate)1084     static int buffersToQueueForBufferDuration (int bufferDurationInMs, double sampleRate) noexcept
1085     {
1086         auto maxBufferFrames = static_cast<int> (std::ceil (bufferDurationInMs * sampleRate / 1000.0));
1087         auto maxNumBuffers   = static_cast<int> (std::ceil (static_cast<double> (maxBufferFrames)
1088                                                   / static_cast<double> (getNativeBufferSize())));
1089 
1090         return jmax (getMinimumBuffersToEnqueue (sampleRate), maxNumBuffers);
1091     }
1092 
1093     //==============================================================================
getNativeSampleRate()1094     static double getNativeSampleRate()
1095     {
1096         return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue();
1097     }
1098 
getNativeBufferSize()1099     static int getNativeBufferSize()
1100     {
1101         const int val = audioManagerGetProperty ("android.media.property.OUTPUT_FRAMES_PER_BUFFER").getIntValue();
1102         return val > 0 ? val : 512;
1103     }
1104 
isProAudioDevice()1105     static bool isProAudioDevice()
1106     {
1107         return androidHasSystemFeature ("android.hardware.audio.pro") || isSapaSupported();
1108     }
1109 
hasLowLatencyAudioPath()1110     static bool hasLowLatencyAudioPath()
1111     {
1112         return androidHasSystemFeature ("android.hardware.audio.low_latency");
1113     }
1114 
canUseHighPerformanceAudioPath(int requestedBufferSize,int requestedSampleRate)1115     static bool canUseHighPerformanceAudioPath (int requestedBufferSize, int requestedSampleRate)
1116     {
1117         return ((requestedBufferSize % getNativeBufferSize()) == 0)
1118              && (requestedSampleRate == getNativeSampleRate())
1119              && isProAudioDevice();
1120     }
1121 
1122     //==============================================================================
1123     // Some minimum Sapa support to check if this device supports pro audio
isSamsungDevice()1124     static bool isSamsungDevice()
1125     {
1126         return SystemStats::getDeviceManufacturer().containsIgnoreCase ("SAMSUNG");
1127     }
1128 
isSapaSupported()1129     static bool isSapaSupported()
1130     {
1131         static bool supported = isSamsungDevice() && DynamicLibrary().open ("libapa_jni.so");
1132 
1133         return supported;
1134     }
1135 
1136     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioIODevice)
1137 };
1138 
create(int numInputChannels,int numOutputChannels,double samleRateToUse,int bufferSizeToUse,int numBuffersToUse)1139 OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create (int numInputChannels, int numOutputChannels,
1140                                                                                 double samleRateToUse, int bufferSizeToUse,
1141                                                                                 int numBuffersToUse)
1142 {
1143     std::unique_ptr<OpenSLSession> retval;
1144     auto sdkVersion = getAndroidSDKVersion();
1145 
1146     // SDK versions 21 and higher should natively support floating point...
1147     if (sdkVersion >= 21)
1148     {
1149         retval.reset (new OpenSLSessionT<float> (numInputChannels, numOutputChannels, samleRateToUse,
1150                                                  bufferSizeToUse, numBuffersToUse));
1151 
1152         // ...however, some devices lie so re-try without floating point
1153         if (retval != nullptr && (! retval->openedOK()))
1154             retval = nullptr;
1155     }
1156 
1157     if (retval == nullptr)
1158     {
1159         retval.reset (new OpenSLSessionT<int16> (numInputChannels, numOutputChannels, samleRateToUse,
1160                                                  bufferSizeToUse, numBuffersToUse));
1161 
1162         if (retval != nullptr && (! retval->openedOK()))
1163             retval = nullptr;
1164     }
1165 
1166     return retval.release();
1167 }
1168 
1169 //==============================================================================
1170 class OpenSLAudioDeviceType  : public AudioIODeviceType
1171 {
1172 public:
OpenSLAudioDeviceType()1173     OpenSLAudioDeviceType()  : AudioIODeviceType (OpenSLAudioIODevice::openSLTypeName) {}
1174 
1175     //==============================================================================
scanForDevices()1176     void scanForDevices() override {}
1177 
getDeviceNames(bool) const1178     StringArray getDeviceNames (bool) const override                             { return StringArray (OpenSLAudioIODevice::openSLTypeName); }
getDefaultDeviceIndex(bool) const1179     int getDefaultDeviceIndex (bool) const override                              { return 0; }
getIndexOfDevice(AudioIODevice * device,bool) const1180     int getIndexOfDevice (AudioIODevice* device, bool) const override            { return device != nullptr ? 0 : -1; }
hasSeparateInputsAndOutputs() const1181     bool hasSeparateInputsAndOutputs() const override                            { return false; }
1182 
createDevice(const String & outputDeviceName,const String & inputDeviceName)1183     AudioIODevice* createDevice (const String& outputDeviceName,
1184                                  const String& inputDeviceName) override
1185     {
1186         std::unique_ptr<OpenSLAudioIODevice> dev;
1187 
1188         if (outputDeviceName.isNotEmpty() || inputDeviceName.isNotEmpty())
1189             dev.reset (new OpenSLAudioIODevice (outputDeviceName.isNotEmpty() ? outputDeviceName
1190                                                                               : inputDeviceName));
1191 
1192         return dev.release();
1193     }
1194 
isOpenSLAvailable()1195     static bool isOpenSLAvailable()
1196     {
1197         DynamicLibrary library;
1198         return library.open ("libOpenSLES.so");
1199     }
1200 
1201     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenSLAudioDeviceType)
1202 };
1203 
1204 const char* const OpenSLAudioIODevice::openSLTypeName = "Android OpenSL";
1205 
1206 
1207 //==============================================================================
isOpenSLAvailable()1208 bool isOpenSLAvailable()  { return OpenSLAudioDeviceType::isOpenSLAvailable(); }
1209 
createAudioIODeviceType_OpenSLES()1210 AudioIODeviceType* AudioIODeviceType::createAudioIODeviceType_OpenSLES()
1211 {
1212     return isOpenSLAvailable() ? new OpenSLAudioDeviceType() : nullptr;
1213 }
1214 
1215 //==============================================================================
1216 class SLRealtimeThread
1217 {
1218 public:
1219     static constexpr int numBuffers = 4;
1220 
SLRealtimeThread()1221     SLRealtimeThread()
1222     {
1223         if (auto createEngine = (CreateEngineFunc) slLibrary.getFunction ("slCreateEngine"))
1224         {
1225             SLObjectItf obj = nullptr;
1226             auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
1227 
1228             if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr)
1229                 return;
1230 
1231             if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1232             {
1233                 destroyObject (obj);
1234                 return;
1235             }
1236 
1237             engine = SlRef<SLEngineItf_>::cast (SlObjectRef (obj));
1238 
1239             if (engine == nullptr)
1240             {
1241                 destroyObject (obj);
1242                 return;
1243             }
1244 
1245             obj = nullptr;
1246             err = (*engine)->CreateOutputMix (engine, &obj, 0, nullptr, nullptr);
1247 
1248             if (err != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1249             {
1250                 destroyObject (obj);
1251                 return;
1252             }
1253 
1254             outputMix = SlRef<SLOutputMixItf_>::cast (SlObjectRef (obj));
1255 
1256             if (outputMix == nullptr)
1257             {
1258                 destroyObject (obj);
1259                 return;
1260             }
1261 
1262             SLDataLocator_AndroidSimpleBufferQueue queueLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (numBuffers)};
1263             SLDataLocator_OutputMix outputMixLocator = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
1264 
1265             PCMDataFormatEx dataFormat;
1266             BufferHelpers<int16>::initPCMDataFormat (dataFormat, 1, OpenSLAudioIODevice::getNativeSampleRate());
1267 
1268             SLDataSource source = { &queueLocator, &dataFormat };
1269             SLDataSink   sink   = { &outputMixLocator, nullptr };
1270 
1271             SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid };
1272             SLboolean trueFlag = SL_BOOLEAN_TRUE;
1273 
1274             obj = nullptr;
1275             err = (*engine)->CreateAudioPlayer (engine, &obj, &source, &sink, 1, queueInterfaces, &trueFlag);
1276 
1277             if (err != SL_RESULT_SUCCESS || obj == nullptr)
1278                 return;
1279 
1280             if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
1281             {
1282                 destroyObject (obj);
1283                 return;
1284             }
1285 
1286             player = SlRef<SLPlayItf_>::cast (SlObjectRef (obj));
1287 
1288             if (player == nullptr)
1289             {
1290                 destroyObject (obj);
1291                 return;
1292             }
1293 
1294             queue = SlRef<SLAndroidSimpleBufferQueueItf_>::cast (player);
1295             if (queue == nullptr)
1296                 return;
1297 
1298             if ((*queue)->RegisterCallback (queue, staticFinished, this) != SL_RESULT_SUCCESS)
1299             {
1300                 queue = nullptr;
1301                 return;
1302             }
1303 
1304             pthread_cond_init (&threadReady, nullptr);
1305             pthread_mutex_init (&threadReadyMutex, nullptr);
1306         }
1307     }
1308 
isOK() const1309     bool isOK() const      { return queue != nullptr; }
1310 
startThread(void * (* entry)(void *),void * userPtr)1311     pthread_t startThread (void* (*entry) (void*), void* userPtr)
1312     {
1313         memset (buffer.get(), 0, static_cast<size_t> (sizeof (int16) * static_cast<size_t> (bufferSize * numBuffers)));
1314 
1315         for (int i = 0; i < numBuffers; ++i)
1316         {
1317             int16* dst = buffer.get() + (bufferSize * i);
1318             (*queue)->Enqueue (queue, dst, static_cast<SLuint32> (static_cast<size_t> (bufferSize) * sizeof (int16)));
1319         }
1320 
1321         pthread_mutex_lock (&threadReadyMutex);
1322 
1323         threadEntryProc = entry;
1324         threadUserPtr  = userPtr;
1325 
1326         (*player)->SetPlayState (player, SL_PLAYSTATE_PLAYING);
1327 
1328         pthread_cond_wait (&threadReady, &threadReadyMutex);
1329         pthread_mutex_unlock (&threadReadyMutex);
1330 
1331         return threadID;
1332     }
1333 
finished()1334     void finished()
1335     {
1336         if (threadEntryProc != nullptr)
1337         {
1338             pthread_mutex_lock (&threadReadyMutex);
1339 
1340             threadID = pthread_self();
1341 
1342             pthread_cond_signal (&threadReady);
1343             pthread_mutex_unlock (&threadReadyMutex);
1344 
1345             threadEntryProc (threadUserPtr);
1346             threadEntryProc = nullptr;
1347 
1348             (*player)->SetPlayState (player, SL_PLAYSTATE_STOPPED);
1349             MessageManager::callAsync ([this] () { delete this; });
1350         }
1351     }
1352 
1353 private:
1354     //==============================================================================
staticFinished(SLAndroidSimpleBufferQueueItf,void * context)1355     static void staticFinished (SLAndroidSimpleBufferQueueItf, void* context)
1356     {
1357         static_cast<SLRealtimeThread*> (context)->finished();
1358     }
1359 
1360     //==============================================================================
1361     DynamicLibrary slLibrary { "libOpenSLES.so" };
1362 
1363     SlRef<SLEngineItf_>    engine;
1364     SlRef<SLOutputMixItf_> outputMix;
1365     SlRef<SLPlayItf_>      player;
1366     SlRef<SLAndroidSimpleBufferQueueItf_> queue;
1367 
1368     int bufferSize = OpenSLAudioIODevice::getNativeBufferSize();
1369     HeapBlock<int16> buffer { HeapBlock<int16> (static_cast<size_t> (1 * bufferSize * numBuffers)) };
1370 
1371     void* (*threadEntryProc) (void*) = nullptr;
1372     void* threadUserPtr              = nullptr;
1373 
1374     pthread_cond_t  threadReady;
1375     pthread_mutex_t threadReadyMutex;
1376     pthread_t       threadID;
1377 };
1378 
juce_createRealtimeAudioThread(void * (* entry)(void *),void * userPtr)1379 pthread_t juce_createRealtimeAudioThread (void* (*entry) (void*), void* userPtr)
1380 {
1381     std::unique_ptr<SLRealtimeThread> thread (new SLRealtimeThread);
1382 
1383     if (! thread->isOK())
1384         return 0;
1385 
1386     pthread_t threadID = thread->startThread (entry, userPtr);
1387 
1388     // the thread will de-allocate itself
1389     thread.release();
1390 
1391     return threadID;
1392 }
1393 
1394 } // namespace juce
1395