pipewire: Consolidate registry enumeration instances

The preferred Pipewire path requires both devices being available, and that a sufficiently recent underlying core version is running on the host system. These criteria were being checked separately, which required two separate instances of enumerating the Pipewire registry, which is a fairly heavy operation. Move the version info callback to the main hotplug thread to avoid enumerating the registry twice, and check for both the version and required devices at the same time on the preferred path.
This commit is contained in:
Frank Praznik 2024-07-11 12:50:21 -04:00
parent f437fe75f2
commit 186fec2560
1 changed files with 27 additions and 95 deletions

View File

@ -179,99 +179,12 @@ static int load_pipewire_syms(void)
return 0;
}
/* When in a container, the library version can differ from the underlying core version,
* so make sure the underlying Pipewire implementation meets the version requirement.
*/
struct version_data
{
struct pw_main_loop *loop;
int major, minor, patch;
int seq;
};
void version_check_core_info_callback(void *data, const struct pw_core_info *info)
{
struct version_data *v = data;
if (SDL_sscanf(info->version, "%d.%d.%d", &v->major, &v->minor, &v->patch) < 3) {
v->major = 0;
v->minor = 0;
v->patch = 0;
}
}
void version_check_core_done_callback(void *data, uint32_t id, int seq)
{
struct version_data *v = data;
if (id == PW_ID_CORE && v->seq == seq) {
PIPEWIRE_pw_main_loop_quit(v->loop);
}
}
static const struct pw_core_events version_check_core_events = { PW_VERSION_CORE_EVENTS, .info = version_check_core_info_callback, .done = version_check_core_done_callback };
SDL_bool pipewire_core_version_at_least(int major, int minor, int patch)
{
struct pw_main_loop *loop = NULL;
struct pw_context *context = NULL;
struct pw_core *core = NULL;
struct version_data version_data;
struct spa_hook core_listener;
SDL_bool ret = SDL_FALSE;
loop = PIPEWIRE_pw_main_loop_new(NULL);
if (!loop) {
goto done;
}
context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_main_loop_get_loop(loop), NULL, 0);
if (!context) {
goto done;
}
core = PIPEWIRE_pw_context_connect(context, NULL, 0);
if (!core) {
goto done;
}
/* Attach a core listener and get the version. */
spa_zero(version_data);
version_data.loop = loop;
pw_core_add_listener(core, &core_listener, &version_check_core_events, &version_data);
version_data.seq = pw_core_sync(core, PW_ID_CORE, 0);
PIPEWIRE_pw_main_loop_run(loop);
spa_hook_remove(&core_listener);
ret = (version_data.major >= major) &&
(version_data.major > major || version_data.minor >= minor) &&
(version_data.major > major || version_data.minor > minor || version_data.patch >= patch);
done:
if (core) {
PIPEWIRE_pw_core_disconnect(core);
}
if (context) {
PIPEWIRE_pw_context_destroy(context);
}
if (loop) {
PIPEWIRE_pw_main_loop_destroy(loop);
}
return ret;
}
static int init_pipewire_library(SDL_bool check_preferred_version)
static int init_pipewire_library()
{
if (!load_pipewire_library()) {
if (!load_pipewire_syms()) {
PIPEWIRE_pw_init(NULL, NULL);
if (!check_preferred_version || pipewire_core_version_at_least(1, 0, 0)) {
return 0;
}
return 0;
}
}
@ -335,9 +248,19 @@ static int hotplug_init_seq_val;
static SDL_bool hotplug_init_complete;
static SDL_bool hotplug_events_enabled;
static int pipewire_version_major;
static int pipewire_version_minor;
static int pipewire_version_patch;
static char *pipewire_default_sink_id = NULL;
static char *pipewire_default_source_id = NULL;
static SDL_bool pipewire_core_version_at_least(int major, int minor, int patch)
{
return (pipewire_version_major >= major) &&
(pipewire_version_major > major || pipewire_version_minor >= minor) &&
(pipewire_version_major > major || pipewire_version_minor > minor || pipewire_version_patch >= patch);
}
// The active node list
static SDL_bool io_list_check_add(struct io_node *node)
{
@ -484,6 +407,15 @@ static void core_events_hotplug_init_callback(void *object, uint32_t id, int seq
}
}
static void core_events_hotplug_info_callback(void *data, const struct pw_core_info *info)
{
if (SDL_sscanf(info->version, "%d.%d.%d", &pipewire_version_major, &pipewire_version_minor, &pipewire_version_patch) < 3) {
pipewire_version_major = 0;
pipewire_version_minor = 0;
pipewire_version_patch = 0;
}
}
static void core_events_interface_callback(void *object, uint32_t id, int seq)
{
struct node_object *node = object;
@ -511,7 +443,7 @@ static void core_events_metadata_callback(void *object, uint32_t id, int seq)
}
}
static const struct pw_core_events hotplug_init_core_events = { PW_VERSION_CORE_EVENTS, .done = core_events_hotplug_init_callback };
static const struct pw_core_events hotplug_init_core_events = { PW_VERSION_CORE_EVENTS, .info = core_events_hotplug_info_callback, .done = core_events_hotplug_init_callback };
static const struct pw_core_events interface_core_events = { PW_VERSION_CORE_EVENTS, .done = core_events_interface_callback };
static const struct pw_core_events metadata_core_events = { PW_VERSION_CORE_EVENTS, .done = core_events_metadata_callback };
@ -1292,11 +1224,11 @@ static void PIPEWIRE_Deinitialize(void)
}
}
static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl, SDL_bool check_preferred_version)
static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl)
{
if (!pipewire_initialized) {
if (init_pipewire_library(check_preferred_version) < 0) {
if (init_pipewire_library() < 0) {
return SDL_FALSE;
}
@ -1326,7 +1258,7 @@ static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl, SDL_bool check_pre
static SDL_bool PIPEWIRE_PREFERRED_Init(SDL_AudioDriverImpl *impl)
{
if (!PipewireInitialize(impl, SDL_TRUE)) {
if (!PipewireInitialize(impl)) {
return SDL_FALSE;
}
@ -1342,7 +1274,7 @@ static SDL_bool PIPEWIRE_PREFERRED_Init(SDL_AudioDriverImpl *impl)
PIPEWIRE_pw_thread_loop_unlock(hotplug_loop);
if (no_devices) {
if (no_devices || !pipewire_core_version_at_least(1, 0, 0)) {
PIPEWIRE_Deinitialize();
return SDL_FALSE;
}
@ -1352,7 +1284,7 @@ static SDL_bool PIPEWIRE_PREFERRED_Init(SDL_AudioDriverImpl *impl)
static SDL_bool PIPEWIRE_Init(SDL_AudioDriverImpl *impl)
{
return PipewireInitialize(impl, SDL_FALSE);
return PipewireInitialize(impl);
}
AudioBootStrap PIPEWIRE_PREFERRED_bootstrap = {