#include "node.h"
#include "discover.h"
#include "router.h"
-#include "switch.h" /* later we should talk just the router */
#include "dbusif.h"
#define AUDIOMGR_DOMAIN "PULSE"
struct pa_audiomgr {
domain_t domain;
- pa_hashmap *nodes;
+ pa_hashmap *nodes; /**< nodes ie. sinks and sources */
+ pa_hashmap *conns; /**< connections */
};
-static void *hash_key(mir_direction, uint16_t);
+static void *node_hash(mir_direction, uint16_t);
+static void *conn_hash(uint16_t);
struct pa_audiomgr *pa_audiomgr_init(struct userdata *u)
am->domain.state = DS_DOWN;
am->nodes = pa_hashmap_new(pa_idxset_trivial_hash_func,
pa_idxset_trivial_compare_func);
+ am->conns = pa_hashmap_new(pa_idxset_trivial_hash_func,
+ pa_idxset_trivial_compare_func);
return am;
}
pa_policy_dbusif_unregister_domain(u, am->domain.id);
pa_hashmap_free(am->nodes, NULL,NULL);
+ pa_hashmap_free(am->conns, NULL,NULL);
pa_xfree((void *)am->domain.name);
pa_xfree(am);
u->audiomgr = NULL;
else {
node->amid = id;
- key = hash_key(node->direction, id);
+ key = node_hash(node->direction, id);
pa_log_debug("registering node '%s' (%p/%p)",
node->amname, key, node);
ud->id = node->amid;
ud->name = pa_xstrdup(node->amname);
- key = hash_key(node->direction, node->amid);
+ key = node_hash(node->direction, node->amid);
removed = pa_hashmap_remove(am->nodes, key);
if (node != removed) {
"attempted to remove '%s' (%p/%p); "
"actually removed '%s' (%p/%p)", __FILE__,
node->amname, key, node, removed->amname,
- hash_key(removed->direction, removed->amid), removed);
+ node_hash(removed->direction, removed->amid), removed);
else
pa_log("%s: confused with data structures: node %u (%p)"
"is not in the hash table", __FILE__, node->amid, node);
void pa_audiomgr_connect(struct userdata *u, am_connect_data *cd)
{
- pa_audiomgr *am;
- am_ack_data ad;
- mir_node *from = NULL;
- mir_node *to = NULL;
- int err = E_OK;
+ pa_audiomgr *am;
+ am_ack_data ad;
+ mir_connection *conn;
+ uint16_t cid;
+ mir_node *from = NULL;
+ mir_node *to = NULL;
+ int err = E_OK;
pa_assert(u);
pa_assert(cd);
pa_assert_se((am = u->audiomgr));
- /* temporary hack: instead of switching we should setup an explicit route*/
- if ((from = pa_hashmap_get(am->nodes, hash_key(mir_input, cd->source))) &&
- (to = pa_hashmap_get(am->nodes, hash_key(mir_output, cd->sink))))
+ if ((from = pa_hashmap_get(am->nodes, node_hash(mir_input, cd->source))) &&
+ (to = pa_hashmap_get(am->nodes, node_hash(mir_output, cd->sink))))
{
+ cid = cd->connection;
+
pa_log_debug("routing '%s' => '%s'", from->amname, to->amname);
- if (!mir_switch_setup_link(u, from, to))
+
+ if (!(conn = mir_router_add_explicit_route(u, cid, from, to)))
err = E_NOT_POSSIBLE;
+ else {
+ pa_log_debug("registering connection (%u/%p)",
+ cd->connection, conn);
+ pa_hashmap_put(am->conns, conn_hash(cid), conn);
+ }
}
else {
pa_log_debug("failed to connect: can't find node for %s %u",
void pa_audiomgr_disconnect(struct userdata *u, am_connect_data *cd)
{
- am_ack_data ad;
- int err = E_OK;
+ pa_audiomgr *am;
+ mir_connection *conn;
+ uint16_t cid;
+ am_ack_data ad;
+ int err = E_OK;
pa_assert(u);
pa_assert(cd);
+ pa_assert_se((am = u->audiomgr));
- /* temporary hack: instead this we should delete an explicit route */
- mir_router_make_routing(u);
+ cid = cd->connection;
+
+ if ((conn = pa_hashmap_remove(am->conns, conn_hash(cid))))
+ mir_router_remove_explicit_route(u, conn);
+ else {
+ pa_log_debug("failed to disconnect: can't find connection %u", cid);
+ err = E_NON_EXISTENT;
+ }
memset(&ad, 0, sizeof(ad));
ad.handle = cd->handle;
pa_policy_dbusif_acknowledge(u, AUDIOMGR_DISCONNECT_ACK, &ad);
}
-static void *hash_key(mir_direction direction, uint16_t amid)
+static void *node_hash(mir_direction direction, uint16_t amid)
{
return NULL + ((uint32_t)direction << 16 | (uint32_t)amid);
}
+static void *conn_hash(uint16_t connid)
+{
+ return NULL + (uint32_t)connid;
+}
+
/*
pa_assert(node);
+ //return FALSE;
+
if (node->implement == mir_stream && node->direction == mir_input) {
class = node->type;
if (!data.mux)
s = sinp->sink;
else {
- if ((csinp = pa_multiplex_default_stream(core, data.mux)))
- s = csinp->sink;
- else
- s = NULL;
+ csinp = pa_idxset_get_by_index(core->sink_inputs,
+ data.mux->defstream_index);
+ s = csinp ? csinp->sink : NULL;
}
if (s)
pa_assert(chmap);
pa_assert_se((core = u->core));
+
+
target = mir_router_make_prerouting(u, data);
if (!target)
#include "module-murphy-ivi-symdef.h"
#include "userdata.h"
+#include "node.h"
#include "tracker.h"
#include "discover.h"
#include "router.h"
u->core = m->core;
u->module = m;
u->nullsink = pa_utils_create_null_sink(u, nsnam);
+ u->nodeset = pa_nodeset_init(u);
u->audiomgr = pa_audiomgr_init(u);
u->dbusif = pa_policy_dbusif_init(u,ifnam,mrppath,mrpnam,ampath,amnam);
u->discover = pa_discover_init(u);
pa_audiomgr_done(u);
pa_policy_dbusif_done(u);
pa_mir_config_done(u);
+ pa_nodeset_done(u);
pa_utils_destroy_null_sink(u);
pa_multiplex_done(u->multiplex, u->core);
mux = pa_xnew0(pa_muxnode, 1);
mux->module_index = module->index;
mux->sink_index = u->sink->index;
+ mux->defstream_index = PA_IDXSET_INVALID;
PA_LLIST_PREPEND(pa_muxnode, multiplex->muxnodes, mux);
if (!(o = pa_idxset_first(u->outputs, &idx)))
pa_log("can't find default multiplexer stream");
else {
- if ((sinp = o->sink_input))
+ if ((sinp = o->sink_input)) {
pa_utils_set_stream_routing_properties(sinp->proplist, type, NULL);
+ mux->defstream_index = sinp->index;
+ /* Hmm... */
+ sinp->flags &= ~(pa_sink_input_flags_t)PA_SINK_INPUT_DONT_MOVE;
+ }
}
pa_log_debug("multiplexer succesfully loaded");
return NULL;
}
-pa_sink_input *pa_multiplex_default_stream(pa_core *core, pa_muxnode *mux)
+
+pa_bool_t pa_multiplex_remove_default_route(pa_core *core,
+ pa_muxnode *mux,
+ pa_bool_t transfer_to_explicit)
{
- pa_module *module;
- pa_sink_input *sinp;
+ pa_module *module;
+ pa_sink_input *sinp;
+ uint32_t idx;
struct userdata *u; /* combine's userdata! */
+
+ pa_assert(core);
+ pa_assert(mux);
+
+ if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
+ pa_log("module %u is gone", mux->module_index);
+ else if ((idx = mux->defstream_index) == PA_IDXSET_INVALID)
+ pa_log_debug("mux %u do not have default stream", mux->module_index);
+ else if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, idx)))
+ pa_log("can't remove default route: sink-input %u is gone", idx);
+ else {
+ pa_assert_se((u = module->userdata));
+ mux->defstream_index = PA_IDXSET_INVALID;
+
+ if (transfer_to_explicit) {
+ pa_log_debug("converting default route sink-input.%u -> sink.%u "
+ "to explicit", sinp->index, sinp->sink->index);
+ pa_utils_set_stream_routing_method_property(sinp->proplist, TRUE);
+ return TRUE;
+ }
+ else {
+ /* call Jaska's routine */
+ }
+ }
+
+ return FALSE;
+}
+
+
+pa_bool_t pa_multiplex_add_explicit_route(pa_core *core,
+ pa_muxnode *mux,
+ pa_sink *sink,
+ int type)
+{
+ pa_module *module;
+ pa_sink_input *sinp;
+ struct userdata *u; /* combine's userdata! */
+
+ pa_assert(core);
+ pa_assert(mux);
+
+ if (!(module = pa_idxset_get_by_index(core->modules, mux->module_index)))
+ pa_log("module %u is gone", mux->module_index);
+ else {
+ pa_assert_se((u = module->userdata));
+
+ if (sink == u->sink) {
+ pa_log("%s: mux %d refuses to make a loopback to itself",
+ __FILE__, mux->module_index);
+ }
+ else {
+ pa_log_debug("adding explicit route to mux %u", mux->module_index);
+ /* pa_utils_set_stream_routing_properties(sinp->proplist, type, sink); */
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+pa_bool_t pa_multiplex_duplicate_route(pa_core *core,
+ pa_muxnode *mux,
+ pa_sink_input *sinp,
+ pa_sink *sink)
+{
+ pa_module *module;
+ struct userdata *u; /* combine's userdata! */
struct output *o;
uint32_t idx;
+ pa_sink_input *i;
pa_assert(core);
pa_assert(mux);
-
- if ((module = pa_idxset_get_by_index(core->modules, mux->module_index)) &&
- (u = module->userdata))
- {
- pa_log_debug("trying to find the default stream on mux %u",
- module->index);
-
- PA_IDXSET_FOREACH(o, u->outputs, idx) {
- if (!(sinp = o->sink_input))
- continue;
+ pa_assert(sink);
- pa_log_debug(" trying sink input %u", sinp->index);
+ pa_log_debug("check for duplicate route on mux %u",
+ mux->module_index);
- if (pa_utils_stream_has_default_route(sinp->proplist)) {
- pa_log_debug("sink input %u is the default", sinp->index);
- return sinp;
+ if (!(module = pa_idxset_get_by_index(core->modules,mux->module_index)))
+ pa_log("module %u is gone", mux->module_index);
+ else {
+ pa_assert_se((u = module->userdata));
+
+ PA_IDXSET_FOREACH(o, u->outputs, idx) {
+ if (!(i = o->sink_input))
+ continue;
+ if (sinp && i == sinp)
+ continue;
+ if (i->sink == sink) {
+ pa_log_debug("route sink-input.%u -> sink.%u is a duplicate",
+ i->index, sink->index);
+ return TRUE;
}
+ }
- pa_log_debug(" no");
+ if (!sinp)
+ pa_log_debug("no duplicate route found to sink.%u", sink->index);
+ else {
+ pa_log_debug("no duplicate found for route sink-input.%u -> "
+ "sink.%u", sinp->index, sink->index);
}
}
-
- pa_log_debug("could not find the default stream on mux %u", module->index);
-
- return NULL;
+
+ return FALSE;
}
if (!mux)
p += snprintf(p, e-p, "<not set>");
else {
- p += snprintf(p, e-p, "module %u, sink %u",
- mux->module_index, mux->sink_index);
+ p += snprintf(p, e-p, "module %u, sink %u, default stream %u",
+ mux->module_index, mux->sink_index,mux->defstream_index);
}
return p - buf;
PA_LLIST_FIELDS(pa_muxnode);
uint32_t module_index;
uint32_t sink_index;
+ uint32_t defstream_index;
};
pa_multiplex *pa_multiplex_init(void);
pa_muxnode *pa_multiplex_find(pa_multiplex *, uint32_t);
-pa_sink_input *pa_multiplex_default_stream(pa_core *, pa_muxnode *);
+pa_bool_t pa_multiplex_remove_default_route(pa_core *,pa_muxnode *,pa_bool_t);
+
+pa_bool_t pa_multiplex_add_explicit_route(pa_core*, pa_muxnode*, pa_sink*,int);
+
+pa_bool_t pa_multiplex_duplicate_route(pa_core *, pa_muxnode *,
+ pa_sink_input *, pa_sink *);
int pa_multiplex_print(pa_muxnode *, char *, int);
#include "discover.h"
#include "router.h"
+struct pa_nodeset {
+ pa_idxset *nodes;
+};
+
+
+pa_nodeset *pa_nodeset_init(struct userdata *u)
+{
+ pa_nodeset *ns;
+
+ pa_assert(u);
+
+ ns = pa_xnew0(pa_nodeset, 1);
+ ns->nodes = pa_idxset_new(pa_idxset_trivial_hash_func,
+ pa_idxset_trivial_compare_func);
+ return ns;
+}
+
+void pa_nodeset_done(struct userdata *u)
+{
+ pa_nodeset *ns;
+
+ if (u && (ns = u->nodeset)) {
+ pa_idxset_free(ns->nodes, NULL, NULL);
+ free(ns);
+ }
+}
+
mir_node *mir_node_create(struct userdata *u, mir_node *data)
{
+ pa_nodeset *ns;
mir_node *node;
pa_assert(u);
pa_assert(data);
+ pa_assert_se((ns = u->nodeset));
pa_assert(data->key);
pa_assert(data->paname);
node->paport = pa_xstrdup(data->paport);
}
+ pa_idxset_put(ns->nodes, node, &node->index);
+
mir_router_register_node(u, node);
return node;
void mir_node_destroy(struct userdata *u, mir_node *node)
{
+ pa_nodeset *ns;
+
pa_assert(u);
+ pa_assert_se((ns = u->nodeset));
if (node) {
mir_router_unregister_node(u, node);
+ pa_idxset_remove_by_index(ns->nodes, node->index);
+
pa_xfree(node->key);
pa_xfree(node->amname);
pa_xfree(node->amdescr);
}
}
+mir_node *mir_node_find_by_index(struct userdata *u, uint32_t nodidx)
+{
+ pa_nodeset *ns;
+ mir_node *node;
+
+ pa_assert(u);
+ pa_assert_se((ns = u->nodeset));
+
+ node = pa_idxset_get_by_index(ns->nodes, nodidx);
+
+ return node;
+}
+
int mir_node_print(mir_node *node, char *buf, int len)
{
char *p, *e;
#define PRINT(f,v) if (p < e) p += snprintf(p, e-p, f "\n", v)
+ PRINT(" index : %u" , node->index);
PRINT(" key : '%s'", node->key ? node->key : "");
PRINT(" direction : %s" , mir_direction_str(node->direction));
PRINT(" implement : %s" , mir_implement_str(node->implement));
#define AM_ID_INVALID 65535
+
enum mir_direction {
mir_direction_unknown,
mir_input,
* is either a sink_input or a source_output
*/
struct mir_node {
+ uint32_t index; /**< index into nodeset->idxset */
char *key; /**< hash key for discover lookups */
mir_direction direction;/**< mir_input | mir_output */
mir_implement implement;/**< mir_device | mir_stream */
};
+pa_nodeset *pa_nodeset_init(struct userdata *);
+void pa_nodeset_done(struct userdata *);
+
+
mir_node *mir_node_create(struct userdata *, mir_node *);
void mir_node_destroy(struct userdata *, mir_node *);
+mir_node *mir_node_find_by_index(struct userdata *, uint32_t);
+
int mir_node_print(mir_node *, char *, int);
const char *mir_direction_str(mir_direction);
static int rtgroup_print(mir_rtgroup *, char *, int);
static void rtgroup_update_module_property(struct userdata *, mir_rtgroup *);
-
static void add_rtentry(struct userdata *, mir_rtgroup *, mir_node *);
static void remove_rtentry(struct userdata *, mir_rtentry *);
-static mir_node *route_stream(struct userdata *, mir_node *);
+static void make_explicit_routes(struct userdata *, uint32_t);
+static mir_node *find_default_route(struct userdata *, mir_node *);
static int uint32_cmp(uint32_t, uint32_t);
router->classmap = pa_xnew0(mir_rtgroup *, num_classes);
router->priormap = pa_xnew0(int, num_classes);
MIR_DLIST_INIT(router->nodlist);
+ MIR_DLIST_INIT(router->connlist);
return router;
}
void pa_router_done(struct userdata *u)
{
- pa_router *router;
- mir_node *e,*n;
+ pa_router *router;
+ mir_connection *conn, *c;
+ mir_node *e,*n;
if (u && (router = u->router)) {
MIR_DLIST_FOR_EACH_SAFE(mir_node, rtentries, e,n, &router->nodlist) {
MIR_DLIST_UNLINK(mir_node, rtentries, e);
}
+ MIR_DLIST_FOR_EACH_SAFE(mir_connection,link, conn,c,&router->connlist){
+ MIR_DLIST_UNLINK(mir_connection, link, conn);
+ pa_xfree(conn);
+ }
+
pa_hashmap_free(router->rtgroups, pa_hashmap_rtgroup_free,u);
pa_xfree(router->classmap);
}
}
+mir_connection *mir_router_add_explicit_route(struct userdata *u,
+ uint16_t amid,
+ mir_node *from,
+ mir_node *to)
+{
+ pa_router *router;
+ mir_connection *conn;
+
+ pa_assert(u);
+ pa_assert(from);
+ pa_assert(to);
+ pa_assert_se((router = u->router));
+
+ conn = pa_xnew0(mir_connection, 1);
+ MIR_DLIST_INIT(conn->link);
+ conn->amid = amid;
+ conn->from = from->index;
+ conn->to = to->index;
+
+ MIR_DLIST_APPEND(mir_connection, link, conn, &router->connlist);
+
+ mir_router_make_routing(u);
+
+ return conn;
+}
+
+void mir_router_remove_explicit_route(struct userdata *u, mir_connection *conn)
+{
+ pa_router *router;
+
+ pa_assert(u);
+ pa_assert(conn);
+ pa_assert_se((router = u->router));
+
+ MIR_DLIST_UNLINK(mir_connection, link, conn);
+
+ if (!conn->blocked)
+ mir_router_make_routing(u);
+
+ pa_xfree(conn);
+}
+
int mir_router_print_rtgroups(struct userdata *u, char *buf, int len)
{
pa_router *router;
mir_node *mir_router_make_prerouting(struct userdata *u, mir_node *data)
{
pa_router *router;
- mir_node *source;
- mir_node *sink;
+ mir_node *from;
+ mir_node *to;
int priority;
pa_bool_t done;
mir_node *target;
+ uint32_t stamp;
pa_assert(u);
pa_assert_se((router = u->router));
+ pa_assert_se((data->implement == mir_stream));
+ pa_assert_se((data->direction == mir_input));
priority = node_priority(u, data);
done = FALSE;
target = NULL;
+ stamp = pa_utils_new_stamp();
- MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, source, &router->nodlist) {
- if (priority >= node_priority(u, source)) {
- if ((target = route_stream(u, data)))
- mir_switch_setup_link(u, NULL, target);
+ make_explicit_routes(u, stamp);
+
+ MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, from, &router->nodlist) {
+ if (priority >= node_priority(u, from)) {
+ if ((target = find_default_route(u, data)))
+ mir_switch_setup_link(u, NULL, target, FALSE);
done = TRUE;
}
- if ((sink = route_stream(u, source)))
- mir_switch_setup_link(u, source, sink);
+ if (from->stamp >= stamp)
+ continue;
+
+ if ((to = find_default_route(u, from)))
+ mir_switch_setup_link(u, from, to, FALSE);
}
- if (!done && (target = route_stream(u, data)))
- mir_switch_setup_link(u, NULL, target);
+ if (!done && (target = find_default_route(u, data)))
+ mir_switch_setup_link(u, NULL, target, FALSE);
return target;
}
{
static pa_bool_t ongoing_routing;
- pa_router *router;
- mir_node *source;
- mir_node *sink;
+ pa_router *router;
+ mir_node *from;
+ mir_node *to;
+ uint32_t stamp;
pa_assert(u);
pa_assert_se((router = u->router));
return;
ongoing_routing = TRUE;
+ stamp = pa_utils_new_stamp();
+
+ make_explicit_routes(u, stamp);
- MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, source, &router->nodlist) {
- if ((sink = route_stream(u, source)))
- mir_switch_setup_link(u, source, sink);
+ MIR_DLIST_FOR_EACH_BACKWARD(mir_node,rtentries, from, &router->nodlist) {
+ if (from->stamp >= stamp)
+ continue;
+
+ if ((to = find_default_route(u, from)))
+ mir_switch_setup_link(u, from, to, FALSE);
}
ongoing_routing = FALSE;
pa_xfree(rte);
}
+static void make_explicit_routes(struct userdata *u, uint32_t stamp)
+{
+ pa_router *router;
+ mir_connection *conn;
+ mir_node *from;
+ mir_node *to;
+
+ pa_assert(u);
+ pa_assert_se((router = u->router));
+
+ MIR_DLIST_FOR_EACH_BACKWARD(mir_connection,link, conn, &router->connlist) {
+ if (conn->blocked)
+ continue;
+
+ if (!(from = mir_node_find_by_index(u, conn->from)) ||
+ !(to = mir_node_find_by_index(u, conn->to)) )
+ {
+ pa_log_debug("ignoring explicit route %u: some of the nodes "
+ "not found", conn->amid);
+ continue;
+ }
+
+ if (!mir_switch_setup_link(u, from, to, TRUE))
+ continue;
+
+ if (from->implement == mir_stream)
+ from->stamp = stamp;
+ }
+}
+
-static mir_node *route_stream(struct userdata *u, mir_node *source)
+static mir_node *find_default_route(struct userdata *u, mir_node *from)
{
pa_router *router = u->router;
- mir_node_type class = source->type;
- mir_node *sink;
+ mir_node_type class = from->type;
+ mir_node *to;
mir_rtgroup *rtg;
mir_rtentry *rte;
if (class < 0 || class > router->maplen) {
pa_log_debug("can't route '%s': class %d is out of range (0 - %d)",
- source->amname, class, router->maplen);
+ from->amname, class, router->maplen);
return NULL;
}
if (!(rtg = router->classmap[class])) {
pa_log_debug("node '%s' won't be routed beacuse its class '%s' "
"is not assigned to any router group",
- source->amname, mir_node_type_str(class));
+ from->amname, mir_node_type_str(class));
return NULL;
}
pa_log_debug("using '%s' router group when routing '%s'",
- rtg->name, source->amname);
+ rtg->name, from->amname);
MIR_DLIST_FOR_EACH_BACKWARD(mir_rtentry, link, rte, &rtg->entries) {
- if (!(sink = rte->node)) {
+ if (!(to = rte->node)) {
pa_log(" node was null in mir_rtentry");
continue;
}
- if (sink->ignore) {
- pa_log_debug(" '%s' ignored. Skipping...",sink->amname);
+ if (to->ignore) {
+ pa_log_debug(" '%s' ignored. Skipping...",to->amname);
continue;
}
- if (!sink->available) {
- pa_log_debug(" '%s' not available. Skipping...", sink->amname);
+ if (!to->available) {
+ pa_log_debug(" '%s' not available. Skipping...", to->amname);
continue;
}
- if (sink->paidx == PA_IDXSET_INVALID) {
- if (sink->type != mir_bluetooth_a2dp &&
- sink->type != mir_bluetooth_sco)
+ if (to->paidx == PA_IDXSET_INVALID) {
+ if (to->type != mir_bluetooth_a2dp &&
+ to->type != mir_bluetooth_sco)
{
- pa_log_debug(" '%s' has no sink. Skipping...", sink->amname);
+ pa_log_debug(" '%s' has no to. Skipping...", to->amname);
continue;
}
}
- pa_log_debug("routing '%s' => '%s'", source->amname, sink->amname);
+ pa_log_debug("routing '%s' => '%s'", from->amname, to->amname);
- return sink;
+ return to;
}
- pa_log_debug("could not find route for '%s'", source->amname);
+ pa_log_debug("could not find route for '%s'", from->amname);
return NULL;
}
struct pa_router {
pa_hashmap *rtgroups;
- int maplen; /**< length of the class- and priormap */
- mir_rtgroup **classmap; /**< to map device node types to rtgroups */
- int *priormap; /**< stream node priorities */
- mir_dlist nodlist; /**< priorized list of the nodes */
+ int maplen; /**< length of the class- and priormap */
+ mir_rtgroup **classmap; /**< to map device node types to rtgroups */
+ int *priormap; /**< stream node priorities */
+ mir_dlist nodlist; /**< priorized list of the input stream nodes */
+ mir_dlist connlist; /**< listhead of the connections */
};
mir_rtgroup_compare_t compare; /**< comparision function for ordering */
};
+struct mir_connection {
+ mir_dlist link; /**< list of connections */
+ pa_bool_t blocked; /**< true if this conflicts with another route */
+ uint16_t amid; /**< audio manager connection id */
+ uint32_t from; /**< source node index */
+ uint32_t to; /**< destination node index */
+ uint32_t stream; /**< index of the sink-input to be routed */
+};
+
pa_router *pa_router_init(struct userdata *);
void pa_router_done(struct userdata *);
mir_node *mir_router_make_prerouting(struct userdata *, mir_node *);
void mir_router_make_routing(struct userdata *);
+mir_connection *mir_router_add_explicit_route(struct userdata *, uint16_t,
+ mir_node *, mir_node *);
+void mir_router_remove_explicit_route(struct userdata *, mir_connection *);
+
+
int mir_router_print_rtgroups(struct userdata *, char *, int);
pa_bool_t mir_router_default_accept(struct userdata *, mir_rtgroup *,
#include "multiplex.h"
-pa_bool_t set_profile(struct userdata *, mir_node *);
+static pa_bool_t explicit_link_from_stream_to_device(struct userdata *,
+ mir_node *, mir_node *);
+static pa_bool_t default_link_from_stream_to_device(struct userdata *,
+ mir_node *, mir_node *);
-pa_bool_t mir_switch_setup_link(struct userdata *u,mir_node *from,mir_node *to)
+static pa_sink *setup_device_output(struct userdata *, mir_node *);
+
+static pa_bool_t set_profile(struct userdata *, mir_node *);
+
+
+pa_bool_t mir_switch_setup_link(struct userdata *u,
+ mir_node *from,
+ mir_node *to,
+ pa_bool_t explicit)
+{
+ pa_core *core;
+
+ pa_assert(u);
+ pa_assert(to);
+ pa_assert_se((core = u->core));
+ pa_assert(!from || from->direction == mir_input);
+ pa_assert(to->direction == mir_output);
+
+ if (explicit) {
+ /*
+ * links for explic routes
+ */
+ pa_assert(from);
+
+ switch (from->implement) {
+
+ case mir_stream:
+ switch (to->implement) {
+
+ case mir_stream:
+ pa_log_debug("routing to streams is not implemented yet");
+ break;
+
+ case mir_device:
+ if (!explicit_link_from_stream_to_device(u, from, to))
+ return FALSE;
+ break;
+
+ default:
+ pa_log("%s: can't setup link: invalid sink node "
+ "implement", __FILE__);
+ return FALSE;
+ }
+ break;
+
+ case mir_device:
+ pa_log_debug("input device routing is not implemented yet");
+ break;
+
+ default:
+ pa_log("%s: can't setup link: invalid source node "
+ "implement", __FILE__);
+ return FALSE;
+ }
+ }
+ else {
+ /*
+ * links for default routes
+ */
+ switch (to->implement) {
+
+ case mir_stream:
+ pa_log_debug("routing to a stream is not implemented yet");
+ break;
+
+ case mir_device:
+ if (!from) /* prerouting */
+ return (!explicit && setup_device_output(u, to) != NULL);
+ else {
+ switch (from->implement) {
+
+ case mir_stream:
+ if (!default_link_from_stream_to_device(u, from, to))
+ return FALSE;
+ break;
+
+ case mir_device:
+ pa_log("%s: default device -> device route is "
+ "not supported", __FILE__);
+ break;
+
+ default:
+ pa_log("%s: can't setup link: invalid source node "
+ "implement", __FILE__);
+ return FALSE;
+ }
+ }
+ break;
+
+ default:
+ pa_log("%s: can't setup link: invalid sink node "
+ "implement", __FILE__);
+ return FALSE;
+ }
+ }
+
+ pa_log_debug("link %s => %s is established", from->amname, to->amname);
+
+ return TRUE;
+}
+
+static pa_bool_t explicit_link_from_stream_to_device(struct userdata *u,
+ mir_node *from,
+ mir_node *to)
{
pa_core *core;
- pa_sink_input *sinp;
pa_sink *sink;
+ pa_sink_input *sinp;
pa_muxnode *mux;
pa_assert(u);
+ pa_assert(from);
pa_assert(to);
- pa_assert_se((core = u->core));
+ pa_assert((core = u->core));
- if (!set_profile(u, to)) {
- pa_log("can't route to '%s'", to->amname);
+ if (!(sink = setup_device_output(u, to)))
return FALSE;
- }
- if (to->paidx == PA_IDXSET_INVALID) {
- pa_log_debug("can't route to '%s': no sink", to->amname);
+ if (!set_profile(u, from)) {
+ pa_log("can't route from '%s'", from->amname);
return FALSE;
}
- if (!(sink = pa_idxset_get_by_index(core->sinks, to->paidx))) {
- pa_log_debug("can't route to '%s': cant find sink", to->amname);
- return FALSE;
+ if ((mux = from->mux)) {
+ sinp = pa_idxset_get_by_index(core->sink_inputs, mux->defstream_index);
+
+ if (sinp && sinp->sink == sink) {
+ if (!pa_multiplex_remove_default_route(core, mux, TRUE))
+ return FALSE;
+ }
+ else if (pa_multiplex_duplicate_route(core, mux, NULL, sink)) {
+ pa_log_debug("multiplex route %s => %s already exists",
+ from->amname, to->amname);
+ return TRUE;
+ }
+ else {
+ if (!pa_multiplex_add_explicit_route(core, mux, sink, from->type))
+ return FALSE;
+ }
+ }
+ else {
+ if ((sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
+ if (sinp->sink == sink)
+ pa_log_debug("direct route already exists. nothing to do");
+ else {
+ pa_log_debug("direct route: sink-input.%u -> sink.%u",
+ sinp->index, sink->index);
+
+ if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
+ return FALSE;
+ }
+ }
}
- if (!from)
- return TRUE;
+ pa_log_debug("link %s => %s is established", from->amname, to->amname);
+
+ return TRUE;
+}
+
+
+static pa_bool_t default_link_from_stream_to_device(struct userdata *u,
+ mir_node *from,
+ mir_node *to)
+{
+ pa_core *core;
+ pa_sink *sink;
+ pa_sink_input *sinp;
+ pa_muxnode *mux;
+
+ pa_assert(u);
+ pa_assert(from);
+ pa_assert(to);
+ pa_assert((core = u->core));
+
+ if (!(sink = setup_device_output(u, to)))
+ return FALSE;
if (!set_profile(u, from)) {
pa_log("can't route from '%s'", from->amname);
return FALSE;
}
+ if ((mux = from->mux)) {
+ sinp = pa_idxset_get_by_index(core->sink_inputs, mux->defstream_index);
- if (from->implement == mir_stream && (mux = from->mux)) {
- if (!(sinp = pa_multiplex_default_stream(core, mux))) {
- pa_log_debug("can't find default stream on mux %u",
- mux->module_index);
+ if (!sinp) {
+ pa_log_debug("no default sstream found on multiplex %u",
+ mux->module_index);
+ mux->defstream_index = PA_IDXSET_INVALID;
return FALSE;
}
+ else if (pa_multiplex_duplicate_route(core, mux, sinp, sink)) {
+ pa_log_debug("default stream on mux %u would be a duplicate "
+ "to an explicit route. Removing it ...",
+ mux->module_index);
+ return TRUE; /* the routing is a success */
+ }
+
+ pa_log_debug("multiplex route: sink-input.%d -> (sink.%d - "
+ "sink-input.%d) -> sink.%d", from->paidx,
+ mux->sink_index, sinp->index, sink->index);
}
else {
if (from->paidx == PA_IDXSET_INVALID) {
}
if (!(sinp = pa_idxset_get_by_index(core->sink_inputs, from->paidx))) {
- pa_log_debug("can't route '%s': cant find sink-input", to->amname);
+ pa_log_debug("can't find sink input for '%s'", from->amname);
return FALSE;
}
+
+ pa_log_debug("direct route: sink-input.%d -> sink.%d",
+ sinp->index, sink->index);
}
if (pa_sink_input_move_to(sinp, sink, FALSE) < 0)
return TRUE;
}
+static pa_sink *setup_device_output(struct userdata *u, mir_node *node)
+{
+ pa_core *core;
+ pa_sink *sink;
+
+ pa_assert(u);
+ pa_assert(node);
+ pa_assert_se((core = u->core));
+
+ if (!set_profile(u, node)) {
+ pa_log("can't route to '%s'", node->amname);
+ return NULL;
+ }
+
+ if (node->paidx == PA_IDXSET_INVALID) {
+ pa_log_debug("can't route to '%s': no sink", node->amname);
+ return NULL;
+ }
+
+ if (!(sink = pa_idxset_get_by_index(core->sinks, node->paidx))) {
+ pa_log_debug("can't route to '%s': cant find sink", node->amname);
+ return NULL;
+ }
+
+ return sink;
+}
+
-pa_bool_t set_profile(struct userdata *u, mir_node *node)
+static pa_bool_t set_profile(struct userdata *u, mir_node *node)
{
pa_core *core;
pa_card *card;
}
+
/*
* Local Variables:
* c-basic-offset: 4
#include "userdata.h"
-pa_bool_t mir_switch_setup_link(struct userdata *, mir_node *, mir_node *);
+pa_bool_t mir_switch_setup_link(struct userdata *, mir_node *, mir_node *,
+ pa_bool_t);
#endif /* foomirswitchfoo */
pa_assert(u);
pa_assert_se((core = u->core));
- pa_utils_new_stamp();
PA_IDXSET_FOREACH(card, core->cards, index) {
pa_discover_add_card(u, card);
pa_assert(u);
pa_assert(card);
- pa_utils_new_stamp();
pa_discover_add_card(u, card);
return PA_HOOK_OK;
pa_assert(u);
pa_assert(card);
- pa_utils_new_stamp();
pa_discover_profile_changed(u, card);
return PA_HOOK_OK;
pa_assert(u);
pa_assert(sink);
- pa_utils_new_stamp();
pa_discover_add_sink(u, sink, TRUE);
return PA_HOOK_OK;
pa_assert(u);
pa_assert(source);
- pa_utils_new_stamp();
pa_discover_add_source(u, source);
return PA_HOOK_OK;
pa_assert(u);
pa_assert(data);
- pa_utils_new_stamp();
pa_discover_preroute_sink_input(u, data);
return PA_HOOK_OK;
pa_assert(u);
pa_assert(sinp);
- pa_utils_new_stamp();
pa_discover_add_sink_input(u, sinp);
return PA_HOOK_OK;
typedef struct pa_discover pa_discover;
typedef struct pa_router pa_router;
typedef struct pa_mir_config pa_mir_config;
+typedef struct pa_nodeset pa_nodeset;
typedef struct pa_node_card pa_node_card;
typedef struct pa_card_hooks pa_card_hooks;
typedef struct pa_sink_hooks pa_sink_hooks;
typedef struct mir_node mir_node;
typedef struct mir_rtgroup mir_rtgroup;
typedef struct mir_rtentry mir_rtentry;
+typedef struct mir_connection mir_connection;
typedef struct am_domainreg_data am_domainreg_data;
typedef struct am_nodereg_data am_nodereg_data;
pa_core *core;
pa_module *module;
pa_null_sink *nullsink;
+ pa_nodeset *nodeset;
pa_audiomgr *audiomgr;
pa_policy_dbusif *dbusif;
pa_discover *discover;
pa_proplist_sets(pl, PA_PROP_ROUTING_CLASS_ID , clid ) < 0 ||
pa_proplist_sets(pl, PA_PROP_ROUTING_METHOD , method) < 0 )
{
- pa_log("failed to set properties on sink-input. "
- "some routing function might malfunction later on");
+ pa_log("failed to set some property on sink-input");
+ }
+}
+
+void pa_utils_set_stream_routing_method_property(pa_proplist *pl,
+ pa_bool_t explicit)
+{
+ const char *method = explicit ? PA_ROUTING_EXPLICIT : PA_ROUTING_DEFAULT;
+
+ pa_assert(pl);
+
+ if (pa_proplist_sets(pl, PA_PROP_ROUTING_METHOD, method) < 0) {
+ pa_log("failed to set routing method property on sink-input");
}
}
}
-const uint32_t pa_utils_new_stamp(void)
+uint32_t pa_utils_new_stamp(void)
{
return ++stamp;
}
-const uint32_t pa_utils_get_stamp(void)
+uint32_t pa_utils_get_stamp(void)
{
return stamp;
}
char *pa_utils_get_sink_input_name_from_data(pa_sink_input_new_data *);
void pa_utils_set_stream_routing_properties(pa_proplist *, int, pa_sink *);
+void pa_utils_set_stream_routing_method_property(pa_proplist *, pa_bool_t);
pa_bool_t pa_utils_stream_has_default_route(pa_proplist *);
const char *pa_utils_file_path(const char *, char *, size_t);
-const uint32_t pa_utils_new_stamp(void);
-const uint32_t pa_utils_get_stamp(void);
+uint32_t pa_utils_new_stamp(void);
+uint32_t pa_utils_get_stamp(void);
#endif