From ecf4b071e5e474a362cde42dfdc8713da4a5b550 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 14 Dec 2023 13:00:00 +0100 Subject: [PATCH] gst: keep track of node ports Keep a list of ports for the node. When the node goes away, clear the port links to the node. Handle the case where the port no longer has a node. This avoids a crash when, for example, the node permission is removed and the port points to the now freed node_data. Fixes #3708 --- src/gst/gstpipewiredeviceprovider.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index 03d763f40..30c436e52 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -180,9 +180,11 @@ struct node_data { struct pw_node_info *info; GstCaps *caps; GstDevice *dev; + struct spa_list ports; }; struct port_data { + struct spa_list link; struct node_data *node_data; struct pw_port *proxy; struct spa_hook proxy_listener; @@ -353,6 +355,9 @@ static void port_event_info(void *data, const struct pw_port_info *info) pw_log_debug("%p", port_data); + if (node_data == NULL) + return; + if (info->change_mask & PW_PORT_CHANGE_MASK_PARAMS) { for (i = 0; i < info->n_params; i++) { uint32_t id = info->params[i].id; @@ -375,6 +380,9 @@ static void port_event_param(void *data, int seq, uint32_t id, struct node_data *node_data = port_data->node_data; GstCaps *c1; + if (node_data == NULL) + return; + c1 = gst_caps_from_format (param); if (c1 && node_data->caps) gst_caps_append (node_data->caps, c1); @@ -438,11 +446,17 @@ static void destroy_node (void *data) { struct node_data *nd = data; + struct port_data *pd; GstPipeWireDeviceProvider *self = nd->self; GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); pw_log_debug("destroy %p", nd); + spa_list_consume(pd, &nd->ports, link) { + spa_list_remove(&pd->link); + pd->node_data = NULL; + } + if (nd->dev != NULL) { gst_device_provider_device_remove (provider, GST_DEVICE (nd->dev)); } @@ -472,6 +486,7 @@ destroy_port (void *data) { struct port_data *pd = data; pw_log_debug("destroy %p", pd); + spa_list_remove(&pd->link); } static const struct pw_proxy_events proxy_port_events = { @@ -515,6 +530,7 @@ static void registry_event_global(void *data, uint32_t id, uint32_t permissions, 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_init(&nd->ports); spa_list_append(&self->nodes, &nd->link); 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); @@ -541,6 +557,7 @@ static void registry_event_global(void *data, uint32_t id, uint32_t permissions, pd->id = id; if (!props || !spa_atou64(spa_dict_lookup(props, PW_KEY_OBJECT_SERIAL), &pd->serial, 0)) pd->serial = SPA_ID_INVALID; + spa_list_append(&nd->ports, &pd->link); 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); resync(self); -- 2.43.0