mirror of
https://github.com/libretro/RetroArch
synced 2025-03-12 04:14:23 +00:00
Fix PulseAudio freeze (#17316)
* Fix freeze when close app/content after stopping/restarting pulse service * Fix pa->devicelist memleak * Logging improvements
This commit is contained in:
parent
6be18bfee9
commit
3a4330238a
@ -254,10 +254,8 @@ void alsa_device_list_free(void *data, void *array_list_data)
|
||||
{
|
||||
struct string_list *s = (struct string_list*)array_list_data;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
string_list_free(s);
|
||||
if (s)
|
||||
string_list_free(s);
|
||||
}
|
||||
|
||||
audio_driver_t audio_alsa = {
|
||||
|
@ -132,11 +132,15 @@ static void stream_state_changed_cb(void *data,
|
||||
|
||||
switch(state)
|
||||
{
|
||||
case PW_STREAM_STATE_ERROR:
|
||||
RARCH_ERR("[PipeWire]: Stream error\n");
|
||||
pw_thread_loop_signal(audio->pw->thread_loop, false);
|
||||
break;
|
||||
case PW_STREAM_STATE_UNCONNECTED:
|
||||
RARCH_WARN("[PipeWire]: Stream unconnected\n");
|
||||
pw_thread_loop_stop(audio->pw->thread_loop);
|
||||
break;
|
||||
case PW_STREAM_STATE_STREAMING:
|
||||
case PW_STREAM_STATE_ERROR:
|
||||
case PW_STREAM_STATE_PAUSED:
|
||||
pw_thread_loop_signal(audio->pw->thread_loop, false);
|
||||
break;
|
||||
@ -192,7 +196,8 @@ static void registry_event_global(void *data, uint32_t id,
|
||||
media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||
if (media && strcmp(media, "Audio/Sink") == 0)
|
||||
{
|
||||
if ((sink = spa_dict_lookup(props, PW_KEY_NODE_NAME)) != NULL)
|
||||
sink = spa_dict_lookup(props, PW_KEY_NODE_NAME);
|
||||
if (sink && pw->devicelist)
|
||||
{
|
||||
attr.i = id;
|
||||
string_list_append(pw->devicelist, sink, attr);
|
||||
@ -231,11 +236,9 @@ static void *pipewire_init(const char *device, unsigned rate,
|
||||
|
||||
if (!audio)
|
||||
goto error;
|
||||
pw = audio->pw = (pipewire_core_t*)calloc(1, sizeof(*audio->pw));
|
||||
|
||||
pw = audio->pw = (pipewire_core_t*)calloc(1, sizeof(*audio->pw));
|
||||
pw->devicelist = string_list_new();
|
||||
if (!pw->devicelist)
|
||||
goto error;
|
||||
|
||||
if (!pipewire_core_init(pw, "audio_driver"))
|
||||
goto error;
|
||||
@ -445,7 +448,7 @@ static void *pipewire_device_list_new(void *data)
|
||||
{
|
||||
pipewire_audio_t *audio = (pipewire_audio_t*)data;
|
||||
|
||||
if (audio && audio->pw->devicelist)
|
||||
if (audio && audio->pw && audio->pw->devicelist)
|
||||
return string_list_clone(audio->pw->devicelist);
|
||||
|
||||
return NULL;
|
||||
|
@ -37,6 +37,7 @@ typedef struct
|
||||
bool nonblock;
|
||||
bool success;
|
||||
bool is_paused;
|
||||
bool is_ready;
|
||||
struct string_list *devicelist;
|
||||
} pa_t;
|
||||
|
||||
@ -65,6 +66,9 @@ static void pulse_free(void *data)
|
||||
if (pa->mainloop)
|
||||
pa_threaded_mainloop_free(pa->mainloop);
|
||||
|
||||
if (pa->devicelist)
|
||||
string_list_free(pa->devicelist);
|
||||
|
||||
free(pa);
|
||||
}
|
||||
|
||||
@ -83,8 +87,15 @@ static void context_state_cb(pa_context *c, void *data)
|
||||
switch (pa_context_get_state(c))
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
RARCH_ERR("[PulseAudio]: Connection failed\n");
|
||||
pa->is_ready = false;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
pa->is_ready = false;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
default:
|
||||
@ -98,9 +109,7 @@ static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *
|
||||
attr.i = 0;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->devicelist)
|
||||
pa->devicelist = string_list_new();
|
||||
if (!pa->devicelist)
|
||||
if (!pa || !pa->devicelist)
|
||||
return;
|
||||
|
||||
/* If EOL is set to a positive number,
|
||||
@ -119,8 +128,13 @@ static void stream_state_cb(pa_stream *s, void *data)
|
||||
switch (pa_stream_get_state(s))
|
||||
{
|
||||
case PA_STREAM_READY:
|
||||
pa->is_ready = true;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
pa->is_ready = false;
|
||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||
break;
|
||||
default:
|
||||
@ -180,6 +194,8 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
if (!pa)
|
||||
goto error;
|
||||
|
||||
pa->devicelist = string_list_new();
|
||||
|
||||
pa->mainloop = pa_threaded_mainloop_new();
|
||||
if (!pa->mainloop)
|
||||
goto error;
|
||||
@ -203,7 +219,7 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
if (pa_context_get_state(pa->context) != PA_CONTEXT_READY)
|
||||
goto unlock_error;
|
||||
|
||||
pa_context_get_sink_info_list(pa->context,pa_sinklist_cb,pa);
|
||||
pa_context_get_sink_info_list(pa->context, pa_sinklist_cb, pa);
|
||||
/* Checking device against sink list would be tricky due to callback, so it is just set. */
|
||||
if (device)
|
||||
pa_context_set_default_sink(pa->context, device, NULL, NULL);
|
||||
@ -249,6 +265,7 @@ static void *pulse_init(const char *device, unsigned rate,
|
||||
pa->buffer_size = buffer_attr.tlength;
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
pa->is_ready = true;
|
||||
|
||||
return pa;
|
||||
|
||||
@ -272,6 +289,9 @@ static ssize_t pulse_write(void *data, const void *buf_, size_t size)
|
||||
if (!pulse_start(pa, false))
|
||||
return -1;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return 0;
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
while (size)
|
||||
{
|
||||
@ -299,11 +319,12 @@ static bool pulse_stop(void *data)
|
||||
{
|
||||
bool ret;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return false;
|
||||
if (pa->is_paused)
|
||||
return true;
|
||||
|
||||
RARCH_LOG("[PulseAudio]: Pausing.\n");
|
||||
|
||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_cork(pa->stream, true, stream_success_cb, pa);
|
||||
@ -318,7 +339,7 @@ static bool pulse_alive(void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa)
|
||||
if (!pa || !pa->is_ready)
|
||||
return false;
|
||||
return !pa->is_paused;
|
||||
}
|
||||
@ -327,11 +348,12 @@ static bool pulse_start(void *data, bool is_shutdown)
|
||||
{
|
||||
bool ret;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return false;
|
||||
if (!pa->is_paused)
|
||||
return true;
|
||||
|
||||
RARCH_LOG("[PulseAudio]: Unpausing.\n");
|
||||
|
||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
pa_stream_cork(pa->stream, false, stream_success_cb, pa);
|
||||
@ -360,6 +382,9 @@ static size_t pulse_write_avail(void *data)
|
||||
size_t _len;
|
||||
pa_t *pa = (pa_t*)data;
|
||||
|
||||
if (!pa->is_ready)
|
||||
return 0;
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
_len = pa_stream_writable_size(pa->stream);
|
||||
|
||||
@ -377,13 +402,11 @@ static size_t pulse_buffer_size(void *data)
|
||||
static void *pulse_device_list_new(void *data)
|
||||
{
|
||||
pa_t *pa = (pa_t*)data;
|
||||
if (!pa)
|
||||
return NULL;
|
||||
|
||||
struct string_list *s = pa->devicelist ? string_list_clone(pa->devicelist) : NULL;
|
||||
if (!s)
|
||||
return NULL;
|
||||
return s;
|
||||
if (pa && pa->devicelist)
|
||||
return string_list_clone(pa->devicelist);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void pulse_device_list_free(void *data, void *array_list_data)
|
||||
|
Loading…
x
Reference in New Issue
Block a user