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

Pali Rohár pali.rohar at gmail.com
Fri Oct 31 15:50:40 PDT 2014


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. 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 some heuristic in module-bluetooth-policy module to decide
if pulseaudio should switch to hsp profile or not. It check if there is some
source output with pass all these conditions:

* does not have set media.role
* do not use peak resample method (which is used by desktop volume programs)
* has assigned client/application (non virtual stream)
* do 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 switch=2

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 200fc84..c682af9 100644
--- a/src/modules/bluetooth/module-bluetooth-policy.c
+++ b/src/modules/bluetooth/module-bluetooth-policy.c
@@ -40,7 +40,7 @@ PA_MODULE_DESCRIPTION("Automatically switch between bluetooth hsp and a2dp profi
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(true);
 PA_MODULE_USAGE(
-        "switch=<Switch between hsp and a2dp profile?> "
+        "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");
@@ -54,6 +54,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;
@@ -208,7 +209,8 @@ static void switch_profile(pa_card *card, bool revert) {
 }
 
 /* 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 identifing streams */
@@ -217,16 +219,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;
@@ -246,7 +264,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);
@@ -258,11 +276,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);
@@ -275,7 +293,7 @@ static pa_hook_result_t card_new_hook_callback(pa_core *c, pa_card_new_data *new
     pa_assert(c);
     pa_assert(new_data);
 
-    if (source_output_count(c) == 0)
+    if (source_output_count(c, userdata) == 0)
         return PA_HOOK_OK;
 
     /* Only consider bluetooth cards */
@@ -385,7 +403,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);
 
@@ -396,8 +413,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, "switch", &auto_switch) < 0) {
+    u->auto_switch = 1;
+    if (pa_modargs_get_value_u32(ma, "switch", &u->auto_switch) < 0) {
         pa_log("Failed to parse switch argument.");
         goto fail;
     }
@@ -424,7 +441,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);
 
-- 
1.7.9.5



More information about the pulseaudio-discuss mailing list