diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index aca4262061..1a306c6752 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -201,6 +201,16 @@ static SDL_AudioDevice *get_audio_device(SDL_AudioDeviceID id) return open_devices[id]; } +int get_max_num_audio_dev(void) +{ + return SDL_arraysize(open_devices); +} + +SDL_AudioDevice *get_audio_dev(SDL_AudioDeviceID id) +{ + return open_devices[id]; +} + /* stubs for audio drivers that don't need a specific entry point... */ static void SDL_AudioDetectDevices_Default(void) { diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 7fb7ac591f..7a49b4e9ce 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -200,4 +200,7 @@ extern AudioBootStrap N3DSAUDIO_bootstrap; extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap; extern AudioBootStrap QSAAUDIO_bootstrap; +extern SDL_AudioDevice *get_audio_dev(SDL_AudioDeviceID id); +extern int get_max_num_audio_dev(void); + #endif /* SDL_sysaudio_h_ */ diff --git a/src/audio/aaudio/SDL_aaudio.c b/src/audio/aaudio/SDL_aaudio.c index 693b5a98cd..9388111aff 100644 --- a/src/audio/aaudio/SDL_aaudio.c +++ b/src/audio/aaudio/SDL_aaudio.c @@ -43,9 +43,6 @@ typedef struct AAUDIO_Data } AAUDIO_Data; static AAUDIO_Data ctx; -static SDL_AudioDevice *audioDevice = NULL; -static SDL_AudioDevice *captureDevice = NULL; - static int aaudio_LoadFunctions(AAUDIO_Data *data) { #define SDL_PROC(ret, func, params) \ @@ -75,18 +72,6 @@ static int aaudio_OpenDevice(_THIS, const char *devname) aaudio_result_t res; LOGI(__func__); - if (iscapture) { - if (captureDevice) { - return SDL_SetError("An audio capture device is already opened"); - } - } - - if (!iscapture) { - if (audioDevice) { - return SDL_SetError("An audio playback device is already opened"); - } - } - if (iscapture) { if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) { LOGI("This app doesn't have RECORD_AUDIO permission"); @@ -94,12 +79,6 @@ static int aaudio_OpenDevice(_THIS, const char *devname) } } - 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(); @@ -200,14 +179,6 @@ static void aaudio_CloseDevice(_THIS) } } - if (this->iscapture) { - SDL_assert(captureDevice == this); - captureDevice = NULL; - } else { - SDL_assert(audioDevice == this); - audioDevice = NULL; - } - SDL_free(this->hidden->mixbuf); SDL_free(this->hidden); } @@ -349,89 +320,120 @@ AudioBootStrap aaudio_bootstrap = { /* Pause (block) all non already paused audio devices by taking their mixer lock */ void aaudio_PauseDevices(void) { - /* TODO: Handle multiple devices? */ - struct SDL_PrivateAudioData *private; - if (audioDevice != NULL && audioDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)audioDevice->hidden; + int i; + 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 (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 (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 (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 (captureDevice != NULL && captureDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)captureDevice->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 (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 (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; - } } } /* Resume (unblock) all non already paused audio devices by releasing their mixer lock */ void aaudio_ResumeDevices(void) { - /* TODO: Handle multiple devices? */ - struct SDL_PrivateAudioData *private; - if (audioDevice != NULL && audioDevice->hidden != NULL) { - private = (struct SDL_PrivateAudioData *)audioDevice->hidden; + int i; + 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 (private->resume) { - SDL_AtomicSet(&audioDevice->paused, 0); - private->resume = SDL_FALSE; - SDL_UnlockMutex(audioDevice->mixer_lock); + if (this == NULL) { + continue; } - 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 (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) { - private = (struct SDL_PrivateAudioData *)captureDevice->hidden; + 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->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 (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)); + } } } } @@ -444,24 +446,39 @@ void aaudio_ResumeDevices(void) */ SDL_bool aaudio_DetectBrokenPlayState(void) { - struct SDL_PrivateAudioData *private; - int64_t framePosition, timeNanoseconds; - aaudio_result_t res; + int i; + 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 (audioDevice == NULL || !audioDevice->hidden) { - return SDL_FALSE; - } - - private = audioDevice->hidden; - - 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; + 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; + } + } + + } + + (void) captureDevice; } return SDL_FALSE;