Signed-off-by: David Henningsson <david.henningsson at canonical.com> --- src/modules/module-switch-on-connect.c | 68 +++++++++++++++++++++++++++++++- 1 files changed, 67 insertions(+), 1 deletions(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index 86eadd7..c99d8a3 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -49,7 +49,8 @@ static const char* const valid_modargs[] = { struct userdata { pa_hook_slot *sink_put_slot, - *source_put_slot; + *source_put_slot, + *port_available_slot; }; static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* userdata) { @@ -154,6 +155,68 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, return PA_HOOK_OK; } +static pa_device_port* find_best_port(pa_hashmap *ports) { + void *state; + pa_device_port* port, *result = NULL; + unsigned prio = 0; + + PA_HASHMAP_FOREACH(port, ports, state) { + if (result == NULL || (port->available != PA_PORT_AVAILABLE_NO && port->priority > prio)) { + result = port; + prio = port->priority; + } + } + pa_assert(result != NULL); + return result; +} + +static pa_hook_result_t port_available_hook_callback(pa_core *c, pa_device_port *port, void* userdata) { + uint32_t state; + pa_card* card; + pa_sink* sink; + pa_source* source; + pa_bool_t /* is_active_profile, */ is_active_port; + + pa_log_debug("finding port %s", port->name); + PA_IDXSET_FOREACH(card, c->cards, state) + if (card->ports && port == pa_hashmap_get(card->ports, port->name)) + break; + + if (!card) { + pa_log_warn("Did not find port %s in array of cards", port->name); + return PA_HOOK_OK; + } + + PA_IDXSET_FOREACH(source, card->sources, state) + if (source->ports && port == pa_hashmap_get(source->ports, port->name)) + break; + PA_IDXSET_FOREACH(sink, card->sinks, state) + if (sink->ports && port == pa_hashmap_get(sink->ports, port->name)) + break; + + /* is_active_profile = port->profiles && card->active_profile && + card->active_profile == pa_hashmap_get(port->profiles, card->active_profile->name); */ + is_active_port = (sink && sink->active_port == port) || (source && source->active_port == port); + + /* TODO: Switch profiles as well, if necessary */ + + if (port->available == PA_PORT_AVAILABLE_YES && !is_active_port) { + if (sink) + pa_sink_set_port(sink, port->name, FALSE); + if (source) + pa_source_set_port(source, port->name, FALSE); + } + + if (port->available == PA_PORT_AVAILABLE_NO && is_active_port) { + if (sink) + pa_sink_set_port(sink, find_best_port(sink->ports)->name, FALSE); + if (source) + pa_source_set_port(source, find_best_port(source->ports)->name, FALSE); + } + + return PA_HOOK_OK; +} + int pa__init(pa_module*m) { pa_modargs *ma; struct userdata *u; @@ -170,6 +233,7 @@ int pa__init(pa_module*m) { /* A little bit later than module-rescue-streams... */ u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+30, (pa_hook_cb_t) sink_put_hook_callback, u); u->source_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+20, (pa_hook_cb_t) source_put_hook_callback, u); + u->port_available_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_PORT_AVAILABLE_CHANGED], PA_HOOK_LATE+20, (pa_hook_cb_t) port_available_hook_callback, u); pa_modargs_free(ma); return 0; @@ -183,6 +247,8 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; + if (u->port_available_slot) + pa_hook_slot_free(u->port_available_slot); if (u->sink_put_slot) pa_hook_slot_free(u->sink_put_slot); if (u->source_put_slot) -- 1.7.5.4