Fix compilation with json-c on Yocto
[staging/agl-audio-plugin.git] / router.c
index 2478ab2..4ef0180 100644 (file)
--- a/router.c
+++ b/router.c
  */
 #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,
@@ -44,9 +45,9 @@ pa_router *pa_router_init (struct userdata *u)
        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;
@@ -84,12 +85,288 @@ void pa_router_done (struct userdata *u)
        }
 }
 
+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;
+}
+
+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);
+
+        /* do we have a routing group associated with this node ? It may have a custom effect */
+       if (node->direction == agl_input)
+               rtg = pa_hashmap_get (router->rtgroups.input, agl_node_type_str (node->type));
+       else
+               rtg = pa_hashmap_get (router->rtgroups.output, agl_node_type_str (node->type));
+
+       /* 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);
 
-       implement_default_route (u, node, NULL, pa_utils_new_stamp ());
+       /* 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 */
+       if (node->direction == agl_input) {
+               rtg = pa_hashmap_get (router->rtgroups.input, agl_node_type_str (node->type));
+               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 {
+               rtg = pa_hashmap_get (router->rtgroups.output, agl_node_type_str (node->type));
+               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)
@@ -97,12 +374,12 @@ 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;
@@ -117,7 +394,7 @@ agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
 
        done_prerouting = false;
        target = NULL;
-       stamp = pa_utils_new_stamp ();
+       stamp = agl_utils_new_stamp ();
 
        //make_explicit_routes (u, stamp);
 
@@ -157,7 +434,7 @@ agl_node *agl_router_make_prerouting (struct userdata *u, agl_node *data)
 
 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;
@@ -168,7 +445,7 @@ void agl_router_make_routing (struct userdata *u)
        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);
 
@@ -198,12 +475,10 @@ void implement_default_route (struct userdata *u,
                               agl_node *start, agl_node *end,
                               uint32_t stamp)
 {
-       if (start->direction == agl_input) {
+       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 {
+       else
                agl_switch_setup_link (u, end, start, false);
-       }
 }
 
 agl_node *find_default_route (struct userdata *u, agl_node *start, uint32_t stamp)