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