Anybody? On Monday 19 September 2016 16:44:00 Pali Rohár wrote: > 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