pipewire: Use the core version info for the preferred version check

When running in a container, the underlying Pipewire version may not match the library version, so retrieve and check the core version info to see if it meets the preferred version requirements.
main
Frank Praznik 2024-04-17 21:41:04 -04:00
parent bc6ad3ee43
commit a923db9d0a
No known key found for this signature in database
1 changed files with 111 additions and 25 deletions

View File

@ -88,6 +88,11 @@ static SDL_bool pipewire_initialized = SDL_FALSE;
static const char *(*PIPEWIRE_pw_get_library_version)(void);
static void (*PIPEWIRE_pw_init)(int *, char ***);
static void (*PIPEWIRE_pw_deinit)(void);
static struct pw_main_loop *(*PIPEWIRE_pw_main_loop_new)(struct pw_main_loop *loop);
static struct pw_loop *(*PIPEWIRE_pw_main_loop_get_loop)(struct pw_main_loop *loop);
static int (*PIPEWIRE_pw_main_loop_run)(struct pw_main_loop *loop);
static int (*PIPEWIRE_pw_main_loop_quit)(struct pw_main_loop *loop);
static void(*PIPEWIRE_pw_main_loop_destroy)(struct pw_main_loop *loop);
static struct pw_thread_loop *(*PIPEWIRE_pw_thread_loop_new)(const char *, const struct spa_dict *);
static void (*PIPEWIRE_pw_thread_loop_destroy)(struct pw_thread_loop *);
static void (*PIPEWIRE_pw_thread_loop_stop)(struct pw_thread_loop *);
@ -116,9 +121,9 @@ static struct pw_properties *(*PIPEWIRE_pw_properties_new)(const char *, ...)SPA
static int (*PIPEWIRE_pw_properties_set)(struct pw_properties *, const char *, const char *);
static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *, const char *, ...) SPA_PRINTF_FUNC(3, 4);
static int pipewire_version_major;
static int pipewire_version_minor;
static int pipewire_version_patch;
static int pipewire_library_version_major;
static int pipewire_library_version_minor;
static int pipewire_library_version_patch;
#ifdef SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC
@ -176,6 +181,11 @@ static int load_pipewire_syms(void)
SDL_PIPEWIRE_SYM(pw_get_library_version);
SDL_PIPEWIRE_SYM(pw_init);
SDL_PIPEWIRE_SYM(pw_deinit);
SDL_PIPEWIRE_SYM(pw_main_loop_new);
SDL_PIPEWIRE_SYM(pw_main_loop_get_loop);
SDL_PIPEWIRE_SYM(pw_main_loop_run);
SDL_PIPEWIRE_SYM(pw_main_loop_quit);
SDL_PIPEWIRE_SYM(pw_main_loop_destroy);
SDL_PIPEWIRE_SYM(pw_thread_loop_new);
SDL_PIPEWIRE_SYM(pw_thread_loop_destroy);
SDL_PIPEWIRE_SYM(pw_thread_loop_stop);
@ -205,30 +215,118 @@ static int load_pipewire_syms(void)
return 0;
}
static SDL_bool pipewire_version_at_least(int major, int minor, int patch)
static SDL_bool pipewire_library_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);
return (pipewire_library_version_major >= major) &&
(pipewire_library_version_major > major || pipewire_library_version_minor >= minor) &&
(pipewire_library_version_major > major || pipewire_library_version_minor > minor || pipewire_library_version_patch >= patch);
}
static int init_pipewire_library(int major, int minor, int patch)
/* 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)
{
if (!load_pipewire_library()) {
if (!load_pipewire_syms()) {
int nargs;
const char *version = PIPEWIRE_pw_get_library_version();
nargs = SDL_sscanf(version, "%d.%d.%d", &pipewire_version_major, &pipewire_version_minor, &pipewire_version_patch);
nargs = SDL_sscanf(version, "%d.%d.%d", &pipewire_library_version_major, &pipewire_library_version_minor, &pipewire_library_version_patch);
if (nargs < 3) {
return -1;
}
if (pipewire_version_at_least(major, minor, patch)) {
// SDL can build against 0.3.20, but requires 0.3.24 at minimum
if (pipewire_library_version_at_least(0, 3, 24)) {
PIPEWIRE_pw_init(NULL, NULL);
if (!check_preferred_version || pipewire_core_version_at_least(1, 0, 0)) {
return 0;
}
}
}
}
return -1;
}
@ -1161,7 +1259,7 @@ static int PIPEWIRE_OpenDevice(SDL_AudioDevice *device)
* the stream to its target. The target_id parameter in pw_stream_connect() is
* now deprecated and should always be PW_ID_ANY.
*/
if (pipewire_version_at_least(0, 3, 44)) {
if (pipewire_library_version_at_least(0, 3, 44)) {
if (node_id != PW_ID_ANY) {
const struct io_node *node;
@ -1255,20 +1353,8 @@ static void PIPEWIRE_Deinitialize(void)
static SDL_bool PipewireInitialize(SDL_AudioDriverImpl *impl, SDL_bool check_preferred_version)
{
if (!pipewire_initialized) {
int major, minor, patch;
// SDL can build against 0.3.20, but requires 0.3.24 at minimum, and 1.0.0 for preferred default status.
if (check_preferred_version) {
major = 1;
minor = 0;
patch = 0;
} else {
major = 0;
minor = 3;
patch = 24;
}
if (init_pipewire_library(major, minor, patch) < 0) {
if (init_pipewire_library(check_preferred_version) < 0) {
return SDL_FALSE;
}