mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-31 22:25:33 -04:00
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:
parent
4d638b5ffd
commit
3f2eb1e09f
7 changed files with 259 additions and 3 deletions
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
164
src/pulsecore/node.c
Normal 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
89
src/pulsecore/node.h
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue