(Switch audren) One lock for the renderer and the buffer state; blocking by default

write_avail() runs on the frontend's thread and brings the wave buffer
states up to date with audrvUpdate(); the writer, on the audio thread,
adds and starts. Every call into the renderer, and the reads and
writes of the wave buffer states and the buffer being filled, are
under the one lock, so the voice's buffer list is never rewritten
under an add - which lost buffers from the voice with their audio,
left them counted free, and took the backpressure with them.

The driver is blocking until the frontend says otherwise; it sets
non-blocking at init only when audio sync is off.

Fixes #19508.
This commit is contained in:
LibretroAdmin authored and libretroadmin committed 2026-09-06 23:22:30 +02:00
1 parent db9d54a031
commit 6d0da53215
1 file changed
+22 -11
+22 -11
View File
@@ -52,6 +52,10 @@ typedef struct
size_t current_size;
size_t buffer_size;
size_t samples;
/* Held for every call into the renderer and for the wave buffer
* states and the buffer being filled: write_avail() reads them on
* the frontend's thread while the writer, on the audio thread, adds
* and starts. */
Mutex update_lock;
bool nonblock;
} libnx_audren_t;
@@ -81,7 +85,9 @@ static void *libnx_audren_audio_init(
real_latency = MAX(5, latency);
RARCH_LOG("[Audren] real_latency is %u.\n", real_latency);
aud->nonblock = !block_frames;
/* Blocking until the frontend says otherwise: it sets non-blocking
* at init only when audio sync is off. */
aud->nonblock = false;
/* The latency setting is split across the BUFFER_COUNT wave buffers
* the renderer plays in turn, so that the buffers together hold the
* setting and rate control - which sees the total, below - holds it
@@ -181,11 +187,11 @@ fail:
static size_t libnx_audren_audio_room(libnx_audren_t *aud)
{
size_t free_bufs = 0;
size_t room;
unsigned i;
mutexLock(&aud->update_lock);
audrvUpdate(&aud->drv);
mutexUnlock(&aud->update_lock);
for (i = 0; i < BUFFER_COUNT; i++)
if ( aud->wavebufs[i].state == AudioDriverWaveBufState_Free
@@ -198,10 +204,13 @@ static size_t libnx_audren_audio_room(libnx_audren_t *aud)
{
if (free_bufs)
free_bufs--;
return free_bufs * aud->buffer_size
room = free_bufs * aud->buffer_size
+ (aud->buffer_size - aud->current_size);
}
return free_bufs * aud->buffer_size;
else
room = free_bufs * aud->buffer_size;
mutexUnlock(&aud->update_lock);
return room;
}
static size_t libnx_audren_audio_buffer_size(void *data)
@@ -237,11 +246,15 @@ static size_t libnx_audren_audio_append(
void *dstbuf = NULL;
ssize_t free_idx = -1;
mutexLock(&aud->update_lock);
if (!aud->current_wavebuf)
{
free_idx = libnx_audren_audio_get_free_wavebuf_idx(aud);
if (free_idx == -1)
{
mutexUnlock(&aud->update_lock);
return 0;
}
aud->current_wavebuf = &aud->wavebufs[free_idx];
aud->current_pool_ptr = aud->mempool + (free_idx * aud->buffer_size);
@@ -260,18 +273,12 @@ static size_t libnx_audren_audio_append(
if (aud->current_size == aud->buffer_size)
{
audrvVoiceAddWaveBuf(&aud->drv, 0, aud->current_wavebuf);
mutexLock(&aud->update_lock);
audrvUpdate(&aud->drv);
mutexUnlock(&aud->update_lock);
if (!audrvVoiceIsPlaying(&aud->drv, 0))
{
audrvVoiceStart(&aud->drv, 0);
}
aud->current_wavebuf = NULL;
}
mutexUnlock(&aud->update_lock);
return len;
}
@@ -321,7 +328,9 @@ static bool libnx_audren_audio_stop(void *data)
if (!aud)
return false;
mutexLock(&aud->update_lock);
audrvVoiceStop(&aud->drv, 0);
mutexUnlock(&aud->update_lock);
return true;
}
@@ -334,7 +343,9 @@ static bool libnx_audren_audio_start(void *data, bool is_shutdown)
if (!aud)
return false;
mutexLock(&aud->update_lock);
audrvVoiceStart(&aud->drv, 0);
mutexUnlock(&aud->update_lock);
return true;
}