[pulseaudio-discuss] [PATCH 05/30] node: Pass the requested connections to PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Jan 16 07:02:31 PST 2014


Also allow the hook users to report failure.
---
 src/modules/module-experimental-router.c | 40 +++++++++++++++++++++++---------
 src/pulsecore/core.h                     | 32 +++++++++++++++++++++++--
 src/pulsecore/node.c                     | 15 +++++++++++-
 src/pulsecore/node.h                     | 10 ++++++++
 4 files changed, 83 insertions(+), 14 deletions(-)

diff --git a/src/modules/module-experimental-router.c b/src/modules/module-experimental-router.c
index fe918bc..594593d 100644
--- a/src/modules/module-experimental-router.c
+++ b/src/modules/module-experimental-router.c
@@ -40,14 +40,26 @@ struct userdata {
 
 static pa_hook_result_t node_set_initial_routing_cb(void *hook_data, void *call_data, void *userdata) {
     pa_core *core = hook_data;
-    pa_node *node = call_data;
+    pa_node_set_initial_routing_hook_data *data = call_data;
+    pa_node *node;
     int r;
 
     pa_assert(core);
-    pa_assert(node);
+    pa_assert(data);
+
+    if (data->ret_valid)
+        /* Some other router module already applied some policy, we don't want
+         * to override that. */
+        return PA_HOOK_OK;
+
+    node = data->node;
 
     if (node->type != PA_NODE_TYPE_SINK_INPUT && node->type != PA_NODE_TYPE_SOURCE_OUTPUT)
-        goto finish;
+        /* We don't set data->ret_valid, because we don't care about nodes that
+         * aren't sink inputs or source outputs. If there is another router
+         * module, it's free to apply its policy, and otherwise pa_node_put()
+         * should apply its fallback policy. */
+        return PA_HOOK_OK;
 
     if (node->type == PA_NODE_TYPE_SINK_INPUT) {
         pa_sink_input *sink_input = node->owner;
@@ -60,10 +72,10 @@ static pa_hook_result_t node_set_initial_routing_cb(void *hook_data, void *call_
 
         default_sink = pa_namereg_get_default_sink(core);
 
-        if (!default_sink)
-            goto fail;
-
-        r = pa_sink_input_set_initial_sink(sink_input, default_sink);
+        if (default_sink)
+            r = pa_sink_input_set_initial_sink(sink_input, default_sink);
+        else
+            r = -PA_ERR_NOENTITY;
     } else {
         pa_source_output *source_output = node->owner;
         pa_source *default_source;
@@ -75,10 +87,10 @@ static pa_hook_result_t node_set_initial_routing_cb(void *hook_data, void *call_
 
         default_source = pa_namereg_get_default_source(core);
 
-        if (!default_source)
-            goto fail;
-
-        r = pa_source_output_set_initial_source(source_output, default_source);
+        if (default_source)
+            r = pa_source_output_set_initial_source(source_output, default_source);
+        else
+            r = -PA_ERR_NOENTITY;
     }
 
     if (r < 0)
@@ -87,11 +99,17 @@ static pa_hook_result_t node_set_initial_routing_cb(void *hook_data, void *call_
 finish:
     pa_log_debug("Successfully routed node %s.", node->name);
 
+    data->ret = 0;
+    data->ret_valid = true;
+
     return PA_HOOK_OK;
 
 fail:
     pa_log_debug("Failed to route node %s.", node->name);
 
+    data->ret = r;
+    data->ret_valid = true;
+
     return PA_HOOK_OK;
 }
 
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 78675da..443af48 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -159,8 +159,36 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_PORT_AVAILABLE_CHANGED,
     PA_CORE_HOOK_PORT_LATENCY_OFFSET_CHANGED,
 
-    /* Fired when a new node is added to the system. Router modules can use
-     * this to set the initial routing for the new node. Call data: pa_node. */
+    /* Fired when a new node is added to the system (from pa_node_put()).
+     * Router modules can use this to set the initial routing for the new node.
+     * Call data: pa_node_set_initial_routing_hook_data, details below:
+     *
+     *     struct pa_node_set_initial_routing_hook_data {
+     *         pa_node *node;
+     *         pa_node **requested_connections;
+     *         unsigned n_requested_connections;
+     *         int ret;
+     *         bool ret_valid;
+     *     }
+     *
+     * Users of this hook are expected to create zero or more connections
+     * between data.node and other nodes in the system. The requested
+     * connections should usually be taken into account when deciding the
+     * initial routing, but if you really want to ignore those, you're free to
+     * do so. If n_requested_connections is zero, it means "use default" (i.e.
+     * nothing specific was requested). XXX: We might some day need to support
+     * also the "don't connect anywhere" case, so the interpretation of
+     * n_requested_connections == 0 may change in the future...
+     *
+     * ret_valid must be set to true in the hook callback, because if it's
+     * false, pa_node_put() assumes that there are no router modules present so
+     * it will run its own fallback routing algorithm.
+     *
+     * If ret is set to a negative error code, the node creation will fail.
+     * Usually you should report an error if your router module can't create
+     * the requested connections, but you don't have to do that if you think it
+     * makes sense to let the node creation succeed even when the requested
+     * connections couldn't be created. */
     PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING,
 
     PA_CORE_HOOK_MAX
diff --git a/src/pulsecore/node.c b/src/pulsecore/node.c
index 790c054..b1dc841 100644
--- a/src/pulsecore/node.c
+++ b/src/pulsecore/node.c
@@ -153,6 +153,14 @@ void pa_node_free(pa_node *node) {
 }
 
 int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_requested_connections) {
+    pa_node_set_initial_routing_hook_data data = {
+        .node = node,
+        .requested_connections = requested_connections,
+        .n_requested_connections = n_requested_connections,
+        .ret = 0,
+        .ret_valid = false
+    };
+
     pa_assert(node);
     pa_assert(node->state == PA_NODE_STATE_INIT);
     pa_assert(node->owner);
@@ -164,7 +172,12 @@ int pa_node_put(pa_node *node, pa_node **requested_connections, unsigned n_reque
     if (node->monitor_of)
         node->monitor_of->monitor = node;
 
-    pa_hook_fire(&node->core->hooks[PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING], node);
+    pa_hook_fire(&node->core->hooks[PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING], &data);
+
+    if (data.ret_valid && data.ret < 0) {
+        pa_log_info("Setting initial routing for node %s failed.", node->name);
+        return data.ret;
+    }
 
     pa_log_debug("Created node %s.", node->name);
 
diff --git a/src/pulsecore/node.h b/src/pulsecore/node.h
index 7366fed..395609e 100644
--- a/src/pulsecore/node.h
+++ b/src/pulsecore/node.h
@@ -77,6 +77,16 @@ struct pa_node {
     void *owner;
 };
 
+/* See the documentation of PA_CORE_HOOK_NODE_SET_INITIAL_ROUTING to understand
+ * this struct. */
+typedef struct pa_node_set_initial_routing_hook_data {
+    pa_node *node;
+    pa_node **requested_connections;
+    unsigned n_requested_connections;
+    int ret;
+    bool ret_valid;
+} pa_node_set_initial_routing_hook_data;
+
 pa_node_new_data *pa_node_new_data_init(pa_node_new_data *data);
 void pa_node_new_data_set_fallback_name_prefix(pa_node_new_data *data, const char *prefix);
 void pa_node_new_data_set_description(pa_node_new_data *data, const char *description);
-- 
1.8.3.1



More information about the pulseaudio-discuss mailing list