Skip to content

Commit

Permalink
Fix PulseAudio freezing
Browse files Browse the repository at this point in the history
* Fix freezing after restarting pipewire service
* Rewrite the logic for starting/stopping stream
* Reduce boilerplate code
  • Loading branch information
viachaslavic committed Jan 20, 2025
1 parent 391ba55 commit c98af91
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 193 deletions.
85 changes: 69 additions & 16 deletions audio/common/pipewire.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@
#include "pipewire.h"

#include <spa/utils/result.h>

#include <pipewire/pipewire.h>

#include <retro_assert.h>

#include "verbosity.h"
#include "../../verbosity.h"


static void core_error_cb(void *data, uint32_t id, int seq, int res, const char *message)
Expand Down Expand Up @@ -141,35 +140,89 @@ bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *s
return active ? st == PW_STREAM_STATE_STREAMING : st == PW_STREAM_STATE_PAUSED;
}

bool pipewire_core_init(pipewire_core_t *pw, const char *loop_name)
bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events)
{
retro_assert(pw);
retro_assert(!*pw);

pw->thread_loop = pw_thread_loop_new(loop_name, NULL);
if (!pw->thread_loop)
*pw = (pipewire_core_t*)calloc(1, sizeof(pipewire_core_t));
if (!*pw)
return false;

pw->ctx = pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
if (!pw->ctx)
(*pw)->devicelist = string_list_new();
if (!(*pw)->devicelist)
{
free(*pw);
*pw = NULL;
return false;
}

if (pw_thread_loop_start(pw->thread_loop) < 0)
pw_init(NULL, NULL);

(*pw)->thread_loop = pw_thread_loop_new(loop_name, NULL);
if (!(*pw)->thread_loop)
return false;

pw_thread_loop_lock(pw->thread_loop);
(*pw)->ctx = pw_context_new(pw_thread_loop_get_loop((*pw)->thread_loop), NULL, 0);
if (!(*pw)->ctx)
return false;

pw->core = pw_context_connect(pw->ctx, NULL, 0);
if (!pw->core)
if (pw_thread_loop_start((*pw)->thread_loop) < 0)
return false;

pw_thread_loop_lock((*pw)->thread_loop);

(*pw)->core = pw_context_connect((*pw)->ctx, NULL, 0);
if (!(*pw)->core)
goto unlock;

if (pw_core_add_listener(pw->core,
&pw->core_listener,
&core_events, pw) < 0)
if (pw_core_add_listener((*pw)->core,
&(*pw)->core_listener,
&core_events, *pw) < 0)
goto unlock;

if (events)
{
(*pw)->registry = pw_core_get_registry((*pw)->core, PW_VERSION_REGISTRY, 0);
spa_zero((*pw)->registry_listener);
pw_registry_add_listener((*pw)->registry, &(*pw)->registry_listener, events, *pw);
}

return true;

unlock:
pw_thread_loop_unlock(pw->thread_loop);
pw_thread_loop_unlock((*pw)->thread_loop);
return false;
}

void pipewire_core_deinit(pipewire_core_t *pw)
{
if (!pw)
return pw_deinit();

if (pw->thread_loop)
{
pw_thread_loop_unlock(pw->thread_loop);
pw_thread_loop_stop(pw->thread_loop);
}

if (pw->registry)
pw_proxy_destroy((struct pw_proxy*)pw->registry);

if (pw->core)
{
spa_hook_remove(&pw->core_listener);
spa_zero(pw->core_listener);
pw_core_disconnect(pw->core);
}

if (pw->ctx)
pw_context_destroy(pw->ctx);

pw_thread_loop_destroy(pw->thread_loop);

if (pw->devicelist)
string_list_free(pw->devicelist);

free(pw);
pw_deinit();
}
10 changes: 7 additions & 3 deletions audio/common/pipewire.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@

#include <spa/param/audio/format-utils.h>
#include <spa/utils/ringbuffer.h>

#include <pipewire/pipewire.h>

#include <lists/string_list.h>


#define PW_RARCH_APPNAME "RetroArch"

/* String literals are part of the PipeWire specification */
Expand Down Expand Up @@ -54,9 +56,11 @@ size_t pipewire_calc_frame_size(enum spa_audio_format fmt, uint32_t nchannels);

void pipewire_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS]);

bool pipewire_core_init(pipewire_core_t *pipewire, const char *loop_name);
bool pipewire_core_init(pipewire_core_t **pw, const char *loop_name, const struct pw_registry_events *events);

void pipewire_core_deinit(pipewire_core_t *pw);

void pipewire_core_wait_resync(pipewire_core_t *pipewire);
void pipewire_core_wait_resync(pipewire_core_t *pw);

bool pipewire_stream_set_active(struct pw_thread_loop *loop, struct pw_stream *stream, bool active);

Expand Down
Loading

0 comments on commit c98af91

Please sign in to comment.