diff options
author | Manuel Bachmann <manuel.bachmann@iot.bzh> | 2016-07-07 17:29:08 +0200 |
---|---|---|
committer | Yannick Gicquel <yannick.gicquel@iot.bzh> | 2016-10-11 17:09:07 +0200 |
commit | cc70e0ae30920ca835bf011f8040afb6fea43f45 (patch) | |
tree | c4d503c5a556bee69842f38b28e85a182c70bfb8 | |
parent | 2478974dfde05063cbf0233e3d3c434ca2f46c7c (diff) |
Implement routing groups and volume ramp up/down
Change-Id: I0e9d3b8b8be4d124907214c165617d86be6906fc
Signed-off-by: Manuel Bachmann <manuel.bachmann@iot.bzh>
-rw-r--r-- | config.c | 5 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | discover.c | 20 | ||||
-rw-r--r-- | node.c | 38 | ||||
-rw-r--r-- | node.h | 3 | ||||
-rw-r--r-- | router.c | 102 | ||||
-rw-r--r-- | router.h | 12 | ||||
-rw-r--r-- | switch.c | 2 | ||||
-rw-r--r-- | utils.c | 35 | ||||
-rw-r--r-- | utils.h | 1 |
10 files changed, 190 insertions, 30 deletions
@@ -74,13 +74,12 @@ static zone_def zones[] = { { NULL } }; - static rtgroup_def rtgroups[] = { { agl_input, "Phone", "PhoneCard", agl_router_phone_accept, - agl_router_phone_compare + agl_router_phone_effect }, { 0, NULL, NULL, NULL, NULL } @@ -128,7 +127,7 @@ bool use_default_configuration (struct userdata *u) for (r = rtgroups; r->name; r++) agl_router_create_rtgroup (u, r->type, r->name, r->node_desc, - r->accept, r->compare); + r->accept, r->effect); for (c = classmap; c->rtgroup; c++) agl_router_assign_class_to_rtgroup (u, c->class, c->zone, @@ -36,7 +36,7 @@ typedef struct { const char *name; const char *node_desc; agl_rtgroup_accept_t accept; - agl_rtgroup_compare_t compare; + agl_rtgroup_effect_t effect; } rtgroup_def; /* CLASS MAP (agl_phone="phone" card routing group...) */ @@ -743,12 +743,10 @@ void agl_discover_register_source_output (struct userdata *u, pa_source_output * void agl_discover_add_sink_input (struct userdata *u, pa_sink_input *sinp) { - pa_core *core; agl_node *node; pa_assert (u); pa_assert (sinp); - pa_assert_se (core = u->core); if (!sinp->client) return; @@ -759,16 +757,22 @@ void agl_discover_add_sink_input (struct userdata *u, pa_sink_input *sinp) /* start routing */ agl_router_register_node (u, node); + + /* apply priority effects */ + agl_router_apply_node_priority_effect (u, node, true); } void agl_discover_remove_sink_input (struct userdata *u, pa_sink_input *sinp) { - pa_core *core; - agl_node *node; + agl_nodeset *nodeset; + agl_node *node, *n; + pa_sink *sink; + int priority; + uint32_t index; pa_assert (u); pa_assert (sinp); - pa_assert_se (core = u->core); + pa_assert_se (nodeset = u->nodeset); if (!sinp->client) return; @@ -779,4 +783,10 @@ void agl_discover_remove_sink_input (struct userdata *u, pa_sink_input *sinp) /* stop routing */ agl_router_unregister_node (u, node); + + /* un-apply priority effects */ + agl_router_apply_node_priority_effect (u, node, false); + + /* remove node */ + agl_node_destroy (u, node); } @@ -20,6 +20,7 @@ * */ #include "node.h" +#include "router.h" #include <pulsecore/idxset.h> @@ -129,12 +130,22 @@ agl_node *agl_node_create (struct userdata *u, agl_node *data) } } - /* TODO : register the node to the router */ - /* agl_router_register_node (u, node); */ - return node; } +void agl_node_destroy (struct userdata *u, agl_node *node) +{ + agl_nodeset *ns; + + pa_assert (u); + pa_assert (node); + pa_assert_se (ns = u->nodeset); + + pa_idxset_remove_by_index (ns->nodes, node->index); + + pa_xfree (node); +} + const char *agl_node_type_str (agl_node_type type) { switch (type) { @@ -208,3 +219,24 @@ agl_node *agl_node_get_from_client (struct userdata *u, pa_client *client) return NULL; } + +bool agl_node_has_highest_priority (struct userdata *u, agl_node *node) +{ + agl_nodeset *nodeset; + agl_node *n; + int priority; + uint32_t index; + + pa_assert (u); + pa_assert (node); + pa_assert (nodeset = u->nodeset); + + priority = agl_router_get_node_priority (u, node); + + PA_IDXSET_FOREACH(n, nodeset->nodes, index) { + if ((n != node) && (agl_router_get_node_priority (u, n) >= priority)) + return false; + } + + return true; +} @@ -104,10 +104,13 @@ void agl_nodeset_done (struct userdata *); int agl_nodeset_add_role (struct userdata *, const char *, agl_node_type, agl_nodeset_resdef *); agl_node *agl_node_create (struct userdata *, agl_node *); +void agl_node_destroy (struct userdata *, agl_node *); const char *agl_node_type_str (agl_node_type); const char *agl_node_direction_str (agl_direction); agl_node *agl_node_get_from_data (struct userdata *, agl_direction, void *); agl_node *agl_node_get_from_client (struct userdata *, pa_client *); +bool agl_node_has_highest_priority (struct userdata *, agl_node *); + #endif @@ -97,19 +97,26 @@ bool agl_router_phone_accept (struct userdata *u, agl_rtgroup *rtg, agl_node *no return true; } -int agl_router_default_compare (struct userdata *u, agl_rtgroup *rtg, agl_node *n1, agl_node *n2) +int agl_router_default_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new) { /* TODO */ return 1; } -int agl_router_phone_compare (struct userdata *u, agl_rtgroup *rtg, agl_node *n1, agl_node *n2) +int agl_router_phone_effect (struct userdata *u, agl_rtgroup *rtg, agl_node *node, bool new) { - /* TODO */ + 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_compare_t compare) +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; @@ -132,7 +139,7 @@ agl_rtgroup *agl_router_create_rtgroup (struct userdata *u, agl_direction type, rtg = pa_xnew0 (agl_rtgroup, 1); rtg->name = pa_xstrdup (name); rtg->accept = accept; - rtg->compare = compare; + rtg->effect = effect; AGL_DLIST_INIT(rtg->entries); /* associate an agl_output node for an agl_input routing group */ if (type == agl_input) { @@ -194,7 +201,7 @@ bool agl_router_assign_class_to_rtgroup (struct userdata *u, agl_node_type class agl_zone *rzone; pa_assert (u); - pa_assert (zone < AGL_ZONE_MAX); + pa_assert (zone < AGL_ZONE_MAX); pa_assert (type == agl_input || type == agl_output); pa_assert (name); pa_assert_se (router = u->router); @@ -225,7 +232,7 @@ bool agl_router_assign_class_to_rtgroup (struct userdata *u, agl_node_type class } zonemap = classmap[zone]; - if (!zonemap) { /* THIS LOOKS LIKE A HACK TO IGNORE THE ERROR... */ + if (!zonemap) { zonemap = pa_xnew0 (agl_rtgroup *, router->maplen); classmap[zone] = zonemap; } @@ -261,6 +268,81 @@ void agl_router_assign_class_priority (struct userdata *u, agl_node_type class, } } +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; @@ -393,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) @@ -29,14 +29,14 @@ #define AGL_ZONE_MAX 8 /* max 8 zones, demo is using 5 */ /* DEFINED IN MURPHY */ typedef bool (*agl_rtgroup_accept_t)(struct userdata *, agl_rtgroup *, agl_node *); -typedef int (*agl_rtgroup_compare_t)(struct userdata *, agl_rtgroup *, agl_node *, agl_node *); +typedef int (*agl_rtgroup_effect_t)(struct userdata *, agl_rtgroup *, agl_node *, bool new); struct agl_rtgroup { char *name; /**< name of the rtgroup */ agl_dlist entries; /**< listhead of ordered rtentries */ agl_node *node; /**< final node */ agl_rtgroup_accept_t accept; /**< function pointer, whether to accept a node or not */ - agl_rtgroup_compare_t compare; /**< function pointer, comparision for ordering */ + agl_rtgroup_effect_t effect; /**< function pointer, custom action such as volume up, down */ }; typedef struct { @@ -73,13 +73,15 @@ void agl_router_done (struct userdata *); bool agl_router_default_accept (struct userdata *, agl_rtgroup *, agl_node *); bool agl_router_phone_accept (struct userdata *, agl_rtgroup *, agl_node *); -int agl_router_default_compare (struct userdata *, agl_rtgroup *, agl_node *, agl_node *); -int agl_router_phone_compare (struct userdata *, agl_rtgroup *, agl_node *, agl_node *); +int agl_router_default_effect (struct userdata *, agl_rtgroup *, agl_node *, bool); +int agl_router_phone_effect (struct userdata *, agl_rtgroup *, agl_node *, bool); -agl_rtgroup *agl_router_create_rtgroup (struct userdata *, agl_direction, const char *, const char *, agl_rtgroup_accept_t, agl_rtgroup_compare_t); +agl_rtgroup *agl_router_create_rtgroup (struct userdata *, agl_direction, const char *, const char *, agl_rtgroup_accept_t, agl_rtgroup_effect_t); void agl_router_destroy_rtgroup (struct userdata *, agl_direction, const char *); bool agl_router_assign_class_to_rtgroup (struct userdata *, agl_node_type, uint32_t, agl_direction, const char *); void agl_router_assign_class_priority (struct userdata *, agl_node_type, int); +int agl_router_get_node_priority (struct userdata *, agl_node *); +bool agl_router_apply_node_priority_effect (struct userdata *, agl_node *, bool); void agl_router_register_node (struct userdata *, agl_node *); void agl_router_unregister_node (struct userdata *, agl_node *); @@ -107,6 +107,7 @@ bool agl_switch_setup_link (struct userdata *u, agl_node *from, agl_node *to, bo /* STREAM TO DEVICE : OK */ case agl_stream: sink = agl_utils_get_alsa_sink (u, to->paname); + if (!sink) break; source = agl_utils_get_null_source (u, from->nullsink); from->loopnode = agl_loopnode_create (u, AGL_LOOPNODE_SINK, from->index, source->index, sink->index); @@ -147,7 +148,6 @@ bool agl_switch_setup_link (struct userdata *u, agl_node *from, agl_node *to, bo sink = agl_utils_get_primary_alsa_sink (u); source = agl_utils_get_null_source (u, from->nullsink); - from->loopnode = agl_loopnode_create (u, AGL_LOOPNODE_SINK, from->index, source->index, sink->index); } } @@ -120,6 +120,39 @@ pa_source *agl_utils_get_null_source (struct userdata *u, struct agl_null_sink * return sink ? sink->monitor_source : NULL; } +void agl_utils_volume_ramp (struct userdata *u, struct agl_null_sink *ns, bool up) +{ + pa_core *core; + pa_sink *sink; + pa_sink_input *sinp; + uint32_t index; + pa_cvolume_ramp rampvol; + pa_volume_t newvol; + long time; + + if (up) { + newvol = PA_VOLUME_NORM; + time = 5000; + } else { + newvol = PA_VOLUME_NORM *10/100; + time = 3000; + } + + pa_assert (u); + pa_assert_se ((core = u->core)); + + sink = agl_utils_get_null_sink (u, ns); + PA_IDXSET_FOREACH(sinp, core->sink_inputs, index) { + if (sinp->sink && sinp->sink == sink) + break; + sinp = NULL; + } + if (!sinp) return; + + pa_cvolume_ramp_set (&rampvol, sinp->volume.channels, PA_VOLUME_RAMP_TYPE_LINEAR, + time, newvol); + pa_sink_input_set_volume_ramp (sinp, &rampvol, true, false); +} const char *agl_utils_get_card_name (pa_card *card) { @@ -196,7 +229,7 @@ pa_sink *agl_utils_get_primary_alsa_sink (struct userdata *u) pa_assert_se ((core = u->core)); PA_IDXSET_FOREACH(sink, core->sinks, idx) { - if (sink->name && strstr (sink->name, "alsa_output") && strstr (sink->name, "pci")) + if (sink->name && strstr (sink->name, "alsa_output")) return sink; } @@ -32,6 +32,7 @@ struct agl_null_sink *agl_utils_create_null_sink (struct userdata *, const char void agl_utils_destroy_null_sink (struct userdata *, struct agl_null_sink *); pa_sink *agl_utils_get_null_sink (struct userdata *, struct agl_null_sink *); pa_source *agl_utils_get_null_source (struct userdata *, struct agl_null_sink *); +void agl_utils_volume_ramp (struct userdata *, struct agl_null_sink *, bool); /* general helper functions */ const char *agl_utils_get_card_name (pa_card *); |