mirror of
https://github.com/libretro/RetroArch
synced 2025-02-20 15:40:44 +00:00
Use threaded mainloop for Pulse. Seems to fix most issues.
This commit is contained in:
parent
e83f3ed444
commit
fff7aba8ec
103
audio/pulse.c
103
audio/pulse.c
@ -26,7 +26,7 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pa_mainloop *mainloop;
|
||||
pa_threaded_mainloop *mainloop;
|
||||
pa_context *context;
|
||||
pa_stream *stream;
|
||||
bool nonblock;
|
||||
@ -37,6 +37,9 @@ static void __pulse_free(void *data)
|
||||
pa_t *pa = data;
|
||||
if (pa)
|
||||
{
|
||||
if (pa->mainloop)
|
||||
pa_threaded_mainloop_stop(pa->mainloop);
|
||||
|
||||
if (pa->stream)
|
||||
{
|
||||
pa_stream_disconnect(pa->stream);
|
||||
@ -50,7 +53,7 @@ static void __pulse_free(void *data)
|
||||
}
|
||||
|
||||
if (pa->mainloop)
|
||||
pa_mainloop_free(pa->mainloop);
|
||||
pa_threaded_mainloop_free(pa->mainloop);
|
||||
|
||||
free(pa);
|
||||
}
|
||||
@ -68,29 +71,77 @@ static inline uint8_t is_little_endian(void)
|
||||
return u.y[0];
|
||||
}
|
||||
|
||||
static void context_state_cb(pa_context *c, void *data)
|
||||
{
|
||||
pa_t *pa = data;
|
||||
switch (pa_context_get_state(c))
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
case PA_CONTEXT_FAILED:
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_state_cb(pa_stream *s, void *data)
|
||||
{
|
||||
pa_t *pa = data;
|
||||
switch (pa_stream_get_state(s)) {
|
||||
case PA_STREAM_READY:
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_request_cb(pa_stream *s, size_t length, void *data)
|
||||
{
|
||||
(void)length;
|
||||
(void)s;
|
||||
pa_t *pa = data;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
}
|
||||
|
||||
static void stream_latency_update_cb(pa_stream *s, void *data)
|
||||
{
|
||||
(void)s;
|
||||
pa_t *pa = data;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
}
|
||||
|
||||
static void* __pulse_init(const char* device, int rate, int latency)
|
||||
{
|
||||
pa_t *pa = calloc(1, sizeof(*pa));
|
||||
if (!pa)
|
||||
goto error;
|
||||
|
||||
pa->mainloop = pa_mainloop_new();
|
||||
pa->mainloop = pa_threaded_mainloop_new();
|
||||
if (!pa->mainloop)
|
||||
goto error;
|
||||
|
||||
pa->context = pa_context_new(pa_mainloop_get_api(pa->mainloop), "SSNES");
|
||||
pa->context = pa_context_new(pa_threaded_mainloop_get_api(pa->mainloop), "SSNES");
|
||||
if (!pa->context)
|
||||
goto error;
|
||||
|
||||
pa_context_set_state_callback(pa->context, context_state_cb, pa);
|
||||
|
||||
if (pa_context_connect(pa->context, device, PA_CONTEXT_NOFLAGS, NULL) < 0)
|
||||
goto error;
|
||||
|
||||
pa_context_state_t cstate;
|
||||
do
|
||||
{
|
||||
pa_mainloop_iterate(pa->mainloop, 1, NULL);
|
||||
cstate = pa_context_get_state(pa->context);
|
||||
if (!PA_CONTEXT_IS_GOOD(cstate)) goto error;
|
||||
} while (cstate != PA_CONTEXT_READY);
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
if (pa_threaded_mainloop_start(pa->mainloop) < 0)
|
||||
goto error;
|
||||
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
|
||||
if (pa_context_get_state(pa->context) != PA_CONTEXT_READY)
|
||||
goto unlock_error;
|
||||
|
||||
pa_sample_spec spec = {
|
||||
.format = is_little_endian() ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_FLOAT32BE,
|
||||
@ -100,7 +151,11 @@ static void* __pulse_init(const char* device, int rate, int latency)
|
||||
|
||||
pa->stream = pa_stream_new(pa->context, "audio", &spec, NULL);
|
||||
if (!pa->stream)
|
||||
goto error;
|
||||
goto unlock_error;
|
||||
|
||||
pa_stream_set_state_callback(pa->stream, stream_state_cb, pa);
|
||||
pa_stream_set_write_callback(pa->stream, stream_request_cb, pa);
|
||||
pa_stream_set_latency_update_callback(pa->stream, stream_latency_update_cb, pa);
|
||||
|
||||
pa_buffer_attr buffer_attr = {
|
||||
.maxlength = -1,
|
||||
@ -113,16 +168,17 @@ static void* __pulse_init(const char* device, int rate, int latency)
|
||||
if (pa_stream_connect_playback(pa->stream, NULL, &buffer_attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0)
|
||||
goto error;
|
||||
|
||||
pa_stream_state_t sstate;
|
||||
do
|
||||
{
|
||||
pa_mainloop_iterate(pa->mainloop, 1, NULL);
|
||||
sstate = pa_stream_get_state(pa->stream);
|
||||
if(!PA_STREAM_IS_GOOD(sstate)) goto error;
|
||||
} while(sstate != PA_STREAM_READY);
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
|
||||
if (pa_stream_get_state(pa->stream) != PA_STREAM_READY)
|
||||
goto unlock_error;
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
|
||||
return pa;
|
||||
|
||||
unlock_error:
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
error:
|
||||
__pulse_free(pa);
|
||||
return NULL;
|
||||
@ -132,12 +188,15 @@ static ssize_t __pulse_write(void* data, const void* buf, size_t size)
|
||||
{
|
||||
pa_t *pa = data;
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
unsigned length = pa_stream_writable_size(pa->stream);
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
while (length < size)
|
||||
{
|
||||
pa_mainloop_iterate(pa->mainloop, 1, NULL);
|
||||
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
length = pa_stream_writable_size(pa->stream);
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
|
||||
if (pa->nonblock)
|
||||
break;
|
||||
@ -145,7 +204,9 @@ static ssize_t __pulse_write(void* data, const void* buf, size_t size)
|
||||
|
||||
size_t write_size = length < size ? length : size;
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_write(pa->stream, buf, write_size, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
return write_size;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user