[pulseaudio-discuss] [V3 PATCH] rescue-streams: try to find best one using availability and priority

David Henningsson david.henningsson at canonical.com
Mon Jun 9 23:37:21 PDT 2014



On 2014-06-05 11:27, Hui Wang wrote:
> Recently met a problem: when I disconnect the bluetooth headset, the
> pulseaudio automatically switch the sound to sink of HDMI output
> instead of the sink of internal speaker even though there is no HDMI
> cable connected.
>
> To fix this problem, I want to change the rule of selecting the target
> sink if the default sink is not available. (same rules apply to the
> source selecting):
> construct a new hashmap with all ports (of all relevant sinks) and
> then call find_best on the new hashmap to find the best port, finally
> find the corresponding sink using the best port.

Thanks, I've pushed this patch to the PA repository now. There were two 
minor things to fix but I found it easier to fix them myself than to let 
you do a v4.

See 
http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=38c5d6d585f588665280df3cecc2ea68a2dcd807 
if you're curious.

>
> Signed-off-by: Hui Wang <hui.wang at canonical.com>
> ---
> diff Vs V2:
> 1) The default sink is not the root cause for this problem, so
> i don't remove it in this version.
>
> 2) Use pa_idxset_trivial_* funcs to replace pa_idxset_string_* funcs
> and use port pointers as key rather than the name
>
> 3) fix the wrong indentation
>
> 4) add a fallback sink in case the sink has no ports.
>
>   src/modules/module-rescue-streams.c | 99 +++++++++++++++++++++++++++++++++----
>   1 file changed, 89 insertions(+), 10 deletions(-)
>
> diff --git a/src/modules/module-rescue-streams.c b/src/modules/module-rescue-streams.c
> index 7035a35..265711c 100644
> --- a/src/modules/module-rescue-streams.c
> +++ b/src/modules/module-rescue-streams.c
> @@ -52,9 +52,56 @@ struct userdata {
>           *source_output_move_fail_slot;
>   };
>
> +static pa_source* find_source_from_port(pa_core *c, pa_device_port *port) {
> +    pa_source *target;
> +    uint32_t idx;
> +    void *state;
> +    pa_device_port *p;
> +
> +    if (!port)
> +        return NULL;
> +
> +    PA_IDXSET_FOREACH(target, c->sources, idx)
> +        PA_HASHMAP_FOREACH(p, target->ports, state)
> +            if (port == p)
> +                return target;
> +
> +    return NULL;
> +}
> +
> +static pa_sink* find_sink_from_port(pa_core *c, pa_device_port *port) {
> +    pa_sink *target;
> +    uint32_t idx;
> +    void *state;
> +    pa_device_port *p;
> +
> +    if (!port)
> +        return NULL;
> +
> +    PA_IDXSET_FOREACH(target, c->sinks, idx)
> +        PA_HASHMAP_FOREACH(p, target->ports, state)
> +            if (port == p)
> +                return target;
> +
> +    return NULL;
> +}
> +
> +static void build_group_ports(pa_hashmap *g_ports, pa_hashmap *s_ports) {
> +    void *state;
> +    pa_device_port *p;
> +
> +    if (!g_ports || !s_ports)
> +        return;
> +
> +    PA_HASHMAP_FOREACH(p, s_ports, state)
> +        pa_hashmap_put(g_ports, p, p);
> +}
> +
>   static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip) {
> -    pa_sink *target, *def;
> +    pa_sink *target, *def, *fb_sink = NULL;
>       uint32_t idx;
> +    pa_hashmap *all_ports;
> +    pa_device_port *best_port;
>
>       pa_assert(c);
>       pa_assert(i);
> @@ -64,6 +111,8 @@ static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip
>       if (def && def != skip && pa_sink_input_may_move_to(i, def))
>           return def;
>
> +    all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
> +
>       PA_IDXSET_FOREACH(target, c->sinks, idx) {
>           if (target == def)
>               continue;
> @@ -74,12 +123,25 @@ static pa_sink* find_evacuation_sink(pa_core *c, pa_sink_input *i, pa_sink *skip
>           if (!PA_SINK_IS_LINKED(pa_sink_get_state(target)))
>               continue;
>
> -        if (pa_sink_input_may_move_to(i, target))
> -            return target;
> +        if (!pa_sink_input_may_move_to(i, target))
> +            continue;
> +
> +        fb_sink = target;
> +
> +        build_group_ports(all_ports, target->ports);
>       }
>
> -    pa_log_debug("No evacuation sink found.");
> -    return NULL;
> +    best_port = pa_device_port_find_best(all_ports);
> +
> +    pa_hashmap_free(all_ports);
> +
> +    if(!best_port) {
> +	pa_log_debug("No evacuation sink found.");
> +        target = fb_sink;
> +    } else
> +	target = find_sink_from_port(c, best_port);
> +
> +    return target;
>   }
>
>   static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, void* userdata) {
> @@ -141,8 +203,10 @@ static pa_hook_result_t sink_input_move_fail_hook_callback(pa_core *c, pa_sink_i
>   }
>
>   static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_source *skip) {
> -    pa_source *target, *def;
> +    pa_source *target, *def, *fb_source = NULL;
>       uint32_t idx;
> +    pa_hashmap *all_ports;
> +    pa_device_port *best_port;
>
>       pa_assert(c);
>       pa_assert(o);
> @@ -152,6 +216,8 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou
>       if (def && def != skip && pa_source_output_may_move_to(o, def))
>           return def;
>
> +    all_ports = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
> +
>       PA_IDXSET_FOREACH(target, c->sources, idx) {
>           if (target == def)
>               continue;
> @@ -165,12 +231,25 @@ static pa_source* find_evacuation_source(pa_core *c, pa_source_output *o, pa_sou
>           if (!PA_SOURCE_IS_LINKED(pa_source_get_state(target)))
>               continue;
>
> -        if (pa_source_output_may_move_to(o, target))
> -            return target;
> +        if (!pa_source_output_may_move_to(o, target))
> +            continue;
> +
> +        fb_source = target;
> +
> +        build_group_ports(all_ports, target->ports);
>       }
>
> -    pa_log_debug("No evacuation source found.");
> -    return NULL;
> +    best_port = pa_device_port_find_best(all_ports);
> +
> +    pa_hashmap_free(all_ports);
> +
> +    if(!best_port) {
> +        pa_log_debug("No evacuation source found.");
> +        target = fb_source;
> +    } else
> +        target = find_source_from_port(c, best_port);
> +
> +    return target;
>   }
>
>   static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *source, void* userdata) {
>

-- 
David Henningsson, Canonical Ltd.
https://launchpad.net/~diwic


More information about the pulseaudio-discuss mailing list