[pulseaudio-discuss] [PATCH v4] bluetooth: Add optional heuristic for switching between hsp and a2dp profiles

Pali Rohár pali.rohar at gmail.com
Fri Oct 21 21:07:55 UTC 2016


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


More information about the pulseaudio-discuss mailing list