https://github.com/libsdl-org/SDL/commit/5ff87c6d4ae89b32b691e3a7083e9b834774c013
From 5ff87c6d4ae89b32b691e3a7083e9b834774c013 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 26 Jul 2023 15:45:40 -0400
Subject: [PATCH] android: Reworked audio backends for SDL3 audio API.
This involved moving an `#ifdef` out of SDL_audio.c for thread priority,
so the default ThreadInit now does the usual stuff for non-Android platforms,
the Android platforms provide an implementatin of ThreadInit with their
side of the `#ifdef` and other platforms that implement ThreadInit
incorporated the appropriate code...which is why WASAPI is touched in here.
The Android bits compile, but have not been tested, and there was some
reworkings in the Java bits, so this might need some further fixes still.
---
.../java/org/libsdl/app/SDLAudioManager.java | 62 +--
src/audio/SDL_audio.c | 26 +-
src/audio/aaudio/SDL_aaudio.c | 453 +++++++-----------
src/audio/aaudio/SDL_aaudiofuncs.h | 4 +-
src/audio/android/SDL_androidaudio.c | 152 +++---
src/audio/openslES/SDL_openslES.c | 354 +++++++-------
src/audio/wasapi/SDL_wasapi_win32.c | 3 +
src/audio/wasapi/SDL_wasapi_winrt.cpp | 1 +
src/core/android/SDL_android.c | 117 ++---
src/core/android/SDL_android.h | 9 +-
10 files changed, 473 insertions(+), 708 deletions(-)
diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java
index 2a6751e47ca3..e64a0790d457 100644
--- a/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java
+++ b/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java
@@ -21,8 +21,6 @@ public class SDLAudioManager {
protected static AudioRecord mAudioRecord;
protected static Context mContext;
- private static final int[] NO_DEVICES = {};
-
private static AudioDeviceCallback mAudioDeviceCallback;
public static void initialize() {
@@ -36,7 +34,7 @@ public static void initialize() {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
for (AudioDeviceInfo deviceInfo : addedDevices) {
- addAudioDevice(deviceInfo.isSink(), deviceInfo.getId());
+ addAudioDevice(deviceInfo.isSink(), deviceInfo.getProductName().toString(), deviceInfo.getId());
}
}
@@ -52,13 +50,10 @@ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
public static void setContext(Context context) {
mContext = context;
- if (context != null) {
- registerAudioDeviceCallback();
- }
}
public static void release(Context context) {
- unregisterAudioDeviceCallback(context);
+ // no-op atm
}
// Audio
@@ -311,62 +306,17 @@ private static AudioDeviceInfo getOutputAudioDeviceInfo(int deviceId) {
return null;
}
- private static void registerAudioDeviceCallback() {
+ public static void registerAudioDeviceCallback() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
}
}
- private static void unregisterAudioDeviceCallback(Context context) {
- if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
- AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
- audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
- }
- }
-
- private static int[] ArrayListToArray(ArrayList<Integer> integers)
- {
- int[] ret = new int[integers.size()];
- for (int i=0; i < ret.length; i++) {
- ret[i] = integers.get(i).intValue();
- }
- return ret;
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static int[] getAudioOutputDevices() {
+ public static void unregisterAudioDeviceCallback() {
if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- ArrayList<Integer> arrlist = new ArrayList<Integer>();
- for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
- /* Device cannot be opened */
- if (dev.getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
- continue;
- }
- arrlist.add(dev.getId());
- }
- return ArrayListToArray(arrlist);
- } else {
- return NO_DEVICES;
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static int[] getAudioInputDevices() {
- if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
- AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- ArrayList<Integer> arrlist = new ArrayList<Integer>();
- for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
- arrlist.add(dev.getId());
- }
- return ArrayListToArray(arrlist);
- } else {
- return NO_DEVICES;
+ audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
}
}
@@ -535,6 +485,6 @@ public static void audioSetThreadPriority(boolean iscapture, int device_id) {
public static native void removeAudioDevice(boolean isCapture, int deviceId);
- public static native void addAudioDevice(boolean isCapture, int deviceId);
+ public static native void addAudioDevice(boolean isCapture, String name, int deviceId);
}
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 52dc724a86a9..dd1d2af1b414 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -25,8 +25,6 @@
#include "../thread/SDL_systhread.h"
#include "../SDL_utils_c.h"
-extern void Android_JNI_AudioSetThreadPriority(int, int); // we need this on Android in the audio device threads.
-
// Available audio drivers
static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_PULSEAUDIO
@@ -412,7 +410,6 @@ void SDL_AudioDeviceDisconnected(SDL_AudioDevice *device)
// stubs for audio drivers that don't need a specific entry point...
-static void SDL_AudioThreadInit_Default(SDL_AudioDevice *device) { /* no-op. */ }
static void SDL_AudioThreadDeinit_Default(SDL_AudioDevice *device) { /* no-op. */ }
static void SDL_AudioWaitDevice_Default(SDL_AudioDevice *device) { /* no-op. */ }
static void SDL_AudioPlayDevice_Default(SDL_AudioDevice *device, const Uint8 *buffer, int buffer_size) { /* no-op. */ }
@@ -422,6 +419,11 @@ static void SDL_AudioCloseDevice_Default(SDL_AudioDevice *device) { /* no-op. */
static void SDL_AudioDeinitialize_Default(void) { /* no-op. */ }
static void SDL_AudioFreeDeviceHandle_Default(SDL_AudioDevice *device) { /* no-op. */ }
+static void SDL_AudioThreadInit_Default(SDL_AudioDevice *device)
+{
+ SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
+}
+
static void SDL_AudioDetectDevices_Default(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
{
// you have to write your own implementation if these assertions fail.
@@ -679,15 +681,6 @@ void SDL_AudioThreadFinalize(SDL_AudioDevice *device)
void SDL_OutputAudioThreadSetup(SDL_AudioDevice *device)
{
SDL_assert(!device->iscapture);
-
- // The audio mixing is always a high priority thread
-#ifdef SDL_AUDIO_DRIVER_ANDROID
- Android_JNI_AudioSetThreadPriority(SDL_FALSE, device->id);
-#else
- SDL_SetThreadPriority(SDL_THREAD_PRIORITY_TIME_CRITICAL);
-#endif
-
- // Perform any thread setup
current_audio.impl.ThreadInit(device);
}
@@ -781,14 +774,6 @@ static int SDLCALL OutputAudioThread(void *devicep) // thread entry point
void SDL_CaptureAudioThreadSetup(SDL_AudioDevice *device)
{
SDL_assert(device->iscapture);
-
- // Audio capture is always a high priority thread (!!! FIXME: _should_ it be?)
-#ifdef SDL_AUDIO_DRIVER_ANDROID
- Android_JNI_AudioSetThreadPriority(SDL_TRUE, device->id);
-#else
- SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
-#endif
-
current_audio.impl.ThreadInit(device);
}
@@ -1068,7 +1053,6 @@ int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec)
if ((devid == 0) && is_default) {
return SDL_SetError("No default audio device available");
- return 0;
}
SDL_AudioDevice *device = ObtainPhysicalAudioDevice(devid);
diff --git a/src/audio/aaudio/SDL_aaudio.c b/src/audio/aaudio/SDL_aaudio.c
index 92bd00a104ef..777286bf38ed 100644
--- a/src/audio/aaudio/SDL_aaudio.c
+++ b/src/audio/aaudio/SDL_aaudio.c
@@ -34,16 +34,13 @@ struct SDL_PrivateAudioData
{
AAudioStream *stream;
- /* Raw mixing buffer */
- Uint8 *mixbuf;
- int mixlen;
+ Uint8 *mixbuf; // Raw mixing buffer
int frame_size;
- /* Resume device if it was paused automatically */
- int resume;
+ int resume; // Resume device if it was paused automatically
};
-/* Debug */
+// Debug
#if 0
#define LOGI(...) SDL_Log(__VA_ARGS__);
#else
@@ -52,7 +49,6 @@ struct SDL_PrivateAudioData
typedef struct AAUDIO_Data
{
- AAudioStreamBuilder *builder;
void *handle;
#define SDL_PROC(ret, func, params) ret (*func) params;
#include "SDL_aaudiofuncs.h"
@@ -79,11 +75,14 @@ static void AAUDIO_errorCallback(AAudioStream *stream, void *userData, aaudio_re
#define LIB_AAUDIO_SO "libaaudio.so"
-static int AAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
+static int AAUDIO_OpenDevice(SDL_AudioDevice *device)
{
- struct SDL_PrivateAudioData *private;
- SDL_bool iscapture = _this->iscapture;
+ struct SDL_PrivateAudioData *hidden;
+ const SDL_bool iscapture = device->iscapture;
aaudio_result_t res;
+
+ SDL_assert(device->handle != NULL); // AAUDIO_UNSPECIFIED is zero, so legit devices should all be non-zero.
+
LOGI(__func__);
if (iscapture) {
@@ -93,75 +92,91 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
}
}
- _this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
- if (_this->hidden == NULL) {
+ hidden = device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
+ if (hidden == NULL) {
return SDL_OutOfMemory();
}
- private = _this->hidden;
-
- ctx.AAudioStreamBuilder_setSampleRate(ctx.builder, _this->spec.freq);
- ctx.AAudioStreamBuilder_setChannelCount(ctx.builder, _this->spec.channels);
- if(devname != NULL) {
- int aaudio_device_id = SDL_atoi(devname);
- LOGI("Opening device id %d", aaudio_device_id);
- ctx.AAudioStreamBuilder_setDeviceId(ctx.builder, aaudio_device_id);
- }
- {
- aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
- ctx.AAudioStreamBuilder_setDirection(ctx.builder, direction);
+
+ AAudioStreamBuilder *builder = NULL;
+ res = ctx.AAudio_createStreamBuilder(&builder);
+ if (res != AAUDIO_OK) {
+ LOGI("SDL Failed AAudio_createStreamBuilder %d", res);
+ return SDL_SetError("SDL Failed AAudio_createStreamBuilder %d", res);
+ } else if (builder == NULL) {
+ LOGI("SDL Failed AAudio_createStreamBuilder - builder NULL");
+ return SDL_SetError("SDL Failed AAudio_createStreamBuilder - builder NULL");
}
- {
- aaudio_format_t format = AAUDIO_FORMAT_PCM_FLOAT;
- if (_this->spec.format == SDL_AUDIO_S16SYS) {
- format = AAUDIO_FORMAT_PCM_I16;
- } else if (_this->spec.format == SDL_AUDIO_S16SYS) {
- format = AAUDIO_FORMAT_PCM_FLOAT;
- }
- ctx.AAudioStreamBuilder_setFormat(ctx.builder, format);
+
+ // !!! FIXME: call AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY); ?
+
+ ctx.AAudioStreamBuilder_setSampleRate(builder, device->spec.freq);
+ ctx.AAudioStreamBuilder_setChannelCount(builder, device->spec.channels);
+
+ const int aaudio_device_id = (int) ((size_t) device->handle);
+ LOGI("Opening device id %d", aaudio_device_id);
+ ctx.AAudioStreamBuilder_setDeviceId(builder, aaudio_device_id);
+
+ const aaudio_direction_t direction = (iscapture ? AAUDIO_DIRECTION_INPUT : AAUDIO_DIRECTION_OUTPUT);
+ ctx.AAudioStreamBuilder_setDirection(builder, direction);
+ aaudio_format_t format;
+ if (device->spec.format == SDL_AUDIO_S32SYS) {
+ format = AAUDIO_FORMAT_PCM_I32;
+ } else if (device->spec.format == SDL_AUDIO_F32SYS) {
+ format = AAUDIO_FORMAT_PCM_FLOAT;
+ } else {
+ format = AAUDIO_FORMAT_PCM_I16; // sint16 is a safe bet for everything else.
}
- ctx.AAudioStreamBuilder_setErrorCallback(ctx.builder, AAUDIO_errorCallback, private);
+ ctx.AAudioStreamBuilder_setFormat(builder, format);
+
+ ctx.AAudioStreamBuilder_setErrorCallback(builder, AAUDIO_errorCallback, hidden);
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
- _this->spec.freq, SDL_AUDIO_BITSIZE(_this->spec.format),
- _this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
+ device->spec.freq, SDL_AUDIO_BITSIZE(device->spec.format),
+ device->spec.channels, (device->spec.format & 0x1000) ? "BE" : "LE", device->sample_frames);
+
+ res = ctx.AAudioStreamBuilder_openStream(builder, &hidden->stream);
+ ctx.AAudioStreamBuilder_delete(builder);
- res = ctx.AAudioStreamBuilder_openStream(ctx.builder, &private->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStreamBuilder_openStream %d", res);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
- _this->spec.freq = ctx.AAudioStream_getSampleRate(private->stream);
- _this->spec.channels = ctx.AAudioStream_getChannelCount(private->stream);
- {
- aaudio_format_t fmt = ctx.AAudioStream_getFormat(private->stream);
- if (fmt == AAUDIO_FORMAT_PCM_I16) {
- _this->spec.format = SDL_AUDIO_S16SYS;
- } else if (fmt == AAUDIO_FORMAT_PCM_FLOAT) {
- _this->spec.format = SDL_AUDIO_F32SYS;
- }
+ device->spec.freq = ctx.AAudioStream_getSampleRate(hidden->stream);
+ device->spec.channels = ctx.AAudioStream_getChannelCount(hidden->stream);
+
+ format = ctx.AAudioStream_getFormat(hidden->stream);
+ if (format == AAUDIO_FORMAT_PCM_I16) {
+ device->spec.format = SDL_AUDIO_S16SYS;
+ } else if (format == AAUDIO_FORMAT_PCM_I32) {
+ device->spec.format = SDL_AUDIO_S32SYS;
+ } else if (format == AAUDIO_FORMAT_PCM_FLOAT) {
+ device->spec.format = SDL_AUDIO_F32SYS;
+ } else {
+ return SDL_SetError("Got unexpected audio format %d from AAudioStream_getFormat", (int) format);
}
+ device->sample_frames = ctx.AAudioStream_getBufferCapacityInFrames(hidden->stream) / 2;
+
LOGI("AAudio Try to open %u hz %u bit chan %u %s samples %u",
- _this->spec.freq, SDL_AUDIO_BITSIZE(_this->spec.format),
- _this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples);
+ device->spec.freq, SDL_AUDIO_BITSIZE(device->spec.format),
+ device->spec.channels, SDL_AUDIO_ISBIGENDIAN(device->spec.format) ? "BE" : "LE", device->sample_frames);
- SDL_CalculateAudioSpec(&_this->spec);
+ SDL_UpdatedAudioDeviceFormat(device);
- /* Allocate mixing buffer */
+ // Allocate mixing buffer
if (!iscapture) {
- private->mixlen = _this->spec.size;
- private->mixbuf = (Uint8 *)SDL_malloc(private->mixlen);
- if (private->mixbuf == NULL) {
+ hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
+ if (hidden->mixbuf == NULL) {
return SDL_OutOfMemory();
}
- SDL_memset(private->mixbuf, _this->spec.silence, _this->spec.size);
+ SDL_memset(hidden->mixbuf, device->silence_value, device->buffer_size);
}
- private->frame_size = _this->spec.channels * (SDL_AUDIO_BITSIZE(_this->spec.format) / 8);
+ hidden->frame_size = device->spec.channels * (SDL_AUDIO_BITSIZE(device->spec.format) / 8);
- res = ctx.AAudioStream_requestStart(private->stream);
+ res = ctx.AAudioStream_requestStart(hidden->stream);
if (res != AAUDIO_OK) {
LOGI("SDL Failed AAudioStream_requestStart %d iscapture:%d", res, iscapture);
return SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
@@ -171,55 +186,51 @@ static int AAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
return 0;
}
-static void AAUDIO_CloseDevice(SDL_AudioDevice *_this)
+static void AAUDIO_CloseDevice(SDL_AudioDevice *device)
{
- struct SDL_PrivateAudioData *private = _this->hidden;
- aaudio_result_t res;
- LOGI(__func__);
+ struct SDL_PrivateAudioData *hidden = device->hidden;
+ if (hidden) {
+ LOGI(__func__);
- if (private->stream) {
- res = ctx.AAudioStream_requestStop(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStream_requestStop %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- return;
+ if (hidden->stream) {
+ ctx.AAudioStream_requestStop(hidden->stream);
+ ctx.AAudioStream_close(hidden->stream);
}
- res = ctx.AAudioStream_close(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStreamBuilder_delete %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- return;
- }
+ SDL_free(hidden->mixbuf);
+ SDL_free(hidden);
+ device->hidden = NULL;
}
+}
- SDL_free(_this->hidden->mixbuf);
- SDL_free(_this->hidden);
+static Uint8 *AAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
+{
+ return device->hidden->mixbuf;
}
-static Uint8 *AAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
+static void AAUDIO_WaitDevice(SDL_AudioDevice *device)
{
- struct SDL_PrivateAudioData *private = _this->hidden;
- return private->mixbuf;
+ AAudioStream *stream = device->hidden->stream;
+ while (!SDL_AtomicGet(&device->shutdown) && ((int) ctx.AAudioStream_getBufferSizeInFrames(stream)) < device->sample_frames) {
+ SDL_Delay(1);
+ }
}
-static void AAUDIO_PlayDevice(SDL_AudioDevice *_this)
+static void AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
{
- struct SDL_PrivateAudioData *private = _this->hidden;
- aaudio_result_t res;
- int64_t timeoutNanoseconds = 1 * 1000 * 1000; /* 8 ms */
- res = ctx.AAudioStream_write(private->stream, private->mixbuf, private->mixlen / private->frame_size, timeoutNanoseconds);
+ AAudioStream *stream = device->hidden->stream;
+ const aaudio_result_t res = ctx.AAudioStream_write(stream, buffer, device->sample_frames, 0);
if (res < 0) {
LOGI("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
} else {
- LOGI("SDL AAudio play: %d frames, wanted:%d frames", (int)res, private->mixlen / private->frame_size);
+ LOGI("SDL AAudio play: %d frames, wanted:%d frames", (int)res, sample_frames);
}
#if 0
- /* Log under-run count */
+ // Log under-run count
{
static int prev = 0;
- int32_t cnt = ctx.AAudioStream_getXRunCount(private->stream);
+ int32_t cnt = ctx.AAudioStream_getXRunCount(hidden->stream);
if (cnt != prev) {
SDL_Log("AAudio underrun: %d - total: %d", cnt - prev, cnt);
prev = cnt;
@@ -228,41 +239,31 @@ static void AAUDIO_PlayDevice(SDL_AudioDevice *_this)
#endif
}
-static int AAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
+static int AAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen)
{
- struct SDL_PrivateAudioData *private = _this->hidden;
- aaudio_result_t res;
- int64_t timeoutNanoseconds = 8 * 1000 * 1000; /* 8 ms */
- res = ctx.AAudioStream_read(private->stream, buffer, buflen / private->frame_size, timeoutNanoseconds);
+ const aaudio_result_t res = ctx.AAudioStream_read(device->hidden->stream, buffer, device->sample_frames, 0);
if (res < 0) {
LOGI("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
return -1;
}
- LOGI("SDL AAudio capture:%d frames, wanted:%d frames", (int)res, buflen / private->frame_size);
- return res * private->frame_size;
+ LOGI("SDL AAudio capture:%d frames, wanted:%d frames", (int)res, buflen / device->hidden->frame_size);
+ return res * device->hidden->frame_size;
}
static void AAUDIO_Deinitialize(void)
{
+ Android_StopAudioHotplug();
+
LOGI(__func__);
if (ctx.handle) {
- if (ctx.builder) {
- aaudio_result_t res;
- res = ctx.AAudioStreamBuilder_delete(ctx.builder);
- if (res != AAUDIO_OK) {
- SDL_SetError("Failed AAudioStreamBuilder_delete %s", ctx.AAudio_convertResultToText(res));
- }
- }
SDL_UnloadObject(ctx.handle);
}
- ctx.handle = NULL;
- ctx.builder = NULL;
+ SDL_zero(ctx);
LOGI("End AAUDIO %s", SDL_GetError());
}
static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
{
- aaudio_result_t res;
LOGI(__func__);
/* AAudio was introduced in Android 8.0, but has reference counting crash issues in that release,
@@ -279,189 +280,96 @@ static SDL_bool AAUDIO_Init(SDL_AudioDriverImpl *impl)
ctx.handle = SDL_LoadObject(LIB_AAUDIO_SO);
if (ctx.handle == NULL) {
LOGI("SDL couldn't find " LIB_AAUDIO_SO);
- goto failure;
+ return SDL_FALSE;
}
if (AAUDIO_LoadFunctions(&ctx) < 0) {
- goto failure;
- }
-
- res = ctx.AAudio_createStreamBuilder(&ctx.builder);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudio_createStreamBuilder %d", res);
- goto failure;
- }
-
- if (ctx.builder == NULL) {
- LOGI("SDL Failed AAudio_createStreamBuilder - builder NULL");
- goto failure;
+ SDL_UnloadObject(ctx.handle);
+ SDL_zero(ctx);
+ return SDL_FALSE;
}
- impl->DetectDevices = Android_DetectDevices;
+ impl->ThreadInit = Android_AudioThreadInit;
+ impl->DetectDevices = Android_StartAudioHotplug;
impl->Deinitialize = AAUDIO_Deinitialize;
impl->OpenDevice = AAUDIO_OpenDevice;
impl->CloseDevice = AAUDIO_CloseDevice;
+ impl->WaitDevice = AAUDIO_WaitDevice;
impl->PlayDevice = AAUDIO_PlayDevice;
impl->GetDeviceBuf = AAUDIO_GetDeviceBuf;
+ impl->WaitCaptureDevice = AAUDIO_WaitDevice;
impl->CaptureFromDevice = AAUDIO_CaptureFromDevice;
- impl->AllowsArbitraryDeviceNames = SDL_TRUE;
- /* and the capabilities */
impl->HasCaptureSupport = SDL_TRUE;
- impl->OnlyHasDefaultOutputDevice = SDL_FALSE;
- impl->OnlyHasDefaultCaptureDevice = SDL_FALSE;
- /* this audio target is available. */
LOGI("SDL AAUDIO_Init OK");
return SDL_TRUE;
-
-failure:
- if (ctx.handle) {
- if (ctx.builder) {
- ctx.AAudioStreamBuilder_delete(ctx.builder);
- }
- SDL_UnloadObject(ctx.handle);
- }
- ctx.handle = NULL;
- ctx.builder = NULL;
- return SDL_FALSE;
}
AudioBootStrap AAUDIO_bootstrap = {
"AAudio", "AAudio audio driver", AAUDIO_Init, SDL_FALSE
};
-/* Pause (block) all non already paused audio devices by taking their mixer lock */
-void AAUDIO_PauseDevices(void)
-{
- int i;
- /* AAUDIO driver is not used */
- if (ctx.handle == NULL) {
- return;
- }
-
- for (i = 0; i < get_max_num_audio_dev(); i++) {
- SDL_AudioDevice *_this = get_audio_dev(i);
- SDL_AudioDevice *audioDevice = NULL;
- SDL_AudioDevice *captureDevice = NULL;
-
- if (_this == NULL) {
- continue;
- }
-
- if (_this->iscapture) {
- captureDevice = _this;
- } else {
- audioDevice = _this;
- }
-
- if (audioDevice != NULL && audioDevice->hidden != NULL) {
- struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
-
- if (private->stream) {
- aaudio_result_t res = ctx.AAudioStream_requestPause(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStream_requestPause %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- }
- }
+static SDL_bool PauseOneDevice(SDL_AudioDevice *device, void *userdata)
+{
+ struct SDL_PrivateAudioData *hidden = (struct SDL_PrivateAudioData *)device->hidden;
+ if (hidden != NULL) {
+ if (hidden->stream) {
+ aaudio_result_t res;
- if (SDL_AtomicGet(&audioDevice->paused)) {
- /* The device is already paused, leave it alone */
- private->resume = SDL_FALSE;
+ if (device->iscapture) {
+ // Pause() isn't implemented for 'capture', use Stop()
+ res = ctx.AAudioStream_requestStop(hidden->stream);
} else {
- SDL_LockMutex(audioDevice->mixer_lock);
- SDL_AtomicSet(&audioDevice->paused, 1);
- private->resume = SDL_TRUE;
+ res = ctx.AAudioStream_requestPause(hidden->stream);
}
- }
- if (captureDevice != NULL && captureDevice->hidden != NULL) {
- struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
-
- if (private->stream) {
- /* Pause() isn't implemented for 'capture', use Stop() */
- aaudio_result_t res = ctx.AAudioStream_requestStop(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStream_requestStop %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- }
+ if (res != AAUDIO_OK) {
+ LOGI("SDL Failed AAudioStream_requestPause %d", res);
+ SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
- if (SDL_AtomicGet(&captureDevice->paused)) {
- /* The device is already paused, leave it alone */
- private->resume = SDL_FALSE;
- } else {
- SDL_LockMutex(captureDevice->mixer_lock);
- SDL_AtomicSet(&captureDevice->paused, 1);
- private->resume = SDL_TRUE;
- }
+ SDL_LockMutex(device->lock);
+ hidden->resume = SDL_TRUE;
}
-
}
+ return SDL_FALSE; // keep enumerating.
}
-/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
-void AAUDIO_ResumeDevices(void)
+// Pause (block) all non already paused audio devices by taking their mixer lock
+void AAUDIO_PauseDevices(void)
{
- int i;
-
- /* AAUDIO driver is not used */
- if (ctx.handle == NULL) {
- return;
+ if (ctx.handle != NULL) { // AAUDIO driver is used?
+ (void) SDL_FindPhysicalAudioDeviceByCallback(PauseOneDevice, NULL);
}
+}
- for (i = 0; i < get_max_num_audio_dev(); i++) {
- SDL_AudioDevice *_this = get_audio_dev(i);
- SDL_AudioDevice *audioDevice = NULL;
- SDL_AudioDevice *captureDevice = NULL;
-
- if (_this == NULL) {
- continue;
- }
-
- if (_this->iscapture) {
- captureDevice = _this;
- } else {
- audioDevice = _this;
+// Resume (unblock) all non already paused audio devices by releasing their mixer lock
+static SDL_bool ResumeOneDevice(SDL_AudioDevice *device, void *userdata)
+{
+ struct SDL_PrivateAudioData *hidden = device->hidden;
+ if (hidden != NULL) {
+ if (hidden->resume) {
+ hidden->resume = SDL_FALSE;
+ SDL_UnlockMutex(device->lock);
}
- if (audioDevice != NULL && audioDevice->hidden != NULL) {
- struct SDL_PrivateAudioData *private = audioDevice->hidden;
-
- if (private->resume) {
- SDL_AtomicSet(&audioDevice->paused, 0);
- private->resume = SDL_FALSE;
- SDL_UnlockMutex(audioDevice->mixer_lock);
- }
-
- if (private->stream) {
- aaudio_result_t res = ctx.AAudioStream_requestStart(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStream_requestStart %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- }
+ if (hidden->stream) {
+ aaudio_result_t res = ctx.AAudioStream_requestStart(hidden->stream);
+ if (res != AAUDIO_OK) {
+ LOGI("SDL Failed AAudioStream_requestStart %d", res);
+ SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
}
}
+ }
+ return SDL_FALSE; // keep enumerating.
+}
- if (captureDevice != NULL && captureDevice->hidden != NULL) {
- struct SDL_PrivateAudioData *private = audioDevice->hidden;
-
- if (private->resume) {
- SDL_AtomicSet(&captureDevice->paused, 0);
- private->resume = SDL_FALSE;
- SDL_UnlockMutex(captureDevice->mixer_lock);
- }
-
- if (private->stream) {
- aaudio_result_t res = ctx.AAudioStream_requestStart(private->stream);
- if (res != AAUDIO_OK) {
- LOGI("SDL Failed AAudioStream_requestStart %d", res);
- SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
- }
- }
- }
+void AAUDIO_ResumeDevices(void)
+{
+ if (ctx.handle != NULL) { // AAUDIO driver is used?
+ (void) SDL_FindPhysicalAudioDeviceByCallback(ResumeOneDevice, NULL);
}
}
@@ -470,50 +378,29 @@ void AAUDIO_ResumeDevices(void)
None of the standard state queries indicate any problem in my testing. And the error callback doesn't actually get called.
But, AAudioStream_getTimestamp() does return AAUDIO_ERROR_INVALID_STATE
*/
-SDL_bool AAUDIO_DetectBrokenPlayState(void)
+static SDL_bool DetectBrokenPlayStatePerDevice(SDL_AudioDevice *device, void *userdata)
{
- int i;
-
- /* AAUDIO driver is not used */
- if (ctx.handle == NULL) {
- return SDL_FALSE;
- }
-
- for (i = 0; i < get_max_num_audio_dev(); i++) {
- SDL_AudioDevice *_this = get_audio_dev(i);
- SDL_AudioDevice *audioDevice = NULL;
- SDL_AudioDevice *captureDevice = NULL;
-
- if (_this == NULL) {
- continue;
- }
-
- if (_this->iscapture) {
- captureDevice = _this;
- } else {
- audioDevice = _this;
- }
-
- if (audioDevice != NULL && audioDevice->hidden != NULL) {
- struct SDL_PrivateAudioData *private = audioDevice->hidden;
- int64_t framePosition, timeNanoseconds;
-
- aaudio_result_t r
(Patch may be truncated, please check the link at the top of this post.)