*/
#include "router.h"
#include "switch.h"
+#include "zone.h"
#include "utils.h"
-pa_router *pa_router_init (struct userdata *u)
+agl_router *agl_router_init (struct userdata *u)
{
- pa_router *router;
+ agl_router *router;
size_t num_classes;
num_classes = agl_application_class_end;
- router = pa_xnew0 (pa_router, 1);
+ router = pa_xnew0 (agl_router, 1);
router->rtgroups.input = pa_hashmap_new (pa_idxset_string_hash_func,
pa_idxset_string_compare_func);
router->rtgroups.output = pa_hashmap_new (pa_idxset_string_hash_func,
return router;
}
-void pa_router_done (struct userdata *u)
+void agl_router_done (struct userdata *u)
{
- pa_router *router;
+ agl_router *router;
agl_node *e,*n;
agl_connection *conn, *c;
agl_rtgroup *rtg;
}
}
+bool agl_router_default_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
+{
+ /* TODO */
+ return true;
+}
+
+bool agl_router_phone_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *node)
+{
+ /* TODO */
+ return true;
+}
+
+int agl_router_default_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new)
+{
+ /* TODO */
+ return 1;
+}
+
+int agl_router_phone_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new)
+{
+ pa_assert (u);
+ pa_assert (node);
+
+ if (new)
+ agl_utils_volume_ramp (u, node->nullsink, false);
+ else
+ agl_utils_volume_ramp (u, node->nullsink, true);
+
+ return 1;
+}
+
+agl_rtgroup *agl_router_create_rtgroup (struct userdata *u, agl_direction type, const char *name, const char *node_desc, agl_rtgroup_accept_t accept, agl_rtgroup_effect_t effect)
+{
+ agl_router *router;
+ agl_rtgroup *rtg;
+ agl_nodeset *nodeset;
+ agl_node *node;
+ pa_hashmap *table;
+
+ pa_assert (u);
+ pa_assert (type == agl_input || type == agl_output);
+ pa_assert (name);
+ pa_assert_se (router = u->router);
+ pa_assert_se (nodeset = u->nodeset);
+
+ if (type == agl_input)
+ table = router->rtgroups.input;
+ else
+ table = router->rtgroups.output;
+ pa_assert (table);
+
+ rtg = pa_xnew0 (agl_rtgroup, 1);
+ rtg->name = pa_xstrdup (name);
+ rtg->accept = accept;
+ rtg->effect = effect;
+ AGL_DLIST_INIT(rtg->entries);
+ /* associate an agl_output node for an agl_input routing group */
+ if (type == agl_input) {
+ node = agl_node_create (u, NULL);
+ node->direction = agl_output;
+ node->implement = agl_device;
+ node->visible = true;
+ node->available = true;
+ node->paname = pa_xstrdup (node_desc);
+ /* add to global nodeset */
+ pa_idxset_put (nodeset->nodes, node, &node->index);
+ rtg->node = node;
+ } else {
+ rtg->node = NULL;
+ }
+
+
+ pa_hashmap_put (table, rtg->name, rtg);
+
+ pa_log_debug ("routing group '%s' created", name);
+
+ return rtg;
+}
+
+void agl_router_destroy_rtgroup (struct userdata *u, agl_direction type, const char *name)
+{
+ agl_router *router;
+ agl_rtgroup *rtg;
+ pa_hashmap *table;
+
+ pa_assert (u);
+ pa_assert (name);
+ pa_assert_se (router = u->router);
+
+ if (type == agl_input)
+ table = router->rtgroups.input;
+ else
+ table = router->rtgroups.output;
+ pa_assert (table);
+
+ rtg = pa_hashmap_remove (table, name);
+ if (!rtg) {
+ pa_log_debug ("can't destroy routing group '%s': not found", name);
+ } else {
+ //rtgroup_destroy (u, rtg);
+ pa_log_debug ("routing group '%s' destroyed", name);
+ }
+}
+
+bool agl_router_assign_class_to_rtgroup (struct userdata *u, agl_node_type class, uint32_t zone, agl_direction type, const char *name)
+{
+ agl_router *router;
+ pa_hashmap *rtable;
+ agl_rtgroup ***classmap;
+ agl_rtgroup **zonemap;
+ const char *classname;
+ const char *direction;
+ agl_rtgroup *rtg;
+ agl_zone *rzone;
+
+ pa_assert (u);
+ pa_assert (zone < AGL_ZONE_MAX);
+ pa_assert (type == agl_input || type == agl_output);
+ pa_assert (name);
+ pa_assert_se (router = u->router);
+
+ if (type == agl_input) {
+ rtable = router->rtgroups.input;
+ classmap = router->classmap.input;
+ } else {
+ rtable = router->rtgroups.output;
+ classmap = router->classmap.output;
+ }
+
+ if (class < 0 || class >= router->maplen) {
+ pa_log_debug ("Cannot assign class to routing group '%s': "
+ "id %d out of range (0 - %d)",
+ name, class, router->maplen);
+ return false;
+ }
+
+ classname = agl_node_type_str (class); /* "Player", "Radio"... */
+ direction = agl_node_direction_str (type); /* "input", "output" */
+
+ rtg = pa_hashmap_get (rtable, name);
+ if (!rtg) {
+ pa_log_debug ("Cannot assign class to routing group '%s': "
+ "router group not found", name);
+ return false;
+ }
+
+ zonemap = classmap[zone];
+ if (!zonemap) {
+ zonemap = pa_xnew0 (agl_rtgroup *, router->maplen);
+ classmap[zone] = zonemap;
+ }
+
+ zonemap[class] = rtg;
+
+ /* try to get zone name for logging, if fails, only print id number */
+ rzone = agl_zoneset_get_zone_by_index (u, zone);
+ if (rzone) {
+ pa_log_debug ("class '%s'@'%s' assigned to routing group '%s'",
+ classname, rzone->name, name);
+ } else {
+ pa_log_debug ("class '%s'@zone%d assigned to routing group '%s'",
+ classname, zone, name);
+ }
+
+ return true;
+}
+
+agl_rtgroup * agl_router_get_rtgroup_from_class (struct userdata *u, agl_node_type class, uint32_t zone, agl_direction type)
+{
+ agl_router *router;
+ pa_hashmap *rtable;
+ agl_rtgroup ***classmap;
+ agl_rtgroup **zonemap;
+ agl_rtgroup * rtg;
+
+ pa_assert (u);
+ pa_assert_se (router = u->router);
+ pa_assert (class >= 0 && class < router->maplen);
+ pa_assert (zone < AGL_ZONE_MAX);
+ pa_assert (type == agl_input || type == agl_output);
+
+ if (type == agl_input) {
+ rtable = router->rtgroups.input;
+ classmap = router->classmap.input;
+ } else {
+ rtable = router->rtgroups.output;
+ classmap = router->classmap.output;
+ }
+
+ zonemap = classmap[zone];
+ rtg = zonemap[class];
+
+ return rtg;
+}
+
+void agl_router_assign_class_priority (struct userdata *u, agl_node_type class, int priority)
+{
+ agl_router *router;
+ int *priormap;
+
+ pa_assert (u);
+ pa_assert_se (router = u->router);
+ pa_assert_se (priormap = router->priormap);
+
+ if (class > 0 && class < router->maplen) {
+ pa_log_debug ("assigning priority %d to class '%s'",
+ priority, agl_node_type_str (class));
+ priormap[class] = priority;
+ }
+}
+
+int agl_router_get_node_priority (struct userdata *u, agl_node *node)
+{
+ agl_router *router;
+ int class;
+
+ pa_assert (u);
+ pa_assert (node);
+ pa_assert_se (router = u->router);
+
+ class = node->type;
+
+ if (class < 0 || class >= (int)router->maplen)
+ return 0;
+
+ return router->priormap[class];
+}
+
+bool agl_router_apply_node_priority_effect (struct userdata *u, agl_node *node, bool new)
+{
+ agl_router *router;
+ agl_rtgroup *rtg;
+ agl_nodeset *nodeset;
+ agl_node *n;
+ pa_sink *sink;
+ int priority;
+ uint32_t index;
+
+ pa_assert (u);
+ pa_assert (node);
+ pa_assert_se (router = u->router);
+ pa_assert_se (nodeset = u->nodeset);
+
+ rtg = agl_router_get_rtgroup_from_class(u, node->type, 0, node->direction);
+
+ /* now let us compare priorities, and apply effect if needed */
+ /* "new" case */
+ if (new) {
+ priority = agl_router_get_node_priority (u, node);
+ PA_IDXSET_FOREACH(n, nodeset->nodes, index) {
+ if (n->nullsink && (priority > agl_router_get_node_priority (u, n))) {
+ sink = agl_utils_get_null_sink (u, n->nullsink);
+ if (sink) {
+ /* do we have a custom effect ? otherwise, just mute it */
+ if (rtg && rtg->effect)
+ rtg->effect (u, rtg, n, new);
+ else
+ pa_sink_set_mute (sink, new, false);
+ }
+ }
+ }
+ } else {
+ /* "old" case */
+ if (!agl_node_has_highest_priority (u, node))
+ return true;
+ PA_IDXSET_FOREACH(n, nodeset->nodes, index) {
+ if (n->nullsink) {
+ sink = agl_utils_get_null_sink (u, n->nullsink);
+ if (sink) {
+ /* do we have a custom effect ? otherwise, just unmute it */
+ if (rtg && rtg->effect)
+ rtg->effect (u, rtg, n, new);
+ else
+ pa_sink_set_mute (sink, new, false);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
void agl_router_register_node (struct userdata *u, agl_node *node)
{
+ agl_router *router;
+ agl_rtgroup *rtg;
+
pa_assert (u);
pa_assert (node);
+ pa_assert_se (router = u->router);
+
+ /* we try to discover node routing group from the configuration, "Phone" for instance,
+ * see defaults in "config.c. Otherwise we just say NULL, a.k.a. default */
+ rtg = agl_router_get_rtgroup_from_class(u, node->type, 0, node->direction);
- implement_default_route (u, node, NULL, pa_utils_new_stamp ());
+ if (node->direction == agl_input) {
+ if (rtg)
+ implement_default_route (u, node, rtg->node, agl_utils_new_stamp ());
+ else
+ implement_default_route (u, node, NULL, agl_utils_new_stamp ());
+ } else {
+ if (rtg)
+ implement_default_route (u, rtg->node, node, agl_utils_new_stamp ());
+ else
+ implement_default_route (u, NULL, node, agl_utils_new_stamp ());
+ }
}
void agl_router_unregister_node (struct userdata *u, agl_node *node)
pa_assert (u);
pa_assert (node);
- remove_routes (u, node, NULL, pa_utils_new_stamp ());
+ remove_routes (u, node, NULL, agl_utils_new_stamp ());
}
agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
{
- pa_router *router;
+ agl_router *router;
int priority;
static bool done_prerouting;
uint32_t stamp;
done_prerouting = false;
target = NULL;
- stamp = pa_utils_new_stamp ();
+ stamp = agl_utils_new_stamp ();
//make_explicit_routes (u, stamp);
void agl_router_make_routing (struct userdata *u)
{
- pa_router *router;
+ agl_router *router;
static bool ongoing_routing; /* true while we are actively routing */
uint32_t stamp;
agl_node *start, *end;
if (ongoing_routing) /* already routing, canceling */
return;
ongoing_routing = true;
- stamp = pa_utils_new_stamp ();
+ stamp = agl_utils_new_stamp ();
pa_log_debug("stamp for routing: %d", stamp);
agl_node *start, agl_node *end,
uint32_t stamp)
{
- if (start->direction == agl_input) {
- agl_switch_setup_link (u, start, end, false);
- //agl_volume_add_limiting_class(u, end, volume_class(start), stamp);
- } else {
- agl_switch_setup_link (u, end, start, false);
- }
+ if (start->direction == agl_input)
+ agl_switch_setup_link (u, start, end);
+ else
+ agl_switch_setup_link (u, end, start);
}
agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)