Hi! Please let me know what do you think about this v4 version of my patch. On Sunday 11 September 2016 16:41:02 Pali Rohár wrote: > Not all VOIP applications (specially those which use alsa) set media.role to > phone. This means we need some heuristic to determinate if we want to switch > from a2dp to hsp profile based on number and types of source output (recording) > streams. > > And also some people want to use their bluetooth headset (with microphone) as > their default recording device but some do not want to because of low quality. > > This patch implements optional heuristic which is disabled by default. It is > disabled by default to not break experience of current pulseaudio users because > heuristic cannot be optimal. Heuristic is implemented in module-bluetooth-policy > module and decide if pulseaudio should switch to a hsp profile or not. It checks > if there is some source output with pass all these conditions: > > * does not have set media.role > * does not use peak resample method (which is used by desktop volume programs) > * has assigned client/application (non virtual stream) > * does not record from monitor of sink > > And if yes it switch to hsp profile. > > By default this heuristic is disabled and can be enabled when loading module > module-bluetooth-policy with specifying parameter auto_switch=2 > > Because it is disabled by default nobody will be affected by this change unless > manually change auto_switch parameter. > > Signed-off-by: Pali Rohár <pali.rohar at gmail.com> > --- > src/modules/bluetooth/module-bluetooth-policy.c | 43 ++++++++++++++++------- > 1 file changed, 30 insertions(+), 13 deletions(-) > > diff --git a/src/modules/bluetooth/module-bluetooth-policy.c b/src/modules/bluetooth/module-bluetooth-policy.c > index 68c8ab4..3f085b8 100644 > --- a/src/modules/bluetooth/module-bluetooth-policy.c > +++ b/src/modules/bluetooth/module-bluetooth-policy.c > @@ -38,7 +38,7 @@ PA_MODULE_DESCRIPTION("Policy module to make using bluetooth devices out-of-the- > PA_MODULE_VERSION(PACKAGE_VERSION); > PA_MODULE_LOAD_ONCE(true); > PA_MODULE_USAGE( > - "auto_switch=<Switch between hsp and a2dp profile?> " > + "auto_switch=<Switch between hsp and a2dp profile? (0 - never, 1 - media.role=phone, 2 - heuristic> " > "a2dp_source=<Handle a2dp_source card profile (sink role)?> " > "ag=<Handle headset_audio_gateway card profile (headset role)?> " > "hfgw=<Handle hfgw card profile (headset role)?> DEPRECATED"); > @@ -52,6 +52,7 @@ static const char* const valid_modargs[] = { > }; > > struct userdata { > + uint32_t auto_switch; > bool enable_a2dp_source; > bool enable_ag; > pa_hook_slot *source_put_slot; > @@ -210,7 +211,8 @@ static void switch_profile(pa_card *card, bool revert_to_a2dp, void *userdata) { > } > > /* Return true if we should ignore this source output */ > -static bool ignore_output(pa_source_output *source_output) { > +static bool ignore_output(pa_source_output *source_output, void *userdata) { > + struct userdata *u = userdata; > const char *s; > > /* New applications could set media.role for identifying streams */ > @@ -219,16 +221,32 @@ static bool ignore_output(pa_source_output *source_output) { > if (s) > return !pa_streq(s, "phone"); > > - return true; > + /* If media.role is not set use some heuristic (if enabled) */ > + if (u->auto_switch != 2) > + return true; > + > + /* Ignore if resample method is peaks (used by desktop volume programs) */ > + if (pa_source_output_get_resample_method(source_output) == PA_RESAMPLER_PEAKS) > + return true; > + > + /* Ignore if there is no client/application assigned (used by virtual stream) */ > + if (!source_output->client) > + return true; > + > + /* Ignore if recording from monitor of sink */ > + if (source_output->direct_on_input) > + return true; > + > + return false; > } > > -static unsigned source_output_count(pa_core *c) { > +static unsigned source_output_count(pa_core *c, void *userdata) { > pa_source_output *source_output; > uint32_t idx; > unsigned count = 0; > > PA_IDXSET_FOREACH(source_output, c->source_outputs, idx) > - if (!ignore_output(source_output)) > + if (!ignore_output(source_output, userdata)) > ++count; > > return count; > @@ -248,7 +266,7 @@ static pa_hook_result_t source_output_put_hook_callback(pa_core *c, pa_source_ou > pa_assert(c); > pa_assert(source_output); > > - if (ignore_output(source_output)) > + if (ignore_output(source_output, userdata)) > return PA_HOOK_OK; > > switch_profile_all(c->cards, false, userdata); > @@ -260,11 +278,11 @@ static pa_hook_result_t source_output_unlink_hook_callback(pa_core *c, pa_source > pa_assert(c); > pa_assert(source_output); > > - if (ignore_output(source_output)) > + if (ignore_output(source_output, userdata)) > return PA_HOOK_OK; > > /* If there are still some source outputs do nothing (count is with *this* source_output, so +1) */ > - if (source_output_count(c) > 1) > + if (source_output_count(c, userdata) > 1) > return PA_HOOK_OK; > > switch_profile_all(c->cards, true, userdata); > @@ -278,7 +296,7 @@ static pa_hook_result_t card_init_profile_hook_callback(pa_core *c, pa_card *car > pa_assert(c); > pa_assert(card); > > - if (source_output_count(c) == 0) > + if (source_output_count(c, userdata) == 0) > return PA_HOOK_OK; > > /* Only consider bluetooth cards */ > @@ -388,7 +406,6 @@ static void handle_all_profiles(pa_core *core) { > int pa__init(pa_module *m) { > pa_modargs *ma; > struct userdata *u; > - bool auto_switch; > > pa_assert(m); > > @@ -399,8 +416,8 @@ int pa__init(pa_module *m) { > > m->userdata = u = pa_xnew0(struct userdata, 1); > > - auto_switch = true; > - if (pa_modargs_get_value_boolean(ma, "auto_switch", &auto_switch) < 0) { > + u->auto_switch = 1; > + if (pa_modargs_get_value_u32(ma, "auto_switch", &u->auto_switch) < 0) { > pa_log("Failed to parse auto_switch argument."); > goto fail; > } > @@ -429,7 +446,7 @@ int pa__init(pa_module *m) { > u->sink_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL, > (pa_hook_cb_t) sink_put_hook_callback, u); > > - if (auto_switch) { > + if (u->auto_switch) { > u->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL, > (pa_hook_cb_t) source_output_put_hook_callback, u); > -- Pali Rohár pali.rohar at gmail.com