|
@@ -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,27 +215,115 @@ 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);
|
|
|
- return 0;
|
|
|
+
|
|
|
+ if (!check_preferred_version || pipewire_core_version_at_least(1, 0, 0)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -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;
|
|
|
}
|
|
|
|