node: Introduce pa_node

This commit adds very basic node objects to the core. This is just
a starting point, the nodes don't do anything useful yet.

A node represents a "routing endpoint" - the purpose is to make
routing easier. There are input nodes and output nodes, which can be
connected together. Generally speaking, sources and sink inputs map to
input nodes and sinks and source outputs map to output nodes. The
nodes form a new logical routing layer, which is an addition, not
replacement, to the current "low level" layer of sinks, sink inputs
and so on.

One goal is to be able to easily route any input to any output. For
example, with the node interface it should be easy to route a source
to a sink, without needing to care about the details, such as setting
up module-loopback. Routing sink inputs to source outputs should be
possible too, perhaps causing a null sink to be created between the
streams.

Another goal is to support new kinds of routing endpoints
that are not well suited to be implemented as sinks, sources or
streams. One example would be audio paths that exist in hardware only
(like cellular audio in many phone designs) that still have some
routing options. Another example would be a "gateway node" that makes
streams go to a remote PulseAudio as separate streams. The gateway
node implementation could dynamically create private tunnel sinks for
each stream.

In this first version the nodes have very few attributes, but the
intention is to add as much attributes as necessary for routing policy
modules to make good automatic routing decisions.

This patch is based on work by Janos Kovacs.
This commit is contained in:
Tanu Kaskinen 2013-07-03 14:09:04 +03:00
parent 4d638b5ffd
commit 3f2eb1e09f
7 changed files with 259 additions and 3 deletions

View file

@ -882,6 +882,7 @@ libpulsecore_@PA_MAJORMINOR@_la_SOURCES = \
pulsecore/module.c pulsecore/module.h \
pulsecore/msgobject.c pulsecore/msgobject.h \
pulsecore/namereg.c pulsecore/namereg.h \
pulsecore/node.c pulsecore/node.h \
pulsecore/object.c pulsecore/object.h \
pulsecore/play-memblockq.c pulsecore/play-memblockq.h \
pulsecore/play-memchunk.c pulsecore/play-memchunk.h \

View file

@ -99,6 +99,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, size_t shm_size) {
c->source_outputs = pa_idxset_new(NULL, NULL);
c->modules = pa_idxset_new(NULL, NULL);
c->scache = pa_idxset_new(NULL, NULL);
c->nodes = pa_idxset_new(NULL, NULL);
c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
c->shared = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);

View file

@ -139,7 +139,7 @@ struct pa_core {
pa_mainloop_api *mainloop;
/* idxset of all kinds of entities */
pa_idxset *clients, *cards, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache;
pa_idxset *clients, *cards, *sinks, *sources, *sink_inputs, *source_outputs, *modules, *scache, *nodes;
/* Some hashmaps for all sorts of entities */
pa_hashmap *namereg, *shared;

View file

@ -119,7 +119,7 @@ const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t
if (!*name)
return NULL;
if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD) &&
if ((type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE || type == PA_NAMEREG_CARD || type == PA_NAMEREG_NODE) &&
!pa_namereg_is_valid_name(name)) {
if (fail)

View file

@ -31,7 +31,8 @@ typedef enum pa_namereg_type {
PA_NAMEREG_SINK,
PA_NAMEREG_SOURCE,
PA_NAMEREG_SAMPLE,
PA_NAMEREG_CARD
PA_NAMEREG_CARD,
PA_NAMEREG_NODE
} pa_namereg_type_t;
const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, bool fail);

164
src/pulsecore/node.c Normal file
View file

@ -0,0 +1,164 @@
/***
This file is part of PulseAudio.
Copyright (c) 2012 Intel Corporation
Janos Kovacs <jankovac503@gmail.com>
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulsecore/core-util.h>
#include <pulsecore/namereg.h>
#include <pulsecore/strbuf.h>
#include "node.h"
pa_node_new_data *pa_node_new_data_init(pa_node_new_data *data) {
pa_assert(data);
pa_zero(*data);
data->direction = PA_DIRECTION_OUTPUT;
return data;
}
void pa_node_new_data_set_fallback_name_prefix(pa_node_new_data *data, const char* prefix) {
pa_assert(data);
pa_xfree(data->fallback_name_prefix);
data->fallback_name_prefix = pa_xstrdup(prefix);
}
void pa_node_new_data_set_description(pa_node_new_data *data, const char *description) {
pa_assert(data);
pa_xfree(data->description);
data->description = pa_xstrdup(description);
}
void pa_node_new_data_set_type(pa_node_new_data *data, pa_node_type_t type) {
pa_assert(data);
data->type = type;
}
void pa_node_new_data_set_direction(pa_node_new_data *data, pa_direction_t direction) {
pa_assert(data);
data->direction = direction;
}
void pa_node_new_data_done(pa_node_new_data *data) {
pa_assert(data);
pa_xfree(data->description);
pa_xfree(data->fallback_name_prefix);
}
pa_node *pa_node_new(pa_core *core, pa_node_new_data *data) {
bool use_fallback_name_prefix;
pa_strbuf *name_buf;
char *name = NULL;
pa_node *n = NULL;
const char *registered_name = NULL;
pa_assert(core);
pa_assert(data);
pa_assert(data->description);
use_fallback_name_prefix = !!data->fallback_name_prefix;
name_buf = pa_strbuf_new();
/* Automatic name generation code will appear here... */
if (use_fallback_name_prefix)
pa_strbuf_printf(name_buf, "%s-", data->fallback_name_prefix);
pa_strbuf_puts(name_buf, data->direction == PA_DIRECTION_OUTPUT ? "output" : "input");
name = pa_strbuf_tostring_free(name_buf);
n = pa_xnew0(pa_node, 1);
n->core = core;
n->state = PA_NODE_STATE_INIT;
if (!(registered_name = pa_namereg_register(core, name, PA_NAMEREG_NODE, n, false))) {
pa_log("Failed to register name %s.", name);
goto fail;
}
pa_xfree(name);
n->name = pa_xstrdup(registered_name);
n->description = pa_xstrdup(data->description);
n->type = data->type;
n->direction = data->direction;
return n;
fail:
pa_xfree(name);
pa_node_free(n);
return NULL;
}
void pa_node_free(pa_node *node) {
pa_assert(node);
if (node->state == PA_NODE_STATE_LINKED)
pa_node_unlink(node);
pa_xfree(node->description);
if (node->name) {
pa_namereg_unregister(node->core, node->name);
pa_xfree(node->name);
}
pa_xfree(node);
}
void pa_node_put(pa_node *node) {
pa_assert(node);
pa_assert(node->state == PA_NODE_STATE_INIT);
pa_assert(node->owner);
pa_assert_se(pa_idxset_put(node->core->nodes, node, &node->index) >= 0);
node->state = PA_NODE_STATE_LINKED;
pa_log_debug("Created node %s.", node->name);
}
void pa_node_unlink(pa_node *node) {
pa_assert(node);
pa_assert(node->state != PA_NODE_STATE_INIT);
if (node->state == PA_NODE_STATE_UNLINKED)
return;
pa_log_debug("Unlinking node %s.", node->name);
pa_assert_se(pa_idxset_remove_by_index(node->core->nodes, node->index));
node->state = PA_NODE_STATE_UNLINKED;
}

89
src/pulsecore/node.h Normal file
View file

@ -0,0 +1,89 @@
#ifndef foonodehfoo
#define foonodehfoo
/***
This file is part of PulseAudio.
Copyright (c) 2012 Intel Corporation
Janos Kovacs <jankovac503@gmail.com>
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
typedef struct pa_node_new_data pa_node_new_data;
typedef struct pa_node pa_node;
#include <pulsecore/core.h>
/* The node type determines what the owner pointer of pa_node points to. */
typedef enum {
PA_NODE_TYPE_PORT, /* owner: pa_port */
PA_NODE_TYPE_SINK, /* owner: pa_sink */
PA_NODE_TYPE_SOURCE, /* owner: pa_source */
PA_NODE_TYPE_SINK_INPUT, /* owner: pa_sink_input */
PA_NODE_TYPE_SOURCE_OUTPUT /* owner: pa_source_output */
} pa_node_type_t;
typedef enum {
PA_NODE_STATE_INIT,
PA_NODE_STATE_LINKED,
PA_NODE_STATE_UNLINKED
} pa_node_state_t;
struct pa_node_new_data {
/* Node names are generated automatically as much as possible, but
* sometimes the available information for automatic generation isn't
* sufficient, in which case the generated node names would be just "input"
* or "output". In such cases the fallback name prefix, if set, is used to
* generate slightly more informative names, such as "jack-output" for JACK
* output nodes (in this example the fallback prefix would be "jack"). */
char *fallback_name_prefix;
char *description;
pa_node_type_t type;
pa_direction_t direction;
};
struct pa_node {
pa_core *core;
uint32_t index;
char *name;
char *description;
pa_node_type_t type;
pa_direction_t direction;
pa_node_state_t state;
void *owner;
};
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);
void pa_node_new_data_set_type(pa_node_new_data *data, pa_node_type_t type);
void pa_node_new_data_set_direction(pa_node_new_data *data, pa_direction_t direction);
void pa_node_new_data_done(pa_node_new_data *data);
pa_node *pa_node_new(pa_core *core, pa_node_new_data *data);
void pa_node_free(pa_node *node);
void pa_node_put(pa_node *node);
void pa_node_unlink(pa_node *node);
#endif