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