pipewire: Use PW_KEY_TARGET_OBJECT to specify stream connection nodes Pipewire 0.3.44 introduced PW_KEY_TARGET_OBJECT, which is to be used to specify target connection nodes for streams. This parameter takes either a node path (PW_KEY_NODE_NAME) or serial number (PW_KEY_OBJECT_SERIAL) to specify a target node. The former is used in this case since the path is already being retrieved and stored for other purposes. The target_id parameter in pw_stream_connect() is now deprecated and should always be PW_ID_ANY when PW_KEY_TARGET_OBJECT is used.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c
index aefa192..e56344d 100644
--- a/src/audio/pipewire/SDL_pipewire.c
+++ b/src/audio/pipewire/SDL_pipewire.c
@@ -34,8 +34,8 @@
/*
* The following keys are defined for compatability when building against older versions of Pipewire
- * prior to their introduction and can be removed if the minimum required Pipewire version is increased
- * to or beyond their point of introduction.
+ * prior to their introduction and can be removed if the minimum required Pipewire build version is
+ * increased to or beyond their point of introduction.
*/
/*
@@ -55,6 +55,14 @@
#endif
/*
+ * Introduced in 0.3.44
+ * Taken from src/pipewire/keys.h
+ */
+#ifndef PW_KEY_TARGET_OBJECT
+#define PW_KEY_TARGET_OBJECT "target.object"
+#endif
+
+/*
* This seems to be a sane lower limit as Pipewire
* uses it in several of it's own modules.
*/
@@ -113,6 +121,9 @@ static int (*PIPEWIRE_pw_properties_setf)(struct pw_properties *, const char *,
static const char *pipewire_library = SDL_AUDIO_DRIVER_PIPEWIRE_DYNAMIC;
static void *pipewire_handle = NULL;
+static int pipewire_version_major;
+static int pipewire_version_minor;
+static int pipewire_version_patch;
static int
pipewire_dlsym(const char *fn, void **addr)
@@ -202,20 +213,28 @@ load_pipewire_syms()
return 0;
}
+SDL_FORCE_INLINE SDL_bool
+pipewire_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);
+}
+
static int
init_pipewire_library()
{
if (!load_pipewire_library()) {
if (!load_pipewire_syms()) {
- int major, minor, patch, nargs;
+ int nargs;
const char *version = PIPEWIRE_pw_get_library_version();
- nargs = SDL_sscanf(version, "%d.%d.%d", &major, &minor, &patch);
+ nargs = SDL_sscanf(version, "%d.%d.%d", &pipewire_version_major, &pipewire_version_minor, &pipewire_version_patch);
if (nargs < 3) {
return -1;
}
/* SDL can build against 0.3.20, but requires 0.3.24 */
- if ((major >= 0) && (major > 0 || minor >= 3) && (major > 0 || minor > 3 || patch >= 24)) {
+ if (pipewire_version_at_least(0, 3, 24)) {
PIPEWIRE_pw_init(NULL, NULL);
return 0;
}
@@ -372,7 +391,19 @@ io_list_clear()
}
static struct io_node*
-io_list_get(char *path)
+io_list_get_by_id(Uint32 id)
+{
+ struct io_node *n, *temp;
+ spa_list_for_each_safe (n, temp, &hotplug_io_list, link) {
+ if (n->id == id) {
+ return n;
+ }
+ }
+ return NULL;
+}
+
+static struct io_node*
+io_list_get_by_path(char *path)
{
struct io_node *n, *temp;
spa_list_for_each_safe (n, temp, &hotplug_io_list, link) {
@@ -1148,7 +1179,7 @@ PIPEWIRE_OpenDevice(_THIS, const char *devname)
struct SDL_PrivateAudioData *priv;
struct pw_properties *props;
const char *app_name, *stream_name, *stream_role, *error;
- const Uint32 node_id = this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(this->handle);
+ Uint32 node_id = this->handle == NULL ? PW_ID_ANY : PW_HANDLE_TO_ID(this->handle);
SDL_bool iscapture = this->iscapture;
int res;
@@ -1229,6 +1260,26 @@ PIPEWIRE_OpenDevice(_THIS, const char *devname)
PIPEWIRE_pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", this->spec.freq);
PIPEWIRE_pw_properties_set(props, PW_KEY_NODE_ALWAYS_PROCESS, "true");
+ /*
+ * Pipewire 0.3.44 introduced PW_KEY_TARGET_OBJECT that takes either a path
+ * (PW_KEY_NODE_NAME) or node serial number (PE_KEY_OBJECT_SERIAL) to connect
+ * 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 (node_id != PW_ID_ANY) {
+ const struct io_node *node;
+
+ PIPEWIRE_pw_thread_loop_lock(hotplug_loop);
+ if ((node = io_list_get_by_id(node_id))) {
+ PIPEWIRE_pw_properties_set(props, PW_KEY_TARGET_OBJECT, node->path);
+ }
+ PIPEWIRE_pw_thread_loop_unlock(hotplug_loop);
+
+ node_id = PW_ID_ANY;
+ }
+ }
+
/* Create the new stream */
priv->stream = PIPEWIRE_pw_stream_new_simple(PIPEWIRE_pw_thread_loop_get_loop(priv->loop), stream_name, props,
iscapture ? &stream_input_events : &stream_output_events, this);
@@ -1315,7 +1366,7 @@ PIPEWIRE_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture)
target = pipewire_default_sink_id;
}
- node = io_list_get(target);
+ node = io_list_get_by_path(target);
if (node == NULL) {
ret = SDL_SetError("PipeWire device list is out of sync with defaults");
goto failed;