[pulseaudio-discuss] [PATCH v4] bluetooth: Add optional heuristic for switching between hsp and a2dp profiles
Pali Rohár
pali.rohar at gmail.com
Mon Sep 19 14:44:00 UTC 2016
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