Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix PulseAudio freeze #17316

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions audio/drivers/alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
15 changes: 9 additions & 6 deletions audio/drivers/pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
55 changes: 39 additions & 16 deletions audio/drivers/pulse.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ typedef struct
bool nonblock;
bool success;
bool is_paused;
bool is_ready;
struct string_list *devicelist;
} pa_t;

Expand Down Expand Up @@ -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);
}

Expand All @@ -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:
Expand All @@ -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,
Expand All @@ -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:
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;

Expand All @@ -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)
{
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);

Expand All @@ -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)
Expand Down
Loading