upgrade to JUCE 5.4.3. Remove (probably) unused JUCE modules. Remove VST2 target (it's been end-of-life'd by Steinberg and by JUCE)
This commit is contained in:
@ -23,6 +23,10 @@
|
||||
namespace juce
|
||||
{
|
||||
|
||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
|
||||
DECLARE_JNI_CLASS (AndroidAudioManager, "android/media/AudioManager")
|
||||
#undef JNI_CLASS_MEMBERS
|
||||
|
||||
//==============================================================================
|
||||
#ifndef SL_ANDROID_DATAFORMAT_PCM_EX
|
||||
#define SL_ANDROID_DATAFORMAT_PCM_EX ((SLuint32) 0x00000004)
|
||||
@ -60,6 +64,22 @@ SLInterfaceID_ IntfIID<SLRecordItf_>::iid = { 0xc5657aa0, 0xdd
|
||||
SLInterfaceID_ IntfIID<SLAndroidSimpleBufferQueueItf_>::iid = { 0x198e4940, 0xc5d7, 0x11df, 0xa2a6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
|
||||
SLInterfaceID_ IntfIID<SLAndroidConfigurationItf_>::iid = { 0x89f6a7e0, 0xbeac, 0x11df, 0x8b5c, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b} };
|
||||
|
||||
template <typename SLObjectType>
|
||||
static void destroyObject (SLObjectType object)
|
||||
{
|
||||
if (object != nullptr && *object != nullptr)
|
||||
(*object)->Destroy (object);
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ContainerDeletePolicy<const SLObjectItf_* const>
|
||||
{
|
||||
static void destroy (SLObjectItf object)
|
||||
{
|
||||
destroyObject (object);
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Some life-time and type management of OpenSL objects
|
||||
class SlObjectRef
|
||||
@ -67,27 +87,34 @@ class SlObjectRef
|
||||
public:
|
||||
//==============================================================================
|
||||
SlObjectRef() noexcept {}
|
||||
SlObjectRef (const SlObjectRef& obj) noexcept : cb (obj.cb) {}
|
||||
SlObjectRef (SlObjectRef&& obj) noexcept : cb (static_cast<ReferenceCountedObjectPtr<ControlBlock>&&> (obj.cb)) { obj.cb = nullptr; }
|
||||
SlObjectRef (const SlObjectRef& obj) noexcept : cb (obj.cb) {}
|
||||
SlObjectRef (SlObjectRef&& obj) noexcept : cb (std::move (obj.cb)) { obj.cb = nullptr; }
|
||||
explicit SlObjectRef (SLObjectItf o) : cb (new ControlBlock (o)) {}
|
||||
|
||||
//==============================================================================
|
||||
SlObjectRef& operator=(const SlObjectRef& r) noexcept { cb = r.cb; return *this; }
|
||||
SlObjectRef& operator=(SlObjectRef&& r) noexcept { cb = static_cast<ReferenceCountedObjectPtr<ControlBlock>&&> (r.cb); r.cb = nullptr; return *this; }
|
||||
SlObjectRef& operator=(std::nullptr_t) noexcept { cb = nullptr; return *this; }
|
||||
SlObjectRef& operator= (const SlObjectRef& r) noexcept { cb = r.cb; return *this; }
|
||||
SlObjectRef& operator= (SlObjectRef&& r) noexcept { cb = std::move (r.cb); r.cb = nullptr; return *this; }
|
||||
SlObjectRef& operator= (std::nullptr_t) noexcept { cb = nullptr; return *this; }
|
||||
|
||||
//==============================================================================
|
||||
const SLObjectItf_* const operator*() noexcept { return *cb->ptr.get(); }
|
||||
SLObjectItf operator->() noexcept { return (cb == nullptr ? nullptr : cb->ptr.get()); }
|
||||
operator SLObjectItf() noexcept { return (cb == nullptr ? nullptr : cb->ptr.get()); }
|
||||
const SLObjectItf_* operator*() noexcept { return *cb->ptr.get(); }
|
||||
SLObjectItf operator->() noexcept { return (cb == nullptr ? nullptr : cb->ptr.get()); }
|
||||
operator SLObjectItf() noexcept { return (cb == nullptr ? nullptr : cb->ptr.get()); }
|
||||
|
||||
//==============================================================================
|
||||
bool operator== (nullptr_t) const noexcept { return (cb == nullptr || cb->ptr == nullptr); }
|
||||
bool operator!= (nullptr_t) const noexcept { return (cb != nullptr && cb->ptr != nullptr); }
|
||||
bool operator== (nullptr_t) const noexcept { return (cb == nullptr || cb->ptr == nullptr); }
|
||||
bool operator!= (nullptr_t) const noexcept { return (cb != nullptr && cb->ptr != nullptr); }
|
||||
|
||||
private:
|
||||
|
||||
//==============================================================================
|
||||
struct ControlBlock : ReferenceCountedObject { std::unique_ptr<const SLObjectItf_* const> ptr; ControlBlock() {} ControlBlock (SLObjectItf o) : ptr (o) {} };
|
||||
struct ControlBlock : ReferenceCountedObject
|
||||
{
|
||||
ControlBlock() = default;
|
||||
ControlBlock (SLObjectItf o) : ptr (o) {}
|
||||
|
||||
std::unique_ptr<const SLObjectItf_* const> ptr;
|
||||
};
|
||||
|
||||
ReferenceCountedObjectPtr<ControlBlock> cb;
|
||||
};
|
||||
|
||||
@ -96,53 +123,53 @@ class SlRef : public SlObjectRef
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
SlRef() noexcept : type (nullptr) {}
|
||||
SlRef (SlRef& r) noexcept : SlObjectRef (r), type (r.type) {}
|
||||
SlRef (SlRef&& r) noexcept : SlObjectRef (static_cast<SlRef&&> (r)), type (r.type) { r.type = nullptr; }
|
||||
SlRef() noexcept {}
|
||||
SlRef (const SlRef& r) noexcept : SlObjectRef (r), type (r.type) {}
|
||||
SlRef (SlRef&& r) noexcept : SlObjectRef (std::move (r)), type (r.type) { r.type = nullptr; }
|
||||
|
||||
//==============================================================================
|
||||
SlRef& operator= (const SlRef& r) noexcept { SlObjectRef::operator= (r); type = r.type; return *this; }
|
||||
SlRef& operator= (SlRef&& r) noexcept { SlObjectRef::operator= (static_cast<SlObjectRef&&> (r)); type = r.type; r.type = nullptr; return *this; }
|
||||
SlRef& operator= (std::nullptr_t) noexcept { SlObjectRef::operator= (nullptr); type = nullptr; return *this; }
|
||||
SlRef& operator= (SlRef&& r) noexcept { SlObjectRef::operator= (std::move (r)); type = r.type; r.type = nullptr; return *this; }
|
||||
SlRef& operator= (std::nullptr_t) noexcept { SlObjectRef::operator= (nullptr); type = nullptr; return *this; }
|
||||
|
||||
//==============================================================================
|
||||
T* const operator*() noexcept { return *type; }
|
||||
T* const * operator->() noexcept { return type; }
|
||||
operator T* const *() noexcept { return type; }
|
||||
T* const operator*() noexcept { return *type; }
|
||||
T* const* operator->() noexcept { return type; }
|
||||
operator T* const*() noexcept { return type; }
|
||||
|
||||
//==============================================================================
|
||||
static SlRef cast (SlObjectRef& base) { return SlRef (base); }
|
||||
static SlRef cast (SlObjectRef&& base) { return SlRef (static_cast<SlObjectRef&&> (base)); }
|
||||
static SlRef cast (SlObjectRef& base) { return SlRef (base); }
|
||||
static SlRef cast (SlObjectRef&& base) { return SlRef (std::move (base)); }
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
SlRef (SlObjectRef& base) : SlObjectRef (base)
|
||||
{
|
||||
SLObjectItf obj = SlObjectRef::operator->();
|
||||
SLresult err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
|
||||
if (type == nullptr || err != SL_RESULT_SUCCESS)
|
||||
*this = nullptr;
|
||||
if (auto obj = SlObjectRef::operator->())
|
||||
{
|
||||
auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
|
||||
|
||||
if (type != nullptr && err == SL_RESULT_SUCCESS)
|
||||
return;
|
||||
}
|
||||
|
||||
*this = nullptr;
|
||||
}
|
||||
|
||||
SlRef (SlObjectRef&& base) : SlObjectRef (static_cast<SlObjectRef&&> (base))
|
||||
SlRef (SlObjectRef&& base) : SlObjectRef (std::move (base))
|
||||
{
|
||||
SLObjectItf obj = SlObjectRef::operator->();
|
||||
SLresult err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
|
||||
base = nullptr;
|
||||
if (auto obj = SlObjectRef::operator->())
|
||||
{
|
||||
auto err = (*obj)->GetInterface (obj, &IntfIID<T>::iid, &type);
|
||||
base = nullptr;
|
||||
|
||||
if (type == nullptr || err != SL_RESULT_SUCCESS)
|
||||
*this = nullptr;
|
||||
}
|
||||
T* const * type;
|
||||
};
|
||||
if (type != nullptr && err == SL_RESULT_SUCCESS)
|
||||
return;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct ContainerDeletePolicy<const SLObjectItf_* const>
|
||||
{
|
||||
static void destroy (SLObjectItf object)
|
||||
{
|
||||
if (object != nullptr)
|
||||
(*object)->Destroy (object);
|
||||
*this = nullptr;
|
||||
}
|
||||
|
||||
T* const* type = nullptr;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
@ -281,8 +308,7 @@ public:
|
||||
numChannels (numChannelsToUse),
|
||||
nativeBuffer (static_cast<size_t> (numChannels * owner.bufferSize * owner.numBuffers)),
|
||||
scratchBuffer (numChannelsToUse, owner.bufferSize),
|
||||
sampleBuffer (scratchBuffer.getArrayOfWritePointers(), numChannelsToUse, owner.bufferSize),
|
||||
nextBlock (0), numBlocksOut (0)
|
||||
sampleBuffer (scratchBuffer.getArrayOfWritePointers(), numChannelsToUse, owner.bufferSize)
|
||||
{}
|
||||
|
||||
~OpenSLQueueRunner()
|
||||
@ -297,10 +323,11 @@ public:
|
||||
bool init()
|
||||
{
|
||||
runner = crtp().createPlayerOrRecorder();
|
||||
|
||||
if (runner == nullptr)
|
||||
return false;
|
||||
|
||||
const bool supportsJavaProxy = (getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT) >= 24);
|
||||
const bool supportsJavaProxy = (getAndroidSDKVersion() >= 24);
|
||||
|
||||
if (supportsJavaProxy)
|
||||
{
|
||||
@ -314,18 +341,18 @@ public:
|
||||
&audioRoutingJni);
|
||||
|
||||
if (status == SL_RESULT_SUCCESS && audioRoutingJni != 0)
|
||||
javaProxy = GlobalRef (audioRoutingJni);
|
||||
javaProxy = GlobalRef (LocalRef<jobject>(getEnv()->NewLocalRef (audioRoutingJni)));
|
||||
}
|
||||
}
|
||||
|
||||
queue = SlRef<SLAndroidSimpleBufferQueueItf_>::cast (runner);
|
||||
|
||||
if (queue == nullptr)
|
||||
return false;
|
||||
|
||||
return ((*queue)->RegisterCallback (queue, staticFinished, this) == SL_RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
void clear()
|
||||
{
|
||||
nextBlock.set (0);
|
||||
@ -349,8 +376,6 @@ public:
|
||||
|
||||
void finished (SLAndroidSimpleBufferQueueItf)
|
||||
{
|
||||
attachAndroidJNI();
|
||||
|
||||
--numBlocksOut;
|
||||
owner.doSomeWorkOnAudioThread();
|
||||
}
|
||||
@ -376,7 +401,7 @@ public:
|
||||
HeapBlock<T> nativeBuffer;
|
||||
AudioBuffer<float> scratchBuffer, sampleBuffer;
|
||||
|
||||
Atomic<int> nextBlock, numBlocksOut;
|
||||
Atomic<int> nextBlock { 0 }, numBlocksOut { 0 };
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
@ -385,35 +410,36 @@ public:
|
||||
{
|
||||
using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerPlayer<T>, SLPlayItf_>;
|
||||
|
||||
enum { isPlayer = 1 };
|
||||
|
||||
OpenSLQueueRunnerPlayer (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
|
||||
: Base (sessionToUse, numChannelsToUse)
|
||||
{}
|
||||
|
||||
SlRef<SLPlayItf_> createPlayerOrRecorder()
|
||||
{
|
||||
SLDataLocator_AndroidSimpleBufferQueue queueLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers)};
|
||||
SLDataLocator_OutputMix outputMix = {SL_DATALOCATOR_OUTPUTMIX, Base::owner.outputMix};
|
||||
SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
|
||||
SLDataLocator_OutputMix outputMix = { SL_DATALOCATOR_OUTPUTMIX, Base::owner.outputMix };
|
||||
|
||||
PCMDataFormatEx dataFormat;
|
||||
BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
|
||||
|
||||
SLDataSource source = {&queueLocator, &dataFormat};
|
||||
SLDataSink sink = {&outputMix, nullptr};
|
||||
SLDataSource source = { &queueLocator, &dataFormat };
|
||||
SLDataSink sink = { &outputMix, nullptr };
|
||||
|
||||
SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
|
||||
SLboolean interfaceRequired[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE};
|
||||
|
||||
SLObjectItf obj = nullptr;
|
||||
|
||||
SLresult status = (*Base::owner.engine)->CreateAudioPlayer (Base::owner.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired);
|
||||
if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
if (auto e = *Base::owner.engine)
|
||||
{
|
||||
if (obj != nullptr)
|
||||
(*obj)->Destroy (obj);
|
||||
auto status = e->CreateAudioPlayer (Base::owner.engine, &obj, &source, &sink, 2,
|
||||
queueInterfaces, interfaceRequired);
|
||||
|
||||
return SlRef<SLPlayItf_>();
|
||||
if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize(obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
destroyObject (obj);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return SlRef<SLPlayItf_>::cast (SlObjectRef (obj));
|
||||
@ -423,58 +449,56 @@ public:
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct OpenSLQueueRunnerRecorder : OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>
|
||||
struct OpenSLQueueRunnerRecorder : public OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>
|
||||
{
|
||||
using Base = OpenSLQueueRunner<T, OpenSLQueueRunnerRecorder<T>, SLRecordItf_>;
|
||||
|
||||
enum { isPlayer = 0 };
|
||||
|
||||
OpenSLQueueRunnerRecorder (OpenSLSessionT<T>& sessionToUse, int numChannelsToUse)
|
||||
: Base (sessionToUse, numChannelsToUse)
|
||||
{}
|
||||
|
||||
SlRef<SLRecordItf_> createPlayerOrRecorder()
|
||||
{
|
||||
SLDataLocator_IODevice ioDeviceLocator = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr};
|
||||
SLDataLocator_AndroidSimpleBufferQueue queueLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers)};
|
||||
SLDataLocator_IODevice ioDeviceLocator = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, nullptr };
|
||||
SLDataLocator_AndroidSimpleBufferQueue queueLocator = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, static_cast<SLuint32> (Base::owner.numBuffers) };
|
||||
|
||||
PCMDataFormatEx dataFormat;
|
||||
BufferHelpers<T>::initPCMDataFormat (dataFormat, Base::numChannels, Base::owner.sampleRate);
|
||||
|
||||
SLDataSource source = {&ioDeviceLocator, nullptr};
|
||||
SLDataSink sink = {&queueLocator, &dataFormat};
|
||||
SLDataSource source = { &ioDeviceLocator, nullptr };
|
||||
SLDataSink sink = { &queueLocator, &dataFormat };
|
||||
|
||||
SLInterfaceID queueInterfaces[] = { &IntfIID<SLAndroidSimpleBufferQueueItf_>::iid, &IntfIID<SLAndroidConfigurationItf_>::iid };
|
||||
SLboolean interfaceRequired[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE};
|
||||
SLboolean interfaceRequired[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE };
|
||||
|
||||
SLObjectItf obj = nullptr;
|
||||
|
||||
SLresult status = (*Base::owner.engine)->CreateAudioRecorder (Base::owner.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired);
|
||||
if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
if (auto e = *Base::owner.engine)
|
||||
{
|
||||
if (obj != nullptr)
|
||||
(*obj)->Destroy (obj);
|
||||
auto status = e->CreateAudioRecorder (Base::owner.engine, &obj, &source, &sink, 2, queueInterfaces, interfaceRequired);
|
||||
|
||||
return SlRef<SLRecordItf_>();
|
||||
if (status != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
destroyObject (obj);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
SlRef<SLRecordItf_> recorder = SlRef<SLRecordItf_>::cast (SlObjectRef (obj));
|
||||
|
||||
return recorder;
|
||||
return SlRef<SLRecordItf_>::cast (SlObjectRef (obj));
|
||||
}
|
||||
|
||||
bool setAudioPreprocessingEnabled (bool shouldEnable)
|
||||
{
|
||||
if (Base::config != nullptr)
|
||||
{
|
||||
const bool supportsUnprocessed = (getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT) >= 25);
|
||||
const bool supportsUnprocessed = (getAndroidSDKVersion() >= 25);
|
||||
const SLuint32 recordingPresetValue
|
||||
= (shouldEnable ? SL_ANDROID_RECORDING_PRESET_GENERIC
|
||||
: (supportsUnprocessed ? SL_ANDROID_RECORDING_PRESET_UNPROCESSED
|
||||
: SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION));
|
||||
|
||||
SLresult status = (*Base::config)->SetConfiguration (Base::config, SL_ANDROID_KEY_RECORDING_PRESET,
|
||||
&recordingPresetValue, sizeof (recordingPresetValue));
|
||||
auto status = (*Base::config)->SetConfiguration (Base::config, SL_ANDROID_KEY_RECORDING_PRESET,
|
||||
&recordingPresetValue, sizeof (recordingPresetValue));
|
||||
|
||||
return (status == SL_RESULT_SUCCESS);
|
||||
}
|
||||
@ -482,7 +506,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
void setState (bool running) { (*Base::runner)->SetRecordState (Base::runner, running ? SL_RECORDSTATE_RECORDING : SL_RECORDSTATE_STOPPED); }
|
||||
void setState (bool running) { (*Base::runner)->SetRecordState (Base::runner, running ? SL_RECORDSTATE_RECORDING
|
||||
: SL_RECORDSTATE_STOPPED); }
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
@ -494,21 +519,19 @@ public:
|
||||
double samleRateToUse, int bufferSizeToUse,
|
||||
int numBuffersToUse)
|
||||
: inputChannels (numInputChannels), outputChannels (numOutputChannels),
|
||||
sampleRate (samleRateToUse), bufferSize (bufferSizeToUse), numBuffers (numBuffersToUse),
|
||||
running (false), audioProcessingEnabled (true), callback (nullptr)
|
||||
sampleRate (samleRateToUse), bufferSize (bufferSizeToUse), numBuffers (numBuffersToUse)
|
||||
{
|
||||
jassert (numInputChannels > 0 || numOutputChannels > 0);
|
||||
|
||||
if (CreateEngineFunc createEngine = (CreateEngineFunc) slLibraryToUse.getFunction ("slCreateEngine"))
|
||||
if (auto createEngine = (CreateEngineFunc) slLibraryToUse.getFunction ("slCreateEngine"))
|
||||
{
|
||||
SLObjectItf obj = nullptr;
|
||||
auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
|
||||
|
||||
SLresult err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
|
||||
|| (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
if (obj != nullptr)
|
||||
(*obj)->Destroy (obj);
|
||||
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -518,13 +541,12 @@ public:
|
||||
if (outputChannels > 0)
|
||||
{
|
||||
SLObjectItf obj = nullptr;
|
||||
auto err = (*engine)->CreateOutputMix (engine, &obj, 0, nullptr, nullptr);
|
||||
|
||||
SLresult err = (*engine)->CreateOutputMix (engine, &obj, 0, nullptr, nullptr);
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr
|
||||
|| (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
if (obj != nullptr)
|
||||
(*obj)->Destroy (obj);
|
||||
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -537,6 +559,7 @@ public:
|
||||
virtual bool openedOK() const { return (engine != nullptr && (outputChannels == 0 || (outputMix != nullptr))); }
|
||||
virtual void start() { stop(); jassert (callback.get() != nullptr); running = true; }
|
||||
virtual void stop() { running = false; }
|
||||
|
||||
virtual bool setAudioPreprocessingEnabled (bool shouldEnable) = 0;
|
||||
virtual bool supportsFloatingPoint() const noexcept = 0;
|
||||
virtual int getXRunCount() const noexcept = 0;
|
||||
@ -553,9 +576,10 @@ public:
|
||||
jassert (callbackToUse != nullptr);
|
||||
|
||||
// spin-lock until we can set the callback
|
||||
while (true)
|
||||
for (;;)
|
||||
{
|
||||
AudioIODeviceCallback* old = callback.get();
|
||||
auto old = callback.get();
|
||||
|
||||
if (old == callbackToUse)
|
||||
break;
|
||||
|
||||
@ -568,7 +592,7 @@ public:
|
||||
|
||||
void process (const float** inputChannelData, float** outputChannelData)
|
||||
{
|
||||
if (AudioIODeviceCallback* cb = callback.exchange(nullptr))
|
||||
if (auto* cb = callback.exchange (nullptr))
|
||||
{
|
||||
cb->audioDeviceIOCallback (inputChannelData, inputChannels, outputChannelData, outputChannels, bufferSize);
|
||||
callback.set (cb);
|
||||
@ -586,19 +610,19 @@ public:
|
||||
int numBuffersToUse);
|
||||
|
||||
//==============================================================================
|
||||
typedef SLresult (*CreateEngineFunc)(SLObjectItf*, SLuint32, const SLEngineOption*, SLuint32, const SLInterfaceID*, const SLboolean*);
|
||||
using CreateEngineFunc = SLresult (*) (SLObjectItf*, SLuint32, const SLEngineOption*,
|
||||
SLuint32, const SLInterfaceID*, const SLboolean*);
|
||||
|
||||
//==============================================================================
|
||||
int inputChannels, outputChannels;
|
||||
double sampleRate;
|
||||
int bufferSize, numBuffers;
|
||||
|
||||
bool running, audioProcessingEnabled;
|
||||
bool running = false, audioProcessingEnabled = true;
|
||||
|
||||
SlRef<SLEngineItf_> engine;
|
||||
SlRef<SLOutputMixItf_> outputMix;
|
||||
|
||||
Atomic<AudioIODeviceCallback*> callback;
|
||||
Atomic<AudioIODeviceCallback*> callback { nullptr };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -609,7 +633,8 @@ public:
|
||||
int numInputChannels, int numOutputChannels,
|
||||
double samleRateToUse, int bufferSizeToUse,
|
||||
int numBuffersToUse)
|
||||
: OpenSLSession (slLibraryToUse, numInputChannels, numOutputChannels, samleRateToUse, bufferSizeToUse, numBuffersToUse)
|
||||
: OpenSLSession (slLibraryToUse, numInputChannels, numOutputChannels,
|
||||
samleRateToUse, bufferSizeToUse, numBuffersToUse)
|
||||
{
|
||||
jassert (numInputChannels > 0 || numOutputChannels > 0);
|
||||
|
||||
@ -636,7 +661,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
const bool supportsUnderrunCount = (getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT) >= 24);
|
||||
const bool supportsUnderrunCount = (getAndroidSDKVersion() >= 24);
|
||||
getUnderrunCount = supportsUnderrunCount ? getEnv()->GetMethodID (AudioTrack, "getUnderrunCount", "()I") : 0;
|
||||
}
|
||||
}
|
||||
@ -644,8 +669,8 @@ public:
|
||||
|
||||
bool openedOK() const override
|
||||
{
|
||||
return (OpenSLSession::openedOK() && (inputChannels == 0 || recorder != nullptr)
|
||||
&& (outputChannels == 0 || player != nullptr));
|
||||
return OpenSLSession::openedOK() && (inputChannels == 0 || recorder != nullptr)
|
||||
&& (outputChannels == 0 || player != nullptr);
|
||||
}
|
||||
|
||||
void start() override
|
||||
@ -762,11 +787,7 @@ public:
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
OpenSLAudioIODevice (const String& deviceName)
|
||||
: AudioIODevice (deviceName, openSLTypeName),
|
||||
actualBufferSize (0), sampleRate (0), audioBuffersToEnqueue (0),
|
||||
audioProcessingEnabled (true),
|
||||
callback (nullptr)
|
||||
OpenSLAudioIODevice (const String& deviceName) : AudioIODevice (deviceName, openSLTypeName)
|
||||
{
|
||||
// OpenSL has piss-poor support for determining latency, so the only way I can find to
|
||||
// get a number for this is by asking the AudioTrack/AudioRecord classes..
|
||||
@ -813,7 +834,7 @@ public:
|
||||
|
||||
Array<double> getAvailableSampleRates() override
|
||||
{
|
||||
//see https://developer.android.com/ndk/guides/audio/opensl-for-android.html
|
||||
// see https://developer.android.com/ndk/guides/audio/opensl-for-android.html
|
||||
|
||||
static const double rates[] = { 8000.0, 11025.0, 12000.0, 16000.0,
|
||||
22050.0, 24000.0, 32000.0, 44100.0, 48000.0 };
|
||||
@ -821,6 +842,7 @@ public:
|
||||
|
||||
// make sure the native sample rate is pafrt of the list
|
||||
double native = getNativeSampleRate();
|
||||
|
||||
if (native != 0.0 && ! retval.contains (native))
|
||||
retval.add (native);
|
||||
|
||||
@ -850,7 +872,8 @@ public:
|
||||
close();
|
||||
|
||||
lastError.clear();
|
||||
sampleRate = (int) requestedSampleRate;
|
||||
|
||||
sampleRate = (int) (requestedSampleRate > 0 ? requestedSampleRate : getNativeSampleRate());
|
||||
|
||||
auto totalPreferredBufferSize = (bufferSize <= 0) ? getDefaultBufferSize() : bufferSize;
|
||||
auto nativeBufferSize = getNativeBufferSize();
|
||||
@ -862,11 +885,11 @@ public:
|
||||
|
||||
activeOutputChans = outputChannels;
|
||||
activeOutputChans.setRange (2, activeOutputChans.getHighestBit(), false);
|
||||
int numOutputChannels = activeOutputChans.countNumberOfSetBits();
|
||||
auto numOutputChannels = activeOutputChans.countNumberOfSetBits();
|
||||
|
||||
activeInputChans = inputChannels;
|
||||
activeInputChans.setRange (1, activeInputChans.getHighestBit(), false);
|
||||
int numInputChannels = activeInputChans.countNumberOfSetBits();
|
||||
auto numInputChannels = activeInputChans.countNumberOfSetBits();
|
||||
|
||||
if (numInputChannels > 0 && (! RuntimePermissions::isGranted (RuntimePermissions::recordAudio)))
|
||||
{
|
||||
@ -879,7 +902,9 @@ public:
|
||||
session.reset (OpenSLSession::create (slLibrary, numInputChannels, numOutputChannels,
|
||||
sampleRate, actualBufferSize, audioBuffersToEnqueue));
|
||||
if (session != nullptr)
|
||||
{
|
||||
session->setAudioPreprocessingEnabled (audioProcessingEnabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numInputChannels > 0 && numOutputChannels > 0 && RuntimePermissions::isGranted (RuntimePermissions::recordAudio))
|
||||
@ -945,7 +970,7 @@ public:
|
||||
{
|
||||
if (session != nullptr && callback != newCallback)
|
||||
{
|
||||
AudioIODeviceCallback* oldCallback = callback;
|
||||
auto oldCallback = callback;
|
||||
|
||||
if (newCallback != nullptr)
|
||||
newCallback->audioDeviceAboutToStart (this);
|
||||
@ -1001,12 +1026,12 @@ private:
|
||||
|
||||
//==============================================================================
|
||||
DynamicLibrary slLibrary;
|
||||
int actualBufferSize, sampleRate, audioBuffersToEnqueue;
|
||||
int actualBufferSize = 0, sampleRate = 0, audioBuffersToEnqueue = 0;
|
||||
int inputLatency, outputLatency;
|
||||
bool deviceOpen, audioProcessingEnabled;
|
||||
bool deviceOpen = false, audioProcessingEnabled = true;
|
||||
String lastError;
|
||||
BigInteger activeOutputChans, activeInputChans;
|
||||
AudioIODeviceCallback* callback;
|
||||
AudioIODeviceCallback* callback = nullptr;
|
||||
|
||||
std::unique_ptr<OpenSLSession> session;
|
||||
|
||||
@ -1024,9 +1049,7 @@ private:
|
||||
// "For Android 4.2 (API level 17) and earlier, a buffer count of two or more is required
|
||||
// for lower latency. Beginning with Android 4.3 (API level 18), a buffer count of one
|
||||
// is sufficient for lower latency."
|
||||
|
||||
auto sdkVersion = getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT);
|
||||
return (sdkVersion >= 18 ? 1 : 2);
|
||||
return (getAndroidSDKVersion() >= 18 ? 1 : 2);
|
||||
}
|
||||
|
||||
// we will not use the low-latency path so we can use the absolute minimum number of buffers
|
||||
@ -1055,23 +1078,6 @@ private:
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static String audioManagerGetProperty (const String& property)
|
||||
{
|
||||
const LocalRef<jstring> jProperty (javaString (property));
|
||||
const LocalRef<jstring> text ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
|
||||
jProperty.get()));
|
||||
if (text.get() != 0)
|
||||
return juceString (text);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool androidHasSystemFeature (const String& property)
|
||||
{
|
||||
const LocalRef<jstring> jProperty (javaString (property));
|
||||
return android.activity.callBooleanMethod (JuceAppActivity.hasSystemFeature, jProperty.get());
|
||||
}
|
||||
|
||||
static double getNativeSampleRate()
|
||||
{
|
||||
return audioManagerGetProperty ("android.media.property.OUTPUT_SAMPLE_RATE").getDoubleValue();
|
||||
@ -1123,7 +1129,7 @@ OpenSLAudioIODevice::OpenSLSession* OpenSLAudioIODevice::OpenSLSession::create (
|
||||
int numBuffersToUse)
|
||||
{
|
||||
std::unique_ptr<OpenSLSession> retval;
|
||||
auto sdkVersion = getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT);
|
||||
auto sdkVersion = getAndroidSDKVersion();
|
||||
|
||||
// SDK versions 21 and higher should natively support floating point...
|
||||
if (sdkVersion >= 21)
|
||||
@ -1210,12 +1216,12 @@ public:
|
||||
SLObjectItf obj = nullptr;
|
||||
auto err = createEngine (&obj, 0, nullptr, 0, nullptr, nullptr);
|
||||
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr)
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || *obj == nullptr)
|
||||
return;
|
||||
|
||||
if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1223,7 +1229,7 @@ public:
|
||||
|
||||
if (engine == nullptr)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1232,7 +1238,7 @@ public:
|
||||
|
||||
if (err != SL_RESULT_SUCCESS || obj == nullptr || (*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1240,7 +1246,7 @@ public:
|
||||
|
||||
if (outputMix == nullptr)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1264,7 +1270,7 @@ public:
|
||||
|
||||
if ((*obj)->Realize (obj, 0) != SL_RESULT_SUCCESS)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1272,7 +1278,7 @@ public:
|
||||
|
||||
if (player == nullptr)
|
||||
{
|
||||
(*obj)->Destroy (obj);
|
||||
destroyObject (obj);
|
||||
return;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user