mirror of
https://github.com/libretro/RetroArch
synced 2025-03-12 13:13:30 +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;
|
struct string_list *s = (struct string_list*)array_list_data;
|
||||||
|
|
||||||
if (!s)
|
if (s)
|
||||||
return;
|
string_list_free(s);
|
||||||
|
|
||||||
string_list_free(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_driver_t audio_alsa = {
|
audio_driver_t audio_alsa = {
|
||||||
|
@ -132,11 +132,15 @@ static void stream_state_changed_cb(void *data,
|
|||||||
|
|
||||||
switch(state)
|
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:
|
case PW_STREAM_STATE_UNCONNECTED:
|
||||||
|
RARCH_WARN("[PipeWire]: Stream unconnected\n");
|
||||||
pw_thread_loop_stop(audio->pw->thread_loop);
|
pw_thread_loop_stop(audio->pw->thread_loop);
|
||||||
break;
|
break;
|
||||||
case PW_STREAM_STATE_STREAMING:
|
case PW_STREAM_STATE_STREAMING:
|
||||||
case PW_STREAM_STATE_ERROR:
|
|
||||||
case PW_STREAM_STATE_PAUSED:
|
case PW_STREAM_STATE_PAUSED:
|
||||||
pw_thread_loop_signal(audio->pw->thread_loop, false);
|
pw_thread_loop_signal(audio->pw->thread_loop, false);
|
||||||
break;
|
break;
|
||||||
@ -192,7 +196,8 @@ static void registry_event_global(void *data, uint32_t id,
|
|||||||
media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||||
if (media && strcmp(media, "Audio/Sink") == 0)
|
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;
|
attr.i = id;
|
||||||
string_list_append(pw->devicelist, sink, attr);
|
string_list_append(pw->devicelist, sink, attr);
|
||||||
@ -231,11 +236,9 @@ static void *pipewire_init(const char *device, unsigned rate,
|
|||||||
|
|
||||||
if (!audio)
|
if (!audio)
|
||||||
goto error;
|
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();
|
pw->devicelist = string_list_new();
|
||||||
if (!pw->devicelist)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!pipewire_core_init(pw, "audio_driver"))
|
if (!pipewire_core_init(pw, "audio_driver"))
|
||||||
goto error;
|
goto error;
|
||||||
@ -445,7 +448,7 @@ static void *pipewire_device_list_new(void *data)
|
|||||||
{
|
{
|
||||||
pipewire_audio_t *audio = (pipewire_audio_t*)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 string_list_clone(audio->pw->devicelist);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -37,6 +37,7 @@ typedef struct
|
|||||||
bool nonblock;
|
bool nonblock;
|
||||||
bool success;
|
bool success;
|
||||||
bool is_paused;
|
bool is_paused;
|
||||||
|
bool is_ready;
|
||||||
struct string_list *devicelist;
|
struct string_list *devicelist;
|
||||||
} pa_t;
|
} pa_t;
|
||||||
|
|
||||||
@ -65,6 +66,9 @@ static void pulse_free(void *data)
|
|||||||
if (pa->mainloop)
|
if (pa->mainloop)
|
||||||
pa_threaded_mainloop_free(pa->mainloop);
|
pa_threaded_mainloop_free(pa->mainloop);
|
||||||
|
|
||||||
|
if (pa->devicelist)
|
||||||
|
string_list_free(pa->devicelist);
|
||||||
|
|
||||||
free(pa);
|
free(pa);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,8 +87,15 @@ static void context_state_cb(pa_context *c, void *data)
|
|||||||
switch (pa_context_get_state(c))
|
switch (pa_context_get_state(c))
|
||||||
{
|
{
|
||||||
case PA_CONTEXT_READY:
|
case PA_CONTEXT_READY:
|
||||||
case PA_CONTEXT_TERMINATED:
|
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||||
|
break;
|
||||||
case PA_CONTEXT_FAILED:
|
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);
|
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -98,9 +109,7 @@ static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *
|
|||||||
attr.i = 0;
|
attr.i = 0;
|
||||||
pa_t *pa = (pa_t*)data;
|
pa_t *pa = (pa_t*)data;
|
||||||
|
|
||||||
if (!pa->devicelist)
|
if (!pa || !pa->devicelist)
|
||||||
pa->devicelist = string_list_new();
|
|
||||||
if (!pa->devicelist)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* If EOL is set to a positive number,
|
/* 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))
|
switch (pa_stream_get_state(s))
|
||||||
{
|
{
|
||||||
case PA_STREAM_READY:
|
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_FAILED:
|
||||||
case PA_STREAM_TERMINATED:
|
case PA_STREAM_TERMINATED:
|
||||||
|
pa->is_ready = false;
|
||||||
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
pa_threaded_mainloop_signal(pa->mainloop, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -180,6 +194,8 @@ static void *pulse_init(const char *device, unsigned rate,
|
|||||||
if (!pa)
|
if (!pa)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
pa->devicelist = string_list_new();
|
||||||
|
|
||||||
pa->mainloop = pa_threaded_mainloop_new();
|
pa->mainloop = pa_threaded_mainloop_new();
|
||||||
if (!pa->mainloop)
|
if (!pa->mainloop)
|
||||||
goto error;
|
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)
|
if (pa_context_get_state(pa->context) != PA_CONTEXT_READY)
|
||||||
goto unlock_error;
|
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. */
|
/* Checking device against sink list would be tricky due to callback, so it is just set. */
|
||||||
if (device)
|
if (device)
|
||||||
pa_context_set_default_sink(pa->context, device, NULL, NULL);
|
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->buffer_size = buffer_attr.tlength;
|
||||||
|
|
||||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||||
|
pa->is_ready = true;
|
||||||
|
|
||||||
return pa;
|
return pa;
|
||||||
|
|
||||||
@ -272,6 +289,9 @@ static ssize_t pulse_write(void *data, const void *buf_, size_t size)
|
|||||||
if (!pulse_start(pa, false))
|
if (!pulse_start(pa, false))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (!pa->is_ready)
|
||||||
|
return 0;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(pa->mainloop);
|
pa_threaded_mainloop_lock(pa->mainloop);
|
||||||
while (size)
|
while (size)
|
||||||
{
|
{
|
||||||
@ -299,11 +319,12 @@ static bool pulse_stop(void *data)
|
|||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
pa_t *pa = (pa_t*)data;
|
pa_t *pa = (pa_t*)data;
|
||||||
|
|
||||||
|
if (!pa->is_ready)
|
||||||
|
return false;
|
||||||
if (pa->is_paused)
|
if (pa->is_paused)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RARCH_LOG("[PulseAudio]: Pausing.\n");
|
|
||||||
|
|
||||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||||
pa_threaded_mainloop_lock(pa->mainloop);
|
pa_threaded_mainloop_lock(pa->mainloop);
|
||||||
pa_stream_cork(pa->stream, true, stream_success_cb, pa);
|
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;
|
pa_t *pa = (pa_t*)data;
|
||||||
|
|
||||||
if (!pa)
|
if (!pa || !pa->is_ready)
|
||||||
return false;
|
return false;
|
||||||
return !pa->is_paused;
|
return !pa->is_paused;
|
||||||
}
|
}
|
||||||
@ -327,11 +348,12 @@ static bool pulse_start(void *data, bool is_shutdown)
|
|||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
pa_t *pa = (pa_t*)data;
|
pa_t *pa = (pa_t*)data;
|
||||||
|
|
||||||
|
if (!pa->is_ready)
|
||||||
|
return false;
|
||||||
if (!pa->is_paused)
|
if (!pa->is_paused)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
RARCH_LOG("[PulseAudio]: Unpausing.\n");
|
|
||||||
|
|
||||||
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
pa->success = true; /* In case of spurious wakeup. Not critical. */
|
||||||
pa_threaded_mainloop_lock(pa->mainloop);
|
pa_threaded_mainloop_lock(pa->mainloop);
|
||||||
pa_stream_cork(pa->stream, false, stream_success_cb, pa);
|
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;
|
size_t _len;
|
||||||
pa_t *pa = (pa_t*)data;
|
pa_t *pa = (pa_t*)data;
|
||||||
|
|
||||||
|
if (!pa->is_ready)
|
||||||
|
return 0;
|
||||||
|
|
||||||
pa_threaded_mainloop_lock(pa->mainloop);
|
pa_threaded_mainloop_lock(pa->mainloop);
|
||||||
_len = pa_stream_writable_size(pa->stream);
|
_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)
|
static void *pulse_device_list_new(void *data)
|
||||||
{
|
{
|
||||||
pa_t *pa = (pa_t*)data;
|
pa_t *pa = (pa_t*)data;
|
||||||
if (!pa)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
struct string_list *s = pa->devicelist ? string_list_clone(pa->devicelist) : NULL;
|
if (pa && pa->devicelist)
|
||||||
if (!s)
|
return string_list_clone(pa->devicelist);
|
||||||
return NULL;
|
|
||||||
return s;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pulse_device_list_free(void *data, void *array_list_data)
|
static void pulse_device_list_free(void *data, void *array_list_data)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user