Android AAUDIO: handle multiple devices

This commit is contained in:
Sylvain
2023-04-06 23:17:29 +02:00
committed by Sylvain Becker
parent f38cb0d06f
commit 117169d610
3 changed files with 135 additions and 105 deletions

View File

@@ -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)
{

View File

@@ -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_ */

View File

@@ -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,10 +320,24 @@ 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;
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 (this == NULL) {
continue;
}
if (this->iscapture) {
captureDevice = this;
} else {
audioDevice = this;
}
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (private->stream) {
aaudio_result_t res = ctx.AAudioStream_requestPause(private->stream);
@@ -373,7 +358,7 @@ void aaudio_PauseDevices(void)
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden;
struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (private->stream) {
/* Pause() isn't implemented for 'capture', use Stop() */
@@ -393,15 +378,31 @@ void aaudio_PauseDevices(void)
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;
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 (this == NULL) {
continue;
}
if (this->iscapture) {
captureDevice = this;
} else {
audioDevice = this;
}
if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
struct SDL_PrivateAudioData *private = audioDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&audioDevice->paused, 0);
@@ -419,7 +420,7 @@ void aaudio_ResumeDevices(void)
}
if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden;
struct SDL_PrivateAudioData *private = audioDevice->hidden;
if (private->resume) {
SDL_AtomicSet(&captureDevice->paused, 0);
@@ -436,6 +437,7 @@ void aaudio_ResumeDevices(void)
}
}
}
}
/*
We can sometimes get into a state where AAudioStream_write() will just block forever until we pause and unpause.
@@ -444,17 +446,27 @@ 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;
if (this == NULL) {
continue;
}
private = audioDevice->hidden;
if (this->iscapture) {
captureDevice = this;
} else {
audioDevice = this;
}
res = ctx.AAudioStream_getTimestamp(private->stream, CLOCK_MONOTONIC, &framePosition, &timeNanoseconds);
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. */
@@ -464,6 +476,11 @@ SDL_bool aaudio_DetectBrokenPlayState(void)
}
}
}
(void) captureDevice;
}
return SDL_FALSE;
}