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]; 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... */ /* stubs for audio drivers that don't need a specific entry point... */
static void SDL_AudioDetectDevices_Default(void) static void SDL_AudioDetectDevices_Default(void)
{ {

View File

@@ -200,4 +200,7 @@ extern AudioBootStrap N3DSAUDIO_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap; extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap QSAAUDIO_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_ */ #endif /* SDL_sysaudio_h_ */

View File

@@ -43,9 +43,6 @@ typedef struct AAUDIO_Data
} AAUDIO_Data; } AAUDIO_Data;
static AAUDIO_Data ctx; static AAUDIO_Data ctx;
static SDL_AudioDevice *audioDevice = NULL;
static SDL_AudioDevice *captureDevice = NULL;
static int aaudio_LoadFunctions(AAUDIO_Data *data) static int aaudio_LoadFunctions(AAUDIO_Data *data)
{ {
#define SDL_PROC(ret, func, params) \ #define SDL_PROC(ret, func, params) \
@@ -75,18 +72,6 @@ static int aaudio_OpenDevice(_THIS, const char *devname)
aaudio_result_t res; aaudio_result_t res;
LOGI(__func__); 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 (iscapture) {
if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) { if (!Android_JNI_RequestPermission("android.permission.RECORD_AUDIO")) {
LOGI("This app doesn't have RECORD_AUDIO permission"); 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)); this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*this->hidden));
if (this->hidden == NULL) { if (this->hidden == NULL) {
return SDL_OutOfMemory(); 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->mixbuf);
SDL_free(this->hidden); SDL_free(this->hidden);
} }
@@ -349,10 +320,24 @@ AudioBootStrap aaudio_bootstrap = {
/* 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 aaudio_PauseDevices(void) void aaudio_PauseDevices(void)
{ {
/* TODO: Handle multiple devices? */ int i;
struct SDL_PrivateAudioData *private; 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) { if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden; struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (private->stream) { if (private->stream) {
aaudio_result_t res = ctx.AAudioStream_requestPause(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) { if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden; struct SDL_PrivateAudioData *private = (struct SDL_PrivateAudioData *)audioDevice->hidden;
if (private->stream) { if (private->stream) {
/* Pause() isn't implemented for 'capture', use Stop() */ /* Pause() isn't implemented for 'capture', use Stop() */
@@ -393,15 +378,31 @@ void aaudio_PauseDevices(void)
private->resume = SDL_TRUE; private->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 aaudio_ResumeDevices(void) void aaudio_ResumeDevices(void)
{ {
/* TODO: Handle multiple devices? */ int i;
struct SDL_PrivateAudioData *private; 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) { if (audioDevice != NULL && audioDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)audioDevice->hidden; struct SDL_PrivateAudioData *private = audioDevice->hidden;
if (private->resume) { if (private->resume) {
SDL_AtomicSet(&audioDevice->paused, 0); SDL_AtomicSet(&audioDevice->paused, 0);
@@ -419,7 +420,7 @@ void aaudio_ResumeDevices(void)
} }
if (captureDevice != NULL && captureDevice->hidden != NULL) { if (captureDevice != NULL && captureDevice->hidden != NULL) {
private = (struct SDL_PrivateAudioData *)captureDevice->hidden; struct SDL_PrivateAudioData *private = audioDevice->hidden;
if (private->resume) { if (private->resume) {
SDL_AtomicSet(&captureDevice->paused, 0); SDL_AtomicSet(&captureDevice->paused, 0);
@@ -435,6 +436,7 @@ void aaudio_ResumeDevices(void)
} }
} }
} }
}
} }
/* /*
@@ -444,17 +446,27 @@ void aaudio_ResumeDevices(void)
*/ */
SDL_bool aaudio_DetectBrokenPlayState(void) SDL_bool aaudio_DetectBrokenPlayState(void)
{ {
struct SDL_PrivateAudioData *private; int i;
int64_t framePosition, timeNanoseconds; for (i = 0; i < get_max_num_audio_dev(); i++) {
aaudio_result_t res; SDL_AudioDevice *this = get_audio_dev(i);
SDL_AudioDevice *audioDevice = NULL;
SDL_AudioDevice *captureDevice = NULL;
if (audioDevice == NULL || !audioDevice->hidden) { if (this == NULL) {
return SDL_FALSE; 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) { if (res == AAUDIO_ERROR_INVALID_STATE) {
aaudio_stream_state_t currentState = ctx.AAudioStream_getState(private->stream); 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. */ /* 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; return SDL_FALSE;
} }