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