gst: use target.object instead of node.target, soft-deprecate ids

Use target-object=<serial/name> instead of path=<id> for specifying
sink/src targets. Deprecate path= argument.

Change device provider to preferably expose serials instead of ids.
This commit is contained in:
Pauli Virtanen 2022-03-06 14:10:55 +02:00 committed by Wim Taymans
parent d66e9f1ae1
commit 67a27d80c6
6 changed files with 128 additions and 12 deletions

View file

@ -44,6 +44,7 @@ G_DEFINE_TYPE (GstPipeWireDevice, gst_pipewire_device, GST_TYPE_DEVICE);
enum enum
{ {
PROP_ID = 1, PROP_ID = 1,
PROP_SERIAL,
}; };
static GstElement * static GstElement *
@ -51,12 +52,16 @@ gst_pipewire_device_create_element (GstDevice * device, const gchar * name)
{ {
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device); GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
GstElement *elem; GstElement *elem;
gchar *str; gchar *id_str, *serial_str;
elem = gst_element_factory_make (pipewire_dev->element, name); elem = gst_element_factory_make (pipewire_dev->element, name);
str = g_strdup_printf ("%u", pipewire_dev->id);
g_object_set (elem, "path", str, NULL); /* XXX: eventually only add target-object here */
g_free (str); id_str = g_strdup_printf ("%u", pipewire_dev->id);
serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial);
g_object_set (elem, "path", id_str, "target-object", serial_str, NULL);
g_free (id_str);
g_free (serial_str);
return elem; return elem;
} }
@ -65,7 +70,7 @@ static gboolean
gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * element) gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * element)
{ {
GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device); GstPipeWireDevice *pipewire_dev = GST_PIPEWIRE_DEVICE (device);
gchar *str; gchar *id_str, *serial_str;
if (spa_streq(pipewire_dev->element, "pipewiresrc")) { if (spa_streq(pipewire_dev->element, "pipewiresrc")) {
if (!GST_IS_PIPEWIRE_SRC (element)) if (!GST_IS_PIPEWIRE_SRC (element))
@ -77,9 +82,12 @@ gst_pipewire_device_reconfigure_element (GstDevice * device, GstElement * elemen
g_assert_not_reached (); g_assert_not_reached ();
} }
str = g_strdup_printf ("%u", pipewire_dev->id); /* XXX: eventually only add target-object here */
g_object_set (element, "path", str, NULL); id_str = g_strdup_printf ("%u", pipewire_dev->id);
g_free (str); serial_str = g_strdup_printf ("%"PRIu64, pipewire_dev->serial);
g_object_set (element, "path", id_str, "target-object", serial_str, NULL);
g_free (id_str);
g_free (serial_str);
return TRUE; return TRUE;
} }
@ -97,6 +105,9 @@ gst_pipewire_device_get_property (GObject * object, guint prop_id,
case PROP_ID: case PROP_ID:
g_value_set_uint (value, device->id); g_value_set_uint (value, device->id);
break; break;
case PROP_SERIAL:
g_value_set_uint64 (value, device->serial);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -115,6 +126,9 @@ gst_pipewire_device_set_property (GObject * object, guint prop_id,
case PROP_ID: case PROP_ID:
device->id = g_value_get_uint (value); device->id = g_value_get_uint (value);
break; break;
case PROP_SERIAL:
device->serial = g_value_get_uint64 (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -144,6 +158,11 @@ gst_pipewire_device_class_init (GstPipeWireDeviceClass * klass)
g_param_spec_uint ("id", "Id", g_param_spec_uint ("id", "Id",
"The internal id of the PipeWire device", 0, G_MAXUINT32, SPA_ID_INVALID, "The internal id of the PipeWire device", 0, G_MAXUINT32, SPA_ID_INVALID,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_SERIAL,
g_param_spec_uint64 ("serial", "Serial",
"The internal serial of the PipeWire device", 0, G_MAXUINT64, SPA_ID_INVALID,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
} }
static void static void
@ -176,6 +195,7 @@ struct node_data {
struct pw_node *proxy; struct pw_node *proxy;
struct spa_hook proxy_listener; struct spa_hook proxy_listener;
uint32_t id; uint32_t id;
uint64_t serial;
struct spa_hook node_listener; struct spa_hook node_listener;
struct pw_node_info *info; struct pw_node_info *info;
GstCaps *caps; GstCaps *caps;
@ -187,6 +207,7 @@ struct port_data {
struct pw_port *proxy; struct pw_port *proxy;
struct spa_hook proxy_listener; struct spa_hook proxy_listener;
uint32_t id; uint32_t id;
uint64_t serial;
struct spa_hook port_listener; struct spa_hook port_listener;
}; };
@ -236,9 +257,10 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data)
gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE, gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE,
"display-name", name, "caps", data->caps, "device-class", klass, "display-name", name, "caps", data->caps, "device-class", klass,
"id", data->id, "properties", props, NULL); "id", data->id, "serial", data->serial, "properties", props, NULL);
gstdev->id = data->id; gstdev->id = data->id;
gstdev->serial = data->serial;
gstdev->type = type; gstdev->type = type;
gstdev->element = element; gstdev->element = element;
if (props) if (props)
@ -476,6 +498,8 @@ static void registry_event_global(void *data, uint32_t id, uint32_t permissions,
nd->self = self; nd->self = self;
nd->proxy = node; nd->proxy = node;
nd->id = id; nd->id = id;
if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &nd->serial, 0))
nd->serial = SPA_ID_INVALID;
spa_list_append(&rd->nodes, &nd->link); spa_list_append(&rd->nodes, &nd->link);
pw_node_add_listener(node, &nd->node_listener, &node_events, nd); pw_node_add_listener(node, &nd->node_listener, &node_events, nd);
pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd); pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd);
@ -500,6 +524,8 @@ static void registry_event_global(void *data, uint32_t id, uint32_t permissions,
pd->node_data = nd; pd->node_data = nd;
pd->proxy = port; pd->proxy = port;
pd->id = id; pd->id = id;
if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &pd->serial, 0))
pd->serial = SPA_ID_INVALID;
pw_port_add_listener(port, &pd->port_listener, &port_events, pd); pw_port_add_listener(port, &pd->port_listener, &port_events, pd);
pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd); pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd);
resync(self); resync(self);

View file

@ -56,6 +56,7 @@ struct _GstPipeWireDevice {
GstPipeWireDeviceType type; GstPipeWireDeviceType type;
uint32_t id; uint32_t id;
uint64_t serial;
const gchar *element; const gchar *element;
}; };

View file

@ -60,6 +60,7 @@ enum
{ {
PROP_0, PROP_0,
PROP_PATH, PROP_PATH,
PROP_TARGET_OBJECT,
PROP_CLIENT_NAME, PROP_CLIENT_NAME,
PROP_STREAM_PROPERTIES, PROP_STREAM_PROPERTIES,
PROP_MODE, PROP_MODE,
@ -124,6 +125,7 @@ gst_pipewire_sink_finalize (GObject * object)
if (pwsink->properties) if (pwsink->properties)
gst_structure_free (pwsink->properties); gst_structure_free (pwsink->properties);
g_free (pwsink->path); g_free (pwsink->path);
g_free (pwsink->target_object);
g_free (pwsink->client_name); g_free (pwsink->client_name);
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
@ -160,6 +162,16 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass)
"The sink path to connect to (NULL = default)", "The sink path to connect to (NULL = default)",
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_DEPRECATED));
g_object_class_install_property (gobject_class,
PROP_TARGET_OBJECT,
g_param_spec_string ("target-object",
"Target object",
"The sink name/serial to connect to (NULL = default)",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
@ -339,6 +351,11 @@ gst_pipewire_sink_set_property (GObject * object, guint prop_id,
pwsink->path = g_value_dup_string (value); pwsink->path = g_value_dup_string (value);
break; break;
case PROP_TARGET_OBJECT:
g_free (pwsink->target_object);
pwsink->target_object = g_value_dup_string (value);
break;
case PROP_CLIENT_NAME: case PROP_CLIENT_NAME:
g_free (pwsink->client_name); g_free (pwsink->client_name);
pwsink->client_name = g_value_dup_string (value); pwsink->client_name = g_value_dup_string (value);
@ -376,6 +393,10 @@ gst_pipewire_sink_get_property (GObject * object, guint prop_id,
g_value_set_string (value, pwsink->path); g_value_set_string (value, pwsink->path);
break; break;
case PROP_TARGET_OBJECT:
g_value_set_string (value, pwsink->target_object);
break;
case PROP_CLIENT_NAME: case PROP_CLIENT_NAME:
g_value_set_string (value, pwsink->client_name); g_value_set_string (value, pwsink->client_name);
break; break;
@ -522,15 +543,37 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
if (state == PW_STREAM_STATE_UNCONNECTED) { if (state == PW_STREAM_STATE_UNCONNECTED) {
enum pw_stream_flags flags = 0; enum pw_stream_flags flags = 0;
uint32_t target_id;
if (pwsink->mode != GST_PIPEWIRE_SINK_MODE_PROVIDE) if (pwsink->mode != GST_PIPEWIRE_SINK_MODE_PROVIDE)
flags |= PW_STREAM_FLAG_AUTOCONNECT; flags |= PW_STREAM_FLAG_AUTOCONNECT;
else else
flags |= PW_STREAM_FLAG_DRIVER; flags |= PW_STREAM_FLAG_DRIVER;
target_id = pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY;
if (pwsink->target_object) {
struct spa_dict_item items[2] = {
SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsink->target_object),
SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL),
};
struct spa_dict dict = SPA_DICT_INIT_ARRAY(items);
uint64_t serial;
/* If target.object is a name, set it also to node.target */
if (spa_atou64(pwsink->target_object, &serial, 0)) {
dict.n_items = 1;
} else {
target_id = PW_ID_ANY;
items[1].value = pwsink->target_object;
}
pw_stream_update_properties (pwsink->stream, &dict);
}
pw_stream_connect (pwsink->stream, pw_stream_connect (pwsink->stream,
PW_DIRECTION_OUTPUT, PW_DIRECTION_OUTPUT,
pwsink->path ? (uint32_t)atoi(pwsink->path) : PW_ID_ANY, target_id,
flags, flags,
(const struct spa_pod **) possible->pdata, (const struct spa_pod **) possible->pdata,
possible->len); possible->len);

View file

@ -78,6 +78,7 @@ struct _GstPipeWireSink {
/*< private >*/ /*< private >*/
gchar *path; gchar *path;
gchar *target_object;
gchar *client_name; gchar *client_name;
int fd; int fd;

View file

@ -67,6 +67,7 @@ enum
{ {
PROP_0, PROP_0,
PROP_PATH, PROP_PATH,
PROP_TARGET_OBJECT,
PROP_CLIENT_NAME, PROP_CLIENT_NAME,
PROP_STREAM_PROPERTIES, PROP_STREAM_PROPERTIES,
PROP_ALWAYS_COPY, PROP_ALWAYS_COPY,
@ -116,6 +117,11 @@ gst_pipewire_src_set_property (GObject * object, guint prop_id,
pwsrc->path = g_value_dup_string (value); pwsrc->path = g_value_dup_string (value);
break; break;
case PROP_TARGET_OBJECT:
g_free (pwsrc->target_object);
pwsrc->target_object = g_value_dup_string (value);
break;
case PROP_CLIENT_NAME: case PROP_CLIENT_NAME:
g_free (pwsrc->client_name); g_free (pwsrc->client_name);
pwsrc->client_name = g_value_dup_string (value); pwsrc->client_name = g_value_dup_string (value);
@ -169,6 +175,10 @@ gst_pipewire_src_get_property (GObject * object, guint prop_id,
g_value_set_string (value, pwsrc->path); g_value_set_string (value, pwsrc->path);
break; break;
case PROP_TARGET_OBJECT:
g_value_set_string (value, pwsrc->target_object);
break;
case PROP_CLIENT_NAME: case PROP_CLIENT_NAME:
g_value_set_string (value, pwsrc->client_name); g_value_set_string (value, pwsrc->client_name);
break; break;
@ -244,6 +254,7 @@ gst_pipewire_src_finalize (GObject * object)
if (pwsrc->clock) if (pwsrc->clock)
gst_object_unref (pwsrc->clock); gst_object_unref (pwsrc->clock);
g_free (pwsrc->path); g_free (pwsrc->path);
g_free (pwsrc->target_object);
g_free (pwsrc->client_name); g_free (pwsrc->client_name);
g_object_unref(pwsrc->pool); g_object_unref(pwsrc->pool);
@ -274,6 +285,16 @@ gst_pipewire_src_class_init (GstPipeWireSrcClass * klass)
"The source path to connect to (NULL = default)", "The source path to connect to (NULL = default)",
NULL, NULL,
G_PARAM_READWRITE | G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS |
G_PARAM_DEPRECATED));
g_object_class_install_property (gobject_class,
PROP_TARGET_OBJECT,
g_param_spec_string ("target-object",
"Target object",
"The source name/serial to connect to (NULL = default)",
NULL,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS)); G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,
@ -675,6 +696,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
GPtrArray *possible; GPtrArray *possible;
const char *error = NULL; const char *error = NULL;
struct timespec abstime; struct timespec abstime;
uint32_t target_id;
/* first see what is possible on our source pad */ /* first see what is possible on our source pad */
thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL); thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
@ -727,11 +749,33 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
} }
} }
GST_DEBUG_OBJECT (basesrc, "connect capture with path %s", pwsrc->path); target_id = pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY;
if (pwsrc->target_object) {
struct spa_dict_item items[2] = {
SPA_DICT_ITEM_INIT(PW_KEY_TARGET_OBJECT, pwsrc->target_object),
SPA_DICT_ITEM_INIT(PW_KEY_NODE_TARGET, NULL),
};
struct spa_dict dict = SPA_DICT_INIT_ARRAY(items);
uint64_t serial;
/* If target.object is a name, set it also to node.target */
if (spa_atou64(pwsrc->target_object, &serial, 0)) {
dict.n_items = 1;
} else {
target_id = PW_ID_ANY;
items[1].value = pwsrc->target_object;
}
pw_stream_update_properties (pwsrc->stream, &dict);
}
GST_DEBUG_OBJECT (basesrc, "connect capture with path %s, target-object %s",
pwsrc->path, pwsrc->target_object);
pwsrc->negotiated = FALSE; pwsrc->negotiated = FALSE;
pw_stream_connect (pwsrc->stream, pw_stream_connect (pwsrc->stream,
PW_DIRECTION_INPUT, PW_DIRECTION_INPUT,
pwsrc->path ? (uint32_t)atoi(pwsrc->path) : PW_ID_ANY, target_id,
PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_DONT_RECONNECT, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_DONT_RECONNECT,
(const struct spa_pod **)possible->pdata, (const struct spa_pod **)possible->pdata,
possible->len); possible->len);

View file

@ -60,6 +60,7 @@ struct _GstPipeWireSrc {
/*< private >*/ /*< private >*/
gchar *path; gchar *path;
gchar *target_object;
gchar *client_name; gchar *client_name;
gboolean always_copy; gboolean always_copy;
gint min_buffers; gint min_buffers;