mirror of https://github.com/libsdl-org/SDL.git
Pause and resume Android audio without taking device locks
The AAudio driver implemented pause/resume by dangerously locking the audio devices. If there was an audio hotplug event or a background thread tried to interact with the audio system, this could cause deadlocks.
This commit is contained in:
parent
9d35f178a6
commit
5318e30ee5
|
|
@ -43,7 +43,6 @@ struct SDL_PrivateAudioData
|
||||||
size_t processed_bytes;
|
size_t processed_bytes;
|
||||||
SDL_Semaphore *semaphore;
|
SDL_Semaphore *semaphore;
|
||||||
SDL_AtomicInt error_callback_triggered;
|
SDL_AtomicInt error_callback_triggered;
|
||||||
SDL_bool resume; // Resume device if it was paused automatically
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
|
|
@ -165,7 +164,18 @@ static Uint8 *AAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *bufsize)
|
||||||
|
|
||||||
static int AAUDIO_WaitDevice(SDL_AudioDevice *device)
|
static int AAUDIO_WaitDevice(SDL_AudioDevice *device)
|
||||||
{
|
{
|
||||||
SDL_WaitSemaphore(device->hidden->semaphore);
|
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||||
|
// this semaphore won't fire when the app is in the background (AAUDIO_PauseDevices was called).
|
||||||
|
const int rc = SDL_WaitSemaphoreTimeout(device->hidden->semaphore, 100);
|
||||||
|
if (rc == -1) { // uh, what?
|
||||||
|
return -1;
|
||||||
|
} else if (rc == 0) {
|
||||||
|
return 0; // semaphore was signaled, let's go!
|
||||||
|
} else {
|
||||||
|
SDL_assert(rc == SDL_MUTEX_TIMEDOUT);
|
||||||
|
}
|
||||||
|
// Still waiting on the semaphore (or the system), check other things then wait again.
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,9 +449,6 @@ static SDL_bool PauseOneDevice(SDL_AudioDevice *device, void *userdata)
|
||||||
LOGI("SDL Failed AAudioStream_requestPause %d", res);
|
LOGI("SDL Failed AAudioStream_requestPause %d", res);
|
||||||
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
|
SDL_SetError("%s : %s", __func__, ctx.AAudio_convertResultToText(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LockMutex(device->lock);
|
|
||||||
hidden->resume = SDL_TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SDL_FALSE; // keep enumerating.
|
return SDL_FALSE; // keep enumerating.
|
||||||
|
|
@ -460,11 +467,6 @@ static SDL_bool ResumeOneDevice(SDL_AudioDevice *device, void *userdata)
|
||||||
{
|
{
|
||||||
struct SDL_PrivateAudioData *hidden = device->hidden;
|
struct SDL_PrivateAudioData *hidden = device->hidden;
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
if (hidden->resume) {
|
|
||||||
hidden->resume = SDL_FALSE;
|
|
||||||
SDL_UnlockMutex(device->lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hidden->stream) {
|
if (hidden->stream) {
|
||||||
aaudio_result_t res = ctx.AAudioStream_requestStart(hidden->stream);
|
aaudio_result_t res = ctx.AAudioStream_requestStart(hidden->stream);
|
||||||
if (res != AAUDIO_OK) {
|
if (res != AAUDIO_OK) {
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,7 @@
|
||||||
#ifndef SDL_aaudio_h_
|
#ifndef SDL_aaudio_h_
|
||||||
#define SDL_aaudio_h_
|
#define SDL_aaudio_h_
|
||||||
|
|
||||||
#ifdef SDL_AUDIO_DRIVER_AAUDIO
|
extern void AAUDIO_ResumeDevices(void);
|
||||||
|
extern void AAUDIO_PauseDevices(void);
|
||||||
void AAUDIO_ResumeDevices(void);
|
|
||||||
void AAUDIO_PauseDevices(void);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define AAUDIO_ResumeDevices()
|
|
||||||
#define AAUDIO_PauseDevices()
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // SDL_aaudio_h_
|
#endif // SDL_aaudio_h_
|
||||||
|
|
|
||||||
|
|
@ -652,8 +652,19 @@ static int OPENSLES_WaitDevice(SDL_AudioDevice *device)
|
||||||
|
|
||||||
LOGV("OPENSLES_WaitDevice()");
|
LOGV("OPENSLES_WaitDevice()");
|
||||||
|
|
||||||
// Wait for an audio chunk to finish
|
while (!SDL_AtomicGet(&device->shutdown)) {
|
||||||
return SDL_WaitSemaphore(audiodata->playsem);
|
// this semaphore won't fire when the app is in the background (OPENSLES_PauseDevices was called).
|
||||||
|
const int rc = SDL_WaitSemaphoreTimeout(audiodata->playsem, 100);
|
||||||
|
if (rc == -1) { // uh, what?
|
||||||
|
return -1;
|
||||||
|
} else if (rc == 0) {
|
||||||
|
return 0; // semaphore was signaled, let's go!
|
||||||
|
} else {
|
||||||
|
SDL_assert(rc == SDL_MUTEX_TIMEDOUT);
|
||||||
|
}
|
||||||
|
// Still waiting on the semaphore (or the system), check other things then wait again.
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int OPENSLES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
static int OPENSLES_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,7 @@
|
||||||
#ifndef SDL_openslesaudio_h_
|
#ifndef SDL_openslesaudio_h_
|
||||||
#define SDL_openslesaudio_h_
|
#define SDL_openslesaudio_h_
|
||||||
|
|
||||||
#ifdef SDL_AUDIO_DRIVER_OPENSLES
|
extern void OPENSLES_ResumeDevices(void);
|
||||||
|
extern void OPENSLES_PauseDevices(void);
|
||||||
void OPENSLES_ResumeDevices(void);
|
|
||||||
void OPENSLES_PauseDevices(void);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static void OPENSLES_ResumeDevices(void) {}
|
|
||||||
static void OPENSLES_PauseDevices(void) {}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // SDL_openslesaudio_h_
|
#endif // SDL_openslesaudio_h_
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue