Nodes need to keep track of the edges that they are part of, so that a node knows which edges to delete when the node is unlinked. --- src/pulsecore/edge.c | 33 +++++++++++++++++++++++++++++++++ src/pulsecore/edge.h | 2 ++ src/pulsecore/node.c | 28 ++++++++++++++++++++++++++++ src/pulsecore/node.h | 6 ++++++ 4 files changed, 69 insertions(+) diff --git a/src/pulsecore/edge.c b/src/pulsecore/edge.c index da40a53..931bee1 100644 --- a/src/pulsecore/edge.c +++ b/src/pulsecore/edge.c @@ -32,6 +32,9 @@ #include <pulse/xmalloc.h> +static int edge_put(pa_edge *edge); +static void edge_unlink(pa_edge *edge); + uint64_t pa_edge_key(uint32_t input_index, uint32_t output_index) { return ((uint64_t) input_index) << 32 | (uint64_t) output_index; } @@ -116,6 +119,8 @@ pa_edge *pa_edge_new(pa_node *input, pa_node *output, int *ret) { edge->output = output; edge->string = pa_sprintf_malloc("%s -> %s", input->name, output->name); + edge_put(edge); + return edge; fail: @@ -128,9 +133,37 @@ fail: return NULL; } +static int edge_put(pa_edge *edge) { + pa_assert(edge); + + pa_node_add_edge(edge->input, edge); + pa_node_add_edge(edge->output, edge); + + pa_log_debug("Created edge %s.", edge->string); + + return 0; +} + +static void edge_unlink(pa_edge *edge) { + pa_assert(edge); + + if (edge->unlinked) { + pa_log_debug("Unlinking edge %s (already unlinked, this is a no-op).", edge->string); + return; + } + + edge->unlinked = true; + + pa_log_debug("Unlinking edge %s.", edge->string); + + pa_node_remove_edge(edge->output, edge); + pa_node_remove_edge(edge->input, edge); +} + void pa_edge_free(pa_edge *edge) { pa_assert(edge); + edge_unlink(edge); pa_xfree(edge->string); pa_xfree(edge); } diff --git a/src/pulsecore/edge.h b/src/pulsecore/edge.h index 880df90..bd5cca1 100644 --- a/src/pulsecore/edge.h +++ b/src/pulsecore/edge.h @@ -36,6 +36,8 @@ struct pa_edge { pa_node *input; pa_node *output; char *string; + + bool unlinked; }; #define PA_MAX_EDGES 1024 diff --git a/src/pulsecore/node.c b/src/pulsecore/node.c index c0408c2..2475c85 100644 --- a/src/pulsecore/node.c +++ b/src/pulsecore/node.c @@ -25,6 +25,7 @@ #endif #include <pulsecore/core-util.h> +#include <pulsecore/edge.h> #include <pulsecore/namereg.h> #include <pulsecore/strbuf.h> @@ -145,6 +146,7 @@ pa_node *pa_node_new(pa_core *core, pa_node_new_data *data) { n->type = data->type; n->direction = data->direction; n->monitor_of = data->monitor_of; + n->edges = pa_hashmap_new(NULL, NULL); n->active = data->active; return n; @@ -161,6 +163,11 @@ void pa_node_free(pa_node *node) { pa_node_unlink(node); + if (node->edges) { + pa_assert(pa_hashmap_isempty(node->edges)); + pa_hashmap_free(node->edges); + } + pa_xfree(node->description); if (node->name) { @@ -404,6 +411,8 @@ int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_reque } void pa_node_unlink(pa_node *node) { + pa_edge *edge; + pa_assert(node); if (node->unlinked) { @@ -415,6 +424,11 @@ void pa_node_unlink(pa_node *node) { pa_log_debug("Unlinking node %s.", node->name); + while ((edge = pa_hashmap_steal_first(node->edges))) { + pa_log_debug("Deleting edge %s due to unlinking one of its endpoints.", edge->string); + pa_core_delete_edge(node->core, edge); + } + if (node->monitor_of) node->monitor_of->monitor = NULL; @@ -425,6 +439,20 @@ void pa_node_unlink(pa_node *node) { } +int pa_node_add_edge(pa_node *node, pa_edge *edge) { + pa_assert(node); + pa_assert(edge); + + return pa_hashmap_put(node->edges, edge, edge); +} + +int pa_node_remove_edge(pa_node *node, pa_edge *edge) { + pa_assert(node); + pa_assert(edge); + + return pa_hashmap_remove(node->edges, edge) ? 0 : -1; +} + void pa_node_active_changed(pa_node *node, bool new_active) { pa_assert(node); diff --git a/src/pulsecore/node.h b/src/pulsecore/node.h index 1014f16..626ee2f 100644 --- a/src/pulsecore/node.h +++ b/src/pulsecore/node.h @@ -23,6 +23,8 @@ USA. ***/ +#include <pulsecore/hashmap.h> + typedef struct pa_node_new_data pa_node_new_data; typedef struct pa_node pa_node; @@ -69,6 +71,7 @@ struct pa_node { pa_node *monitor; pa_node *monitor_of; + pa_hashmap *edges; /* pa_edge -> pa_edge (hashmap-as-a-set) */ bool active; bool unlinked; @@ -101,6 +104,9 @@ void pa_node_free(pa_node *node); int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_requested_connections); void pa_node_unlink(pa_node *node); +int pa_node_add_edge(pa_node *node, pa_edge *edge); +int pa_node_remove_edge(pa_node *node, pa_edge *edge); + /* To be called by the node back end when its active state changes. */ void pa_node_active_changed(pa_node *node, bool new_active); -- 1.8.3.1