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 2a6751e47c..e64a0790d4 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 class SDLAudioManager { @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 class SDLAudioManager { 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,65 +306,20 @@ public class SDLAudioManager { 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) { + public static void unregisterAudioDeviceCallback() { if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) { - AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback); } } - private static int[] ArrayListToArray(ArrayList 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() { - if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) { - AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - ArrayList arrlist = new ArrayList(); - 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 arrlist = new ArrayList(); - for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) { - arrlist.add(dev.getId()); - } - return ArrayListToArray(arrlist); - } else { - return NO_DEVICES; - } - } - /** * This method is called by SDL using JNI. */ @@ -535,6 +485,6 @@ public class SDLAudioManager { 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 52dc724a86..dd1d2af1b4 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 92bd00a104..777286bf38 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); - } - { - 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); + 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"); } - ctx.AAudioStreamBuilder_setErrorCallback(ctx.builder, AAUDIO_errorCallback, private); + // !!! 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_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 *_this) +static Uint8 *AAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize) { - struct SDL_PrivateAudioData *private = _this->hidden; - return private->mixbuf; + return device->hidden->mixbuf; } -static void AAUDIO_PlayDevice(SDL_AudioDevice *_this) +static void AAUDIO_WaitDevice(SDL_AudioDevice *device) { - 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; + while (!SDL_AtomicGet(&device->shutdown) && ((int) ctx.AAudioStream_getBufferSizeInFrames(stream)) < device->sample_frames) { + SDL_Delay(1); + } +} + +static void AAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) +{ + 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; + SDL_UnloadObject(ctx.handle); + SDL_zero(ctx); + return SDL_FALSE; } - 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; - } - - 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 */ + +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 (device->iscapture) { + // Pause() isn't implemented for 'capture', use Stop() + res = ctx.AAudioStream_requestStop(hidden->stream); + } else { + res = ctx.AAudioStream_requestPause(hidden->stream); + } + + if (res != AAUDIO_OK) { + LOGI("SDL Failed AAudioStream_requestPause %d", res); + SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res)); + } + + SDL_LockMutex(device->lock); + hidden->resume = SDL_TRUE; + } + } + return SDL_FALSE; // keep enumerating. +} + +// 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)); - } - } - - if (SDL_AtomicGet(&audioDevice->paused)) { - /* The device is already paused, leave it alone */ - private->resume = SDL_FALSE; - } else { - SDL_LockMutex(audioDevice->mixer_lock); - SDL_AtomicSet(&audioDevice->paused, 1); - private->resume = SDL_TRUE; - } - } - - 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 (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; - } - } - + if (ctx.handle != NULL) { // AAUDIO driver is used? + (void) SDL_FindPhysicalAudioDeviceByCallback(PauseOneDevice, NULL); } } -/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */ +// 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 (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. +} + void AAUDIO_ResumeDevices(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 = 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 (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)); - } - } - } + 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 res = ctx.AAudioStream_getTimestamp(private->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds); - if (res == AAUDIO_ERROR_INVALID_STATE) { - aaudio_stream_state_t currentState = ctx.AAudioStream_getState(private->stream); - /* AAudioStream_getTimestamp() will also return AAUDIO_ERROR_INVALID_STATE while the stream is still initially starting. But we only care if it silently went invalid while playing. */ - if (currentState == AAUDIO_STREAM_STATE_STARTED) { - LOGI("SDL AAUDIO_DetectBrokenPlayState: detected invalid audio device state: AAudioStream_getTimestamp result=%d, framePosition=%lld, timeNanoseconds=%lld, getState=%d", (int)res, (long long)framePosition, (long long)timeNanoseconds, (int)currentState); - return SDL_TRUE; - } + SDL_assert(device != NULL); + if (!device->iscapture && device->hidden != NULL) { + struct SDL_PrivateAudioData *hidden = device->hidden; + int64_t framePosition, timeNanoseconds; + aaudio_result_t res = ctx.AAudioStream_getTimestamp(hidden->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds); + if (res == AAUDIO_ERROR_INVALID_STATE) { + aaudio_stream_state_t currentState = ctx.AAudioStream_getState(hidden->stream); + // AAudioStream_getTimestamp() will also return AAUDIO_ERROR_INVALID_STATE while the stream is still initially starting. But we only care if it silently went invalid while playing. + if (currentState == AAUDIO_STREAM_STATE_STARTED) { + LOGI("SDL AAUDIO_DetectBrokenPlayState: detected invalid audio device state: AAudioStream_getTimestamp result=%d, framePosition=%lld, timeNanoseconds=%lld, getState=%d", (int)res, (long long)framePosition, (long long)timeNanoseconds, (int)currentState); + return SDL_TRUE; // this guy. } - } - - (void) captureDevice; } - return SDL_FALSE; + return SDL_FALSE; // enumerate more devices. } -#endif /* SDL_AUDIO_DRIVER_AAUDIO */ +SDL_bool AAUDIO_DetectBrokenPlayState(void) +{ + return (ctx.handle && SDL_FindPhysicalAudioDeviceByCallback(DetectBrokenPlayStatePerDevice, NULL) != NULL) ? SDL_TRUE : SDL_FALSE; +} + +#endif // SDL_AUDIO_DRIVER_AAUDIO diff --git a/src/audio/aaudio/SDL_aaudiofuncs.h b/src/audio/aaudio/SDL_aaudiofuncs.h index 1e4e989057..f6e860d6a1 100644 --- a/src/audio/aaudio/SDL_aaudiofuncs.h +++ b/src/audio/aaudio/SDL_aaudiofuncs.h @@ -55,9 +55,9 @@ SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_waitForStateChange, (AAudioStream SDL_PROC(aaudio_result_t, AAudioStream_read, (AAudioStream * stream, void *buffer, int32_t numFrames, int64_t timeoutNanoseconds)) SDL_PROC(aaudio_result_t, AAudioStream_write, (AAudioStream * stream, const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds)) SDL_PROC_UNUSED(aaudio_result_t, AAudioStream_setBufferSizeInFrames, (AAudioStream * stream, int32_t numFrames)) -SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferSizeInFrames, (AAudioStream * stream)) +SDL_PROC(int32_t, AAudioStream_getBufferSizeInFrames, (AAudioStream * stream)) SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerBurst, (AAudioStream * stream)) -SDL_PROC_UNUSED(int32_t, AAudioStream_getBufferCapacityInFrames, (AAudioStream * stream)) +SDL_PROC(int32_t, AAudioStream_getBufferCapacityInFrames, (AAudioStream * stream)) SDL_PROC_UNUSED(int32_t, AAudioStream_getFramesPerDataCallback, (AAudioStream * stream)) SDL_PROC(int32_t, AAudioStream_getXRunCount, (AAudioStream * stream)) SDL_PROC(int32_t, AAudioStream_getSampleRate, (AAudioStream * stream)) diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c index 5f666a278a..7dbb8541af 100644 --- a/src/audio/android/SDL_androidaudio.c +++ b/src/audio/android/SDL_androidaudio.c @@ -22,7 +22,7 @@ #ifdef SDL_AUDIO_DRIVER_ANDROID -/* Output audio to Android */ +// Output audio to Android (legacy interface) #include "../SDL_sysaudio.h" #include "../SDL_audio_c.h" @@ -34,185 +34,157 @@ struct SDL_PrivateAudioData { - /* Resume device if it was paused automatically */ - int resume; + int resume; // Resume device if it was paused automatically }; static SDL_AudioDevice *audioDevice = NULL; static SDL_AudioDevice *captureDevice = NULL; - -static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname) +static int ANDROIDAUDIO_OpenDevice(SDL_AudioDevice *device) { - SDL_AudioFormat test_format; - const SDL_AudioFormat *closefmts; - SDL_bool iscapture = _this->iscapture; + device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden)); + if (device->hidden == NULL) { + return SDL_OutOfMemory(); + } + + const SDL_bool iscapture = device->iscapture; if (iscapture) { if (captureDevice) { return SDL_SetError("An audio capture device is already opened"); } - } - - if (!iscapture) { + captureDevice = device; + } else { if (audioDevice) { return SDL_SetError("An audio playback device is already opened"); } + audioDevice = device; } - if (iscapture) { - captureDevice = _this; - } else { - audioDevice = _this; - } - - _this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden)); - if (_this->hidden == NULL) { - return SDL_OutOfMemory(); - } - - closefmts = SDL_ClosestAudioFormats(_this->spec.format); + SDL_AudioFormat test_format; + const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format); while ((test_format = *(closefmts++)) != 0) { if ((test_format == SDL_AUDIO_U8) || (test_format == SDL_AUDIO_S16) || (test_format == SDL_AUDIO_F32)) { - _this->spec.format = test_format; + device->spec.format = test_format; break; } } if (!test_format) { - /* Didn't find a compatible format :( */ - return SDL_SetError("%s: Unsupported audio format", "android"); + return SDL_SetError("android: Unsupported audio format"); } - { - int audio_device_id = 0; - if (devname != NULL) { - audio_device_id = SDL_atoi(devname); - } - if (Android_JNI_OpenAudioDevice(iscapture, audio_device_id, &_this->spec) < 0) { - return -1; - } + if (Android_JNI_OpenAudioDevice(device) < 0) { + return -1; } - SDL_CalculateAudioSpec(&_this->spec); + SDL_UpdatedAudioDeviceFormat(device); return 0; } -static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *_this) +// !!! FIXME: this needs a WaitDevice implementation. + +static void ANDROIDAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) { Android_JNI_WriteAudioBuffer(); } -static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *_this) +static Uint8 *ANDROIDAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size) { return Android_JNI_GetAudioBuffer(); } -static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen) +static int ANDROIDAUDIO_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen) { return Android_JNI_CaptureAudioBuffer(buffer, buflen); } -static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *_this) +static void ANDROIDAUDIO_FlushCapture(SDL_AudioDevice *device) { Android_JNI_FlushCapturedAudio(); } -static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *_this) +static void ANDROIDAUDIO_CloseDevice(SDL_AudioDevice *device) { /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread so it's safe to terminate the Java side buffer and AudioTrack */ - Android_JNI_CloseAudioDevice(_this->iscapture); - if (_this->iscapture) { - SDL_assert(captureDevice == _this); - captureDevice = NULL; - } else { - SDL_assert(audioDevice == _this); - audioDevice = NULL; + if (device->hidden) { + Android_JNI_CloseAudioDevice(device->iscapture); + if (device->iscapture) { + SDL_assert(captureDevice == device); + captureDevice = NULL; + } else { + SDL_assert(audioDevice == device); + audioDevice = NULL; + } + SDL_free(device->hidden); + device->hidden = NULL; } - SDL_free(_this->hidden); } static SDL_bool ANDROIDAUDIO_Init(SDL_AudioDriverImpl *impl) { - /* Set the function pointers */ - impl->DetectDevices = Android_DetectDevices; + impl->ThreadInit = Android_AudioThreadInit; + impl->DetectDevices = Android_StartAudioHotplug; + impl->Deinitialize = Android_StopAudioHotplug; impl->OpenDevice = ANDROIDAUDIO_OpenDevice; impl->PlayDevice = ANDROIDAUDIO_PlayDevice; impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf; impl->CloseDevice = ANDROIDAUDIO_CloseDevice; impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice; impl->FlushCapture = ANDROIDAUDIO_FlushCapture; - impl->AllowsArbitraryDeviceNames = SDL_TRUE; - /* and the capabilities */ impl->HasCaptureSupport = SDL_TRUE; - impl->OnlyHasDefaultOutputDevice = SDL_FALSE; - impl->OnlyHasDefaultCaptureDevice = SDL_FALSE; - return SDL_TRUE; /* this audio target is available. */ + return SDL_TRUE; } AudioBootStrap ANDROIDAUDIO_bootstrap = { "android", "SDL Android audio driver", ANDROIDAUDIO_Init, SDL_FALSE }; -/* Pause (block) all non already paused audio devices by taking their mixer lock */ +// Pause (block) all non already paused audio devices by taking their mixer lock void ANDROIDAUDIO_PauseDevices(void) { - /* TODO: Handle multiple devices? */ - struct SDL_PrivateAudioData *private; + // TODO: Handle multiple devices? + struct SDL_PrivateAudioData *hidden; if (audioDevice != NULL && audioDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)audioDevice->hidden; - if (SDL_AtomicGet(&audioDevice->paused)) { - /* The device is already paused, leave it alone */ - private->resume = SDL_FALSE; - } else { - SDL_LockMutex(audioDevice->mixer_lock); - SDL_AtomicSet(&audioDevice->paused, 1); - private->resume = SDL_TRUE; - } + hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden; + SDL_LockMutex(audioDevice->lock); + hidden->resume = SDL_TRUE; } if (captureDevice != NULL && captureDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)captureDevice->hidden; - 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; - } + hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden; + SDL_LockMutex(captureDevice->lock); + hidden->resume = SDL_TRUE; } } -/* Resume (unblock) all non already paused audio devices by releasing their mixer lock */ +// Resume (unblock) all non already paused audio devices by releasing their mixer lock void ANDROIDAUDIO_ResumeDevices(void) { - /* TODO: Handle multiple devices? */ - struct SDL_PrivateAudioData *private; + // TODO: Handle multiple devices? + struct SDL_PrivateAudioData *hidden; if (audioDevice != NULL && audioDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)audioDevice->hidden; - if (private->resume) { - SDL_AtomicSet(&audioDevice->paused, 0); - private->resume = SDL_FALSE; - SDL_UnlockMutex(audioDevice->mixer_lock); + hidden = (struct SDL_PrivateAudioData *)audioDevice->hidden; + if (hidden->resume) { + hidden->resume = SDL_FALSE; + SDL_UnlockMutex(audioDevice->lock); } } if (captureDevice != NULL && captureDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)captureDevice->hidden; - if (private->resume) { - SDL_AtomicSet(&captureDevice->paused, 0); - private->resume = SDL_FALSE; - SDL_UnlockMutex(captureDevice->mixer_lock); + hidden = (struct SDL_PrivateAudioData *)captureDevice->hidden; + if (hidden->resume) { + hidden->resume = SDL_FALSE; + SDL_UnlockMutex(captureDevice->lock); } } } -#endif /* SDL_AUDIO_DRIVER_ANDROID */ +#endif // SDL_AUDIO_DRIVER_ANDROID diff --git a/src/audio/openslES/SDL_openslES.c b/src/audio/openslES/SDL_openslES.c index 128fef61e9..37c7dc8cb3 100644 --- a/src/audio/openslES/SDL_openslES.c +++ b/src/audio/openslES/SDL_openslES.c @@ -22,9 +22,8 @@ #ifdef SDL_AUDIO_DRIVER_OPENSLES -/* For more discussion of low latency audio on Android, see this: - https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html -*/ +// For more discussion of low latency audio on Android, see this: +// https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html #include "../SDL_sysaudio.h" #include "../SDL_audio_c.h" @@ -36,7 +35,7 @@ #include -#define NUM_BUFFERS 2 /* -- Don't lower this! */ +#define NUM_BUFFERS 2 // -- Don't lower this! struct SDL_PrivateAudioData { @@ -83,14 +82,14 @@ struct SDL_PrivateAudioData #define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY) #define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT) -/* engine interfaces */ +// engine interfaces static SLObjectItf engineObject = NULL; static SLEngineItf engineEngine = NULL; -/* output mix interfaces */ +// output mix interfaces static SLObjectItf outputMixObject = NULL; -/* buffer queue player interfaces */ +// buffer queue player interfaces static SLObjectItf bqPlayerObject = NULL; static SLPlayItf bqPlayerPlay = NULL; static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL; @@ -98,7 +97,7 @@ static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue = NULL; static SLVolumeItf bqPlayerVolume; #endif -/* recorder interfaces */ +// recorder interfaces static SLObjectItf recorderObject = NULL; static SLRecordItf recorderRecord = NULL; static SLAndroidSimpleBufferQueueItf recorderBufferQueue = NULL; @@ -123,13 +122,13 @@ static void openslES_DestroyEngine(void) { LOGI("openslES_DestroyEngine()"); - /* destroy output mix object, and invalidate all associated interfaces */ + // destroy output mix object, and invalidate all associated interfaces if (outputMixObject != NULL) { (*outputMixObject)->Destroy(outputMixObject); outputMixObject = NULL; } - /* destroy engine object, and invalidate all associated interfaces */ + // destroy engine object, and invalidate all associated interfaces if (engineObject != NULL) { (*engineObject)->Destroy(engineObject); engineObject = NULL; @@ -145,7 +144,7 @@ static int openslES_CreateEngine(void) LOGI("openSLES_CreateEngine()"); - /* create engine */ + // create engine result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL); if (SL_RESULT_SUCCESS != result) { LOGE("slCreateEngine failed: %d", result); @@ -153,7 +152,7 @@ static int openslES_CreateEngine(void) } LOGI("slCreateEngine OK"); - /* realize the engine */ + // realize the engine result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { LOGE("RealizeEngine failed: %d", result); @@ -161,7 +160,7 @@ static int openslES_CreateEngine(void) } LOGI("RealizeEngine OK"); - /* get the engine interface, which is needed in order to create other objects */ + // get the engine interface, which is needed in order to create other objects result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); if (SL_RESULT_SUCCESS != result) { LOGE("EngineGetInterface failed: %d", result); @@ -169,7 +168,7 @@ static int openslES_CreateEngine(void) } LOGI("EngineGetInterface OK"); - /* create output mix */ + // create output mix result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req); if (SL_RESULT_SUCCESS != result) { LOGE("CreateOutputMix failed: %d", result); @@ -177,7 +176,7 @@ static int openslES_CreateEngine(void) } LOGI("CreateOutputMix OK"); - /* realize the output mix */ + // realize the output mix result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { LOGE("RealizeOutputMix failed: %d", result); @@ -190,7 +189,7 @@ error: return 0; } -/* this callback handler is called every time a buffer finishes recording */ +// this callback handler is called every time a buffer finishes recording static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *)context; @@ -199,12 +198,12 @@ static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context) SDL_PostSemaphore(audiodata->playsem); } -static void openslES_DestroyPCMRecorder(SDL_AudioDevice *_this) +static void openslES_DestroyPCMRecorder(SDL_AudioDevice *device) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; + struct SDL_PrivateAudioData *audiodata = device->hidden; SLresult result; - /* stop recording */ + // stop recording if (recorderRecord != NULL) { result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); if (SL_RESULT_SUCCESS != result) { @@ -212,7 +211,7 @@ static void openslES_DestroyPCMRecorder(SDL_AudioDevice *_this) } } - /* destroy audio recorder object, and invalidate all associated interfaces */ + // destroy audio recorder object, and invalidate all associated interfaces if (recorderObject != NULL) { (*recorderObject)->Destroy(recorderObject); recorderObject = NULL; @@ -230,9 +229,9 @@ static void openslES_DestroyPCMRecorder(SDL_AudioDevice *_this) } } -static int openslES_CreatePCMRecorder(SDL_AudioDevice *_this) +static int openslES_CreatePCMRecorder(SDL_AudioDevice *device) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; + struct SDL_PrivateAudioData *audiodata = device->hidden; SLDataFormat_PCM format_pcm; SLDataLocator_AndroidSimpleBufferQueue loc_bufq; SLDataSink audioSnk; @@ -248,19 +247,19 @@ static int openslES_CreatePCMRecorder(SDL_AudioDevice *_this) return SDL_SetError("This app doesn't have RECORD_AUDIO permission"); } - /* Just go with signed 16-bit audio as it's the most compatible */ - _this->spec.format = SDL_AUDIO_S16SYS; - _this->spec.channels = 1; - /*_this->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/ + // Just go with signed 16-bit audio as it's the most compatible + device->spec.format = SDL_AUDIO_S16SYS; + device->spec.channels = 1; + //device->spec.freq = SL_SAMPLINGRATE_16 / 1000;*/ - /* Update the fragment size as size in bytes */ - SDL_CalculateAudioSpec(&_this->spec); + // Update the fragment size as size in bytes + SDL_UpdatedAudioDeviceFormat(device); LOGI("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); - /* configure audio source */ + // configure audio source loc_dev.locatorType = SL_DATALOCATOR_IODEVICE; loc_dev.deviceType = SL_IODEVICE_AUDIOINPUT; loc_dev.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; @@ -268,93 +267,93 @@ static int openslES_CreatePCMRecorder(SDL_AudioDevice *_this) audioSrc.pLocator = &loc_dev; audioSrc.pFormat = NULL; - /* configure audio sink */ + // configure audio sink loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bufq.numBuffers = NUM_BUFFERS; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = _this->spec.channels; - format_pcm.samplesPerSec = _this->spec.freq * 1000; /* / kilo Hz to milli Hz */ - format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format); - format_pcm.containerSize = SDL_AUDIO_BITSIZE(_this->spec.format); + format_pcm.numChannels = device->spec.channels; + format_pcm.samplesPerSec = device->spec.freq * 1000; // / kilo Hz to milli Hz + format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(device->spec.format); + format_pcm.containerSize = SDL_AUDIO_BITSIZE(device->spec.format); format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER; audioSnk.pLocator = &loc_bufq; audioSnk.pFormat = &format_pcm; - /* create audio recorder */ - /* (requires the RECORD_AUDIO permission) */ + // create audio recorder + // (requires the RECORD_AUDIO permission) result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc, &audioSnk, 1, ids, req); if (SL_RESULT_SUCCESS != result) { LOGE("CreateAudioRecorder failed: %d", result); goto failed; } - /* realize the recorder */ + // realize the recorder result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { LOGE("RealizeAudioPlayer failed: %d", result); goto failed; } - /* get the record interface */ + // get the record interface result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord); if (SL_RESULT_SUCCESS != result) { LOGE("SL_IID_RECORD interface get failed: %d", result); goto failed; } - /* get the buffer queue interface */ + // get the buffer queue interface result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &recorderBufferQueue); if (SL_RESULT_SUCCESS != result) { LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result); goto failed; } - /* register callback on the buffer queue */ - /* context is '(SDL_PrivateAudioData *)_this->hidden' */ - result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, _this->hidden); + // register callback on the buffer queue + // context is '(SDL_PrivateAudioData *)device->hidden' + result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, bqRecorderCallback, device->hidden); if (SL_RESULT_SUCCESS != result) { LOGE("RegisterCallback failed: %d", result); goto failed; } - /* Create the audio buffer semaphore */ + // Create the audio buffer semaphore audiodata->playsem = SDL_CreateSemaphore(0); if (!audiodata->playsem) { LOGE("cannot create Semaphore!"); goto failed; } - /* Create the sound buffers */ - audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * _this->spec.size); + // Create the sound buffers + audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * device->buffer_size); if (audiodata->mixbuff == NULL) { LOGE("mixbuffer allocate - out of memory"); goto failed; } for (i = 0; i < NUM_BUFFERS; i++) { - audiodata->pmixbuff[i] = audiodata->mixbuff + i * _this->spec.size; + audiodata->pmixbuff[i] = audiodata->mixbuff + i * device->buffer_size; } - /* in case already recording, stop recording and clear buffer queue */ + // in case already recording, stop recording and clear buffer queue result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); if (SL_RESULT_SUCCESS != result) { LOGE("Record set state failed: %d", result); goto failed; } - /* enqueue empty buffers to be filled by the recorder */ + // enqueue empty buffers to be filled by the recorder for (i = 0; i < NUM_BUFFERS; i++) { - result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], _this->spec.size); + result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[i], device->buffer_size); if (SL_RESULT_SUCCESS != result) { LOGE("Record enqueue buffers failed: %d", result); goto failed; } } - /* start recording */ + // start recording result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING); if (SL_RESULT_SUCCESS != result) { LOGE("Record set state failed: %d", result); @@ -367,7 +366,7 @@ failed: return SDL_SetError("Open device failed!"); } -/* this callback handler is called every time a buffer finishes playing */ +// this callback handler is called every time a buffer finishes playing static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { struct SDL_PrivateAudioData *audiodata = (struct SDL_PrivateAudioData *)context; @@ -376,20 +375,19 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) SDL_PostSemaphore(audiodata->playsem); } -static void openslES_DestroyPCMPlayer(SDL_AudioDevice *_this) +static void openslES_DestroyPCMPlayer(SDL_AudioDevice *device) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; - SLresult result; + struct SDL_PrivateAudioData *audiodata = device->hidden; - /* set the player's state to 'stopped' */ + // set the player's state to 'stopped' if (bqPlayerPlay != NULL) { - result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); + const SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); if (SL_RESULT_SUCCESS != result) { LOGE("SetPlayState stopped failed: %d", result); } } - /* destroy buffer queue audio player object, and invalidate all associated interfaces */ + // destroy buffer queue audio player object, and invalidate all associated interfaces if (bqPlayerObject != NULL) { (*bqPlayerObject)->Destroy(bqPlayerObject); @@ -408,26 +406,14 @@ static void openslES_DestroyPCMPlayer(SDL_AudioDevice *_this) } } -static int openslES_CreatePCMPlayer(SDL_AudioDevice *_this) +static int openslES_CreatePCMPlayer(SDL_AudioDevice *device) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataFormat_PCM format_pcm; - SLAndroidDataFormat_PCM_EX format_pcm_ex; - SLDataSource audioSrc; - SLDataSink audioSnk; - SLDataLocator_OutputMix loc_outmix; - const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME }; - const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; - SLresult result; - int i; - /* If we want to add floating point audio support (requires API level 21) it can be done as described here: https://developer.android.com/ndk/guides/audio/opensl/android-extensions.html#floating-point */ if (SDL_GetAndroidSDKVersion() >= 21) { - const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(_this->spec.format); + const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format); SDL_AudioFormat test_format; while ((test_format = *(closefmts++)) != 0) { if (SDL_AUDIO_ISSIGNED(test_format)) { @@ -436,40 +422,42 @@ static int openslES_CreatePCMPlayer(SDL_AudioDevice *_this) } if (!test_format) { - /* Didn't find a compatible format : */ + // Didn't find a compatible format : LOGI("No compatible audio format, using signed 16-bit audio"); test_format = SDL_AUDIO_S16SYS; } - _this->spec.format = test_format; + device->spec.format = test_format; } else { - /* Just go with signed 16-bit audio as it's the most compatible */ - _this->spec.format = SDL_AUDIO_S16SYS; + // Just go with signed 16-bit audio as it's the most compatible + device->spec.format = SDL_AUDIO_S16SYS; } - /* Update the fragment size as size in bytes */ - SDL_CalculateAudioSpec(&_this->spec); + // Update the fragment size as size in bytes + SDL_UpdatedAudioDeviceFormat(device); LOGI("Try to open %u hz %s %u bit chan %u %s samples %u", - _this->spec.freq, SDL_AUDIO_ISFLOAT(_this->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(_this->spec.format), - _this->spec.channels, (_this->spec.format & 0x1000) ? "BE" : "LE", _this->spec.samples); + device->spec.freq, SDL_AUDIO_ISFLOAT(device->spec.format) ? "float" : "pcm", SDL_AUDIO_BITSIZE(device->spec.format), + device->spec.channels, (device->spec.format & 0x1000) ? "BE" : "LE", device->sample_frames); - /* configure audio source */ + // configure audio source + SLDataLocator_AndroidSimpleBufferQueue loc_bufq; loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; loc_bufq.numBuffers = NUM_BUFFERS; + SLDataFormat_PCM format_pcm; format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = _this->spec.channels; - format_pcm.samplesPerSec = _this->spec.freq * 1000; /* / kilo Hz to milli Hz */ - format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(_this->spec.format); - format_pcm.containerSize = SDL_AUDIO_BITSIZE(_this->spec.format); + format_pcm.numChannels = device->spec.channels; + format_pcm.samplesPerSec = device->spec.freq * 1000; // / kilo Hz to milli Hz + format_pcm.bitsPerSample = SDL_AUDIO_BITSIZE(device->spec.format); + format_pcm.containerSize = SDL_AUDIO_BITSIZE(device->spec.format); - if (SDL_AUDIO_ISBIGENDIAN(_this->spec.format)) { + if (SDL_AUDIO_ISBIGENDIAN(device->spec.format)) { format_pcm.endianness = SL_BYTEORDER_BIGENDIAN; } else { format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; } - switch (_this->spec.channels) { + switch (device->spec.channels) { case 1: format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT; break; @@ -495,14 +483,19 @@ static int openslES_CreatePCMPlayer(SDL_AudioDevice *_this) format_pcm.channelMask = SL_ANDROID_SPEAKER_7DOT1; break; default: - /* Unknown number of channels, fall back to stereo */ - _this->spec.channels = 2; + // Unknown number of channels, fall back to stereo + device->spec.channels = 2; format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; break; } - if (SDL_AUDIO_ISFLOAT(_this->spec.format)) { - /* Copy all setup into PCM EX structure */ + SLDataSink audioSnk; + SLDataSource audioSrc; + audioSrc.pFormat = (void *)&format_pcm; + + SLAndroidDataFormat_PCM_EX format_pcm_ex; + if (SDL_AUDIO_ISFLOAT(device->spec.format)) { + // Copy all setup into PCM EX structure format_pcm_ex.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; format_pcm_ex.endianness = format_pcm.endianness; format_pcm_ex.channelMask = format_pcm.channelMask; @@ -511,81 +504,87 @@ static int openslES_CreatePCMPlayer(SDL_AudioDevice *_this) format_pcm_ex.bitsPerSample = format_pcm.bitsPerSample; format_pcm_ex.containerSize = format_pcm.containerSize; format_pcm_ex.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; + audioSrc.pFormat = (void *)&format_pcm_ex; } audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = SDL_AUDIO_ISFLOAT(_this->spec.format) ? (void *)&format_pcm_ex : (void *)&format_pcm; - /* configure audio sink */ + // configure audio sink + SLDataLocator_OutputMix loc_outmix; loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; loc_outmix.outputMix = outputMixObject; audioSnk.pLocator = &loc_outmix; audioSnk.pFormat = NULL; - /* create audio player */ + // create audio player + const SLInterfaceID ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME }; + const SLboolean req[2] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_FALSE }; + SLresult result; result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); if (SL_RESULT_SUCCESS != result) { LOGE("CreateAudioPlayer failed: %d", result); goto failed; } - /* realize the player */ + // realize the player result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); if (SL_RESULT_SUCCESS != result) { LOGE("RealizeAudioPlayer failed: %d", result); goto failed; } - /* get the play interface */ + // get the play interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); if (SL_RESULT_SUCCESS != result) { LOGE("SL_IID_PLAY interface get failed: %d", result); goto failed; } - /* get the buffer queue interface */ + // get the buffer queue interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &bqPlayerBufferQueue); if (SL_RESULT_SUCCESS != result) { LOGE("SL_IID_BUFFERQUEUE interface get failed: %d", result); goto failed; } - /* register callback on the buffer queue */ - /* context is '(SDL_PrivateAudioData *)_this->hidden' */ - result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, _this->hidden); + // register callback on the buffer queue + // context is '(SDL_PrivateAudioData *)device->hidden' + result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, device->hidden); if (SL_RESULT_SUCCESS != result) { LOGE("RegisterCallback failed: %d", result); goto failed; } #if 0 - /* get the volume interface */ + // get the volume interface result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume); if (SL_RESULT_SUCCESS != result) { LOGE("SL_IID_VOLUME interface get failed: %d", result); - /* goto failed; */ + // goto failed; } #endif - /* Create the audio buffer semaphore */ + struct SDL_PrivateAudioData *audiodata = device->hidden; + + // Create the audio buffer semaphore audiodata->playsem = SDL_CreateSemaphore(NUM_BUFFERS - 1); if (!audiodata->playsem) { LOGE("cannot create Semaphore!"); goto failed; } - /* Create the sound buffers */ - audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * _this->spec.size); + // Create the sound buffers + audiodata->mixbuff = (Uint8 *)SDL_malloc(NUM_BUFFERS * device->buffer_size); if (audiodata->mixbuff == NULL) { LOGE("mixbuffer allocate - out of memory"); goto failed; } - for (i = 0; i < NUM_BUFFERS; i++) { - audiodata->pmixbuff[i] = audiodata->mixbuff + i * _this->spec.size; + for (int i = 0; i < NUM_BUFFERS; i++) { + audiodata->pmixbuff[i] = audiodata->mixbuff + i * device->buffer_size; } - /* set the player's state to playing */ + // set the player's state to playing result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); if (SL_RESULT_SUCCESS != result) { LOGE("Play set state failed: %d", result); @@ -598,103 +597,98 @@ failed: return -1; } -static int openslES_OpenDevice(SDL_AudioDevice *_this, const char *devname) +static int openslES_OpenDevice(SDL_AudioDevice *device) { - _this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden)); - if (_this->hidden == NULL) { + device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden)); + if (device->hidden == NULL) { return SDL_OutOfMemory(); } - if (_this->iscapture) { - LOGI("openslES_OpenDevice() %s for capture", devname); - return openslES_CreatePCMRecorder(_this); + if (device->iscapture) { + LOGI("openslES_OpenDevice() for capture"); + return openslES_CreatePCMRecorder(device); } else { int ret; - LOGI("openslES_OpenDevice() %s for playing", devname); - ret = openslES_CreatePCMPlayer(_this); + LOGI("openslES_OpenDevice() for playing"); + ret = openslES_CreatePCMPlayer(device); if (ret < 0) { - /* Another attempt to open the device with a lower frequency */ - if (_this->spec.freq > 48000) { - openslES_DestroyPCMPlayer(_this); - _this->spec.freq = 48000; - ret = openslES_CreatePCMPlayer(_this); + // Another attempt to open the device with a lower frequency + if (device->spec.freq > 48000) { + openslES_DestroyPCMPlayer(device); + device->spec.freq = 48000; + ret = openslES_CreatePCMPlayer(device); } } - if (ret == 0) { - return 0; - } else { + if (ret != 0) { return SDL_SetError("Open device failed!"); } } + + return 0; } -static void openslES_WaitDevice(SDL_AudioDevice *_this) +static void openslES_WaitDevice(SDL_AudioDevice *device) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; + struct SDL_PrivateAudioData *audiodata = device->hidden; LOGV("openslES_WaitDevice()"); - /* Wait for an audio chunk to finish */ + // Wait for an audio chunk to finish SDL_WaitSemaphore(audiodata->playsem); } -static void openslES_PlayDevice(SDL_AudioDevice *_this) +static void openslES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; - SLresult result; + struct SDL_PrivateAudioData *audiodata = device->hidden; LOGV("======openslES_PlayDevice()======"); - /* Queue it up */ - result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size); + // Queue it up + const SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer, buflen); audiodata->next_buffer++; if (audiodata->next_buffer >= NUM_BUFFERS) { audiodata->next_buffer = 0; } - /* If Enqueue fails, callback won't be called. - * Post the semaphore, not to run out of buffer */ + // If Enqueue fails, callback won't be called. + // Post the semaphore, not to run out of buffer if (SL_RESULT_SUCCESS != result) { SDL_PostSemaphore(audiodata->playsem); } } -/*/ n playn sem */ -/* getbuf 0 - 1 */ -/* fill buff 0 - 1 */ -/* play 0 - 0 1 */ -/* wait 1 0 0 */ -/* getbuf 1 0 0 */ -/* fill buff 1 0 0 */ -/* play 0 0 0 */ -/* wait */ -/* */ -/* okay.. */ +/// n playn sem +// getbuf 0 - 1 +// fill buff 0 - 1 +// play 0 - 0 1 +// wait 1 0 0 +// getbuf 1 0 0 +// fill buff 1 0 0 +// play 0 0 0 +// wait +// +// okay.. -static Uint8 *openslES_GetDeviceBuf(SDL_AudioDevice *_this) +static Uint8 *openslES_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; + struct SDL_PrivateAudioData *audiodata = device->hidden; LOGV("openslES_GetDeviceBuf()"); return audiodata->pmixbuff[audiodata->next_buffer]; } -static int openslES_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen) +static int openslES_CaptureFromDevice(SDL_AudioDevice *device, void *buffer, int buflen) { - struct SDL_PrivateAudioData *audiodata = _this->hidden; - SLresult result; + struct SDL_PrivateAudioData *audiodata = device->hidden; - /* Wait for new recorded data */ - SDL_WaitSemaphore(audiodata->playsem); + // Copy it to the output buffer + SDL_assert(buflen == device->buffer_size); + SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], device->buffer_size); - /* Copy it to the output buffer */ - SDL_assert(buflen == _this->spec.size); - SDL_memcpy(buffer, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size); - - /* Re-enqueue the buffer */ - result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], _this->spec.size); + // Re-enqueue the buffer + const SLresult result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, audiodata->pmixbuff[audiodata->next_buffer], device->buffer_size); if (SL_RESULT_SUCCESS != result) { LOGE("Record enqueue buffers failed: %d", result); return -1; @@ -705,22 +699,24 @@ static int openslES_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int audiodata->next_buffer = 0; } - return _this->spec.size; + return device->buffer_size; } -static void openslES_CloseDevice(SDL_AudioDevice *_this) +static void openslES_CloseDevice(SDL_AudioDevice *device) { - /* struct SDL_PrivateAudioData *audiodata = _this->hidden; */ + // struct SDL_PrivateAudioData *audiodata = device->hidden; + if (device->hidden) { + if (device->iscapture) { + LOGI("openslES_CloseDevice() for capture"); + openslES_DestroyPCMRecorder(device); + } else { + LOGI("openslES_CloseDevice() for playing"); + openslES_DestroyPCMPlayer(device); + } - if (_this->iscapture) { - LOGI("openslES_CloseDevice() for capture"); - openslES_DestroyPCMRecorder(_this); - } else { - LOGI("openslES_CloseDevice() for playing"); - openslES_DestroyPCMPlayer(_this); + SDL_free(device->hidden); + device->hidden = NULL; } - - SDL_free(_this->hidden); } static SDL_bool openslES_Init(SDL_AudioDriverImpl *impl) @@ -733,24 +729,26 @@ static SDL_bool openslES_Init(SDL_AudioDriverImpl *impl) LOGI("openslES_Init() - set pointers"); - /* Set the function pointers */ - /* impl->DetectDevices = openslES_DetectDevices; */ + // Set the function pointers + // impl->DetectDevices = openslES_DetectDevices; + impl->ThreadInit = Android_AudioThreadInit; impl->OpenDevice = openslES_OpenDevice; impl->WaitDevice = openslES_WaitDevice; impl->PlayDevice = openslES_PlayDevice; impl->GetDeviceBuf = openslES_GetDeviceBuf; + impl->WaitCaptureDevice = openslES_WaitDevice; impl->CaptureFromDevice = openslES_CaptureFromDevice; impl->CloseDevice = openslES_CloseDevice; impl->Deinitialize = openslES_DestroyEngine; - /* and the capabilities */ + // and the capabilities impl->HasCaptureSupport = SDL_TRUE; impl->OnlyHasDefaultOutputDevice = SDL_TRUE; impl->OnlyHasDefaultCaptureDevice = SDL_TRUE; LOGI("openslES_Init() - success"); - /* this audio target is available. */ + // this audio target is available. return SDL_TRUE; } @@ -761,7 +759,7 @@ AudioBootStrap openslES_bootstrap = { void openslES_ResumeDevices(void) { if (bqPlayerPlay != NULL) { - /* set the player's state to 'playing' */ + // set the player's state to 'playing' SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); if (SL_RESULT_SUCCESS != result) { LOGE("openslES_ResumeDevices failed: %d", result); @@ -772,7 +770,7 @@ void openslES_ResumeDevices(void) void openslES_PauseDevices(void) { if (bqPlayerPlay != NULL) { - /* set the player's state to 'paused' */ + // set the player's state to 'paused' SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED); if (SL_RESULT_SUCCESS != result) { LOGE("openslES_PauseDevices failed: %d", result); @@ -780,4 +778,4 @@ void openslES_PauseDevices(void) } } -#endif /* SDL_AUDIO_DRIVER_OPENSLES */ +#endif // SDL_AUDIO_DRIVER_OPENSLES diff --git a/src/audio/wasapi/SDL_wasapi_win32.c b/src/audio/wasapi/SDL_wasapi_win32.c index 75862371c4..719ac94a3b 100644 --- a/src/audio/wasapi/SDL_wasapi_win32.c +++ b/src/audio/wasapi/SDL_wasapi_win32.c @@ -86,7 +86,10 @@ void WASAPI_PlatformThreadInit(SDL_AudioDevice *device) if (pAvSetMmThreadCharacteristicsW) { DWORD idx = 0; device->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx); + } else { + SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL); } + } void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device) diff --git a/src/audio/wasapi/SDL_wasapi_winrt.cpp b/src/audio/wasapi/SDL_wasapi_winrt.cpp index 373244ac73..a4030f39c2 100644 --- a/src/audio/wasapi/SDL_wasapi_winrt.cpp +++ b/src/audio/wasapi/SDL_wasapi_winrt.cpp @@ -334,6 +334,7 @@ int WASAPI_ActivateDevice(SDL_AudioDevice *device) void WASAPI_PlatformThreadInit(SDL_AudioDevice *device) { // !!! FIXME: set this thread to "Pro Audio" priority. + SDL_SetThreadPriority(device->iscapture ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL); } void WASAPI_PlatformThreadDeinit(SDL_AudioDevice *device) diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 1d3909b693..ad71d3d644 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -233,7 +233,7 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)( JNIEnv *env, jclass jcls); JNIEXPORT void JNICALL - SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture, + SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture, jstring name, jint device_id); JNIEXPORT void JNICALL @@ -242,7 +242,7 @@ JNIEXPORT void JNICALL static JNINativeMethod SDLAudioManager_tab[] = { { "nativeSetupJNI", "()I", SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI) }, - { "addAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(addAudioDevice) }, + { "addAudioDevice", "(ZLjava/lang/String;I)V", SDL_JAVA_AUDIO_INTERFACE(addAudioDevice) }, { "removeAudioDevice", "(ZI)V", SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice) } }; @@ -350,8 +350,8 @@ static jmethodID midSupportsRelativeMouse; static jclass mAudioManagerClass; /* method signatures */ -static jmethodID midGetAudioOutputDevices; -static jmethodID midGetAudioInputDevices; +static jmethodID midRegisterAudioDeviceCallback; +static jmethodID midUnregisterAudioDeviceCallback; static jmethodID midAudioOpen; static jmethodID midAudioWriteByteBuffer; static jmethodID midAudioWriteShortBuffer; @@ -681,12 +681,12 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl mAudioManagerClass = (jclass)((*env)->NewGlobalRef(env, cls)); - midGetAudioOutputDevices = (*env)->GetStaticMethodID(env, mAudioManagerClass, - "getAudioOutputDevices", - "()[I"); - midGetAudioInputDevices = (*env)->GetStaticMethodID(env, mAudioManagerClass, - "getAudioInputDevices", - "()[I"); + midRegisterAudioDeviceCallback = (*env)->GetStaticMethodID(env, mAudioManagerClass, + "registerAudioDeviceCallback", + "()V"); + midUnregisterAudioDeviceCallback = (*env)->GetStaticMethodID(env, mAudioManagerClass, + "unregisterAudioDeviceCallback", + "()V"); midAudioOpen = (*env)->GetStaticMethodID(env, mAudioManagerClass, "audioOpen", "(IIIII)[I"); midAudioWriteByteBuffer = (*env)->GetStaticMethodID(env, mAudioManagerClass, @@ -710,7 +710,7 @@ JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv *env, jcl midAudioSetThreadPriority = (*env)->GetStaticMethodID(env, mAudioManagerClass, "audioSetThreadPriority", "(ZI)V"); - if (!midGetAudioOutputDevices || !midGetAudioInputDevices || !midAudioOpen || + if (!midRegisterAudioDeviceCallback || !midUnregisterAudioDeviceCallback || !midAudioOpen || !midAudioWriteByteBuffer || !midAudioWriteShortBuffer || !midAudioWriteFloatBuffer || !midAudioClose || !midCaptureOpen || !midCaptureReadByteBuffer || !midCaptureReadShortBuffer || @@ -1002,19 +1002,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativePermissionResult)( SDL_AtomicSet(&bPermissionRequestPending, SDL_FALSE); } -extern void SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, SDL_AudioSpec *spec, void *handle); -extern void SDL_RemoveAudioDevice(const SDL_bool iscapture, void *handle); - JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(addAudioDevice)(JNIEnv *env, jclass jcls, jboolean is_capture, - jint device_id) + jstring name, jint device_id) { - if (SDL_GetCurrentAudioDriver() != NULL) { - char device_name[64]; - SDL_snprintf(device_name, sizeof(device_name), "%d", device_id); - SDL_Log("Adding device with name %s, capture %d", device_name, is_capture); - SDL_AddAudioDevice(is_capture, SDL_strdup(device_name), NULL, (void *)((size_t)device_id + 1)); - } + SDL_assert(SDL_GetCurrentAudioDriver() != NULL); // should have been started by Android_StartAudioHotplug inside an audio driver. + const char *utf8name = (*env)->GetStringUTFChars(env, name, NULL); + SDL_AddAudioDevice(is_capture ? SDL_TRUE : SDL_FALSE, SDL_strdup(utf8name), NULL, (void *)((size_t)device_id)); + (*env)->ReleaseStringUTFChars(env, name, utf8name); } JNIEXPORT void JNICALL @@ -1022,8 +1017,8 @@ SDL_JAVA_AUDIO_INTERFACE(removeAudioDevice)(JNIEnv *env, jclass jcls, jboolean i jint device_id) { if (SDL_GetCurrentAudioDriver() != NULL) { - SDL_Log("Removing device with handle %d, capture %d", device_id + 1, is_capture); - SDL_RemoveAudioDevice(is_capture, (void *)((size_t)device_id + 1)); + SDL_Log("Removing device with handle %d, capture %d", device_id, is_capture); + SDL_AudioDeviceDisconnected(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)device_id))); } } @@ -1564,58 +1559,25 @@ static void *audioBufferPinned = NULL; static int captureBufferFormat = 0; static jobject captureBuffer = NULL; -static void Android_JNI_GetAudioDevices(int *devices, int *length, int max_len, int is_input) +void Android_StartAudioHotplug(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture) { JNIEnv *env = Android_JNI_GetEnv(); - jintArray result; - - if (is_input) { - result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midGetAudioInputDevices); - } else { - result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midGetAudioOutputDevices); - } - - *length = (*env)->GetArrayLength(env, result); - - *length = SDL_min(*length, max_len); - - (*env)->GetIntArrayRegion(env, result, 0, *length, devices); + // this will fire the callback for each existing device right away (which will eventually SDL_AddAudioDevice), and again later when things change. + (void) (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midRegisterAudioDeviceCallback); + *default_output = *default_capture = NULL; // !!! FIXME: how do you decide the default device id? } -void Android_DetectDevices(void) +void Android_StopAudioHotplug(void) { - int inputs[100]; - int outputs[100]; - int inputs_length = 0; - int outputs_length = 0; - - SDL_zeroa(inputs); - - Android_JNI_GetAudioDevices(inputs, &inputs_length, 100, 1 /* input devices */); - - for (int i = 0; i < inputs_length; ++i) { - int device_id = inputs[i]; - char device_name[64]; - SDL_snprintf(device_name, sizeof(device_name), "%d", device_id); - SDL_Log("Adding input device with name %s", device_name); - SDL_AddAudioDevice(SDL_TRUE, SDL_strdup(device_name), NULL, (void *)((size_t)device_id + 1)); - } - - SDL_zeroa(outputs); - - Android_JNI_GetAudioDevices(outputs, &outputs_length, 100, 0 /* output devices */); - - for (int i = 0; i < outputs_length; ++i) { - int device_id = outputs[i]; - char device_name[64]; - SDL_snprintf(device_name, sizeof(device_name), "%d", device_id); - SDL_Log("Adding output device with name %s", device_name); - SDL_AddAudioDevice(SDL_FALSE, SDL_strdup(device_name), NULL, (void *)((size_t)device_id + 1)); - } + JNIEnv *env = Android_JNI_GetEnv(); + (void) (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midUnregisterAudioDeviceCallback); } -int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spec) +int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device) { + const SDL_bool iscapture = device->iscapture; + SDL_AudioSpec *spec = &device->spec; + const int device_id = (int) ((size_t) device->handle); int audioformat; jobject jbufobj = NULL; jobject result; @@ -1640,10 +1602,10 @@ int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spe if (iscapture) { __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture"); - result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midCaptureOpen, spec->freq, audioformat, spec->channels, spec->samples, device_id); + result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midCaptureOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id); } else { __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output"); - result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, spec->samples, device_id); + result = (*env)->CallStaticObjectMethod(env, mAudioManagerClass, midAudioOpen, spec->freq, audioformat, spec->channels, device->sample_frames, device_id); } if (result == NULL) { /* Error during audio initialization, error printed from Java */ @@ -1668,10 +1630,10 @@ int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spe spec->format = SDL_AUDIO_F32; break; default: - return SDL_SetError("Unexpected audio format from Java: %d\n", audioformat); + return SDL_SetError("Unexpected audio format from Java: %d", audioformat); } spec->channels = resultElements[2]; - spec->samples = resultElements[3]; + device->sample_frames = resultElements[3]; (*env)->ReleaseIntArrayElements(env, (jintArray)result, resultElements, JNI_ABORT); (*env)->DeleteLocalRef(env, result); @@ -1680,7 +1642,7 @@ int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spe switch (audioformat) { case ENCODING_PCM_8BIT: { - jbyteArray audioBufferLocal = (*env)->NewByteArray(env, spec->samples * spec->channels); + jbyteArray audioBufferLocal = (*env)->NewByteArray(env, device->sample_frames * spec->channels); if (audioBufferLocal) { jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal); (*env)->DeleteLocalRef(env, audioBufferLocal); @@ -1688,7 +1650,7 @@ int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spe } break; case ENCODING_PCM_16BIT: { - jshortArray audioBufferLocal = (*env)->NewShortArray(env, spec->samples * spec->channels); + jshortArray audioBufferLocal = (*env)->NewShortArray(env, device->sample_frames * spec->channels); if (audioBufferLocal) { jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal); (*env)->DeleteLocalRef(env, audioBufferLocal); @@ -1696,7 +1658,7 @@ int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spe } break; case ENCODING_PCM_FLOAT: { - jfloatArray audioBufferLocal = (*env)->NewFloatArray(env, spec->samples * spec->channels); + jfloatArray audioBufferLocal = (*env)->NewFloatArray(env, device->sample_frames * spec->channels); if (audioBufferLocal) { jbufobj = (*env)->NewGlobalRef(env, audioBufferLocal); (*env)->DeleteLocalRef(env, audioBufferLocal); @@ -1887,12 +1849,17 @@ void Android_JNI_CloseAudioDevice(const int iscapture) } } -void Android_JNI_AudioSetThreadPriority(int iscapture, int device_id) +static void Android_JNI_AudioSetThreadPriority(int iscapture, int device_id) { JNIEnv *env = Android_JNI_GetEnv(); (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioSetThreadPriority, iscapture, device_id); } +void Android_AudioThreadInit(SDL_AudioDevice *device) +{ + Android_JNI_AudioSetThreadPriority((int) device->iscapture, (int)device->instance_id); +} + /* Test for an exception and call SDL_SetError with its detail if one occurs */ /* If the parameter silent is truthy then SDL_SetError() will not be called. */ static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent) diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index a245af9800..be9b3d2bd5 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -30,6 +30,8 @@ extern "C" { #include #include +#include "../../audio/SDL_sysaudio.h" + /* Interface from the SDL library into the Android Java activity */ extern void Android_JNI_SetActivityTitle(const char *title); extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen); @@ -47,14 +49,15 @@ extern SDL_DisplayOrientation Android_JNI_GetDisplayNaturalOrientation(void); extern SDL_DisplayOrientation Android_JNI_GetDisplayCurrentOrientation(void); /* Audio support */ -extern void Android_DetectDevices(void); -extern int Android_JNI_OpenAudioDevice(int iscapture, int device_id, SDL_AudioSpec *spec); +void Android_StartAudioHotplug(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture); +void Android_StopAudioHotplug(void); +extern void Android_AudioThreadInit(SDL_AudioDevice *device); +extern int Android_JNI_OpenAudioDevice(SDL_AudioDevice *device); extern void *Android_JNI_GetAudioBuffer(void); extern void Android_JNI_WriteAudioBuffer(void); extern int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen); extern void Android_JNI_FlushCapturedAudio(void); extern void Android_JNI_CloseAudioDevice(const int iscapture); -extern void Android_JNI_AudioSetThreadPriority(int iscapture, int device_id); /* Detecting device type */ extern SDL_bool Android_IsDeXMode(void);