[pulseaudio-discuss] [PATCH 5/5] bluetooth: Refuse to use the HSP profile if there is some other HSP device active.

Luiz Augusto von Dentz luiz.dentz at gmail.com
Mon Mar 28 08:17:04 PDT 2011


Hi Tanu,

On Mon, Mar 28, 2011 at 3:35 PM, Tanu Kaskinen <tanu.kaskinen at digia.com> wrote:
> From: Tanu Kaskinen <ext-tanu.kaskinen at nokia.com>
>
> ---
>  src/modules/bluetooth/module-bluetooth-device.c |  126 +++++++++++++++++------
>  1 files changed, 93 insertions(+), 33 deletions(-)
>
> diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
> index 540d48c..1154651 100644
> --- a/src/modules/bluetooth/module-bluetooth-device.c
> +++ b/src/modules/bluetooth/module-bluetooth-device.c
> @@ -185,6 +185,8 @@ struct userdata {
>
>  #define MAX_PLAYBACK_CATCH_UP_USEC (100*PA_USEC_PER_MSEC)
>
> +#define CURRENT_HSP_DEVICE_KEY "current-hsp-device" /* Key to core->shared. */
> +
>  #define USE_SCO_OVER_PCM(u) (u->profile == PROFILE_HSP && (u->hsp.sco_sink && u->hsp.sco_source))
>
>  static int init_bt(struct userdata *u);
> @@ -1961,6 +1963,8 @@ static pa_hook_result_t source_state_changed_cb(pa_core *c, pa_source *s, struct
>
>  /* Run from main thread */
>  static int add_sink(struct userdata *u) {
> +    char *k;
> +
>     if (USE_SCO_OVER_PCM(u)) {
>         pa_proplist *p;
>
> @@ -2014,6 +2018,10 @@ static int add_sink(struct userdata *u) {
>     if (u->profile == PROFILE_HSP) {
>         u->sink->set_volume = sink_set_volume_cb;
>         u->sink->n_volume_steps = 16;
> +
> +        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
> +        pa_shared_set(u->core, k, u);
> +        pa_xfree(k);
>     }
>
>     return 0;
> @@ -2021,6 +2029,8 @@ static int add_sink(struct userdata *u) {
>
>  /* Run from main thread */
>  static int add_source(struct userdata *u) {
> +    char *k;
> +
>     if (USE_SCO_OVER_PCM(u)) {
>         u->source = u->hsp.sco_source;
>         pa_proplist_sets(u->source->proplist, "bluetooth.protocol", "hsp");
> @@ -2079,6 +2089,10 @@ static int add_source(struct userdata *u) {
>     if (u->profile == PROFILE_HSP) {
>         u->source->set_volume = source_set_volume_cb;
>         u->source->n_volume_steps = 16;
> +
> +        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
> +        pa_shared_set(u->core, k, u);
> +        pa_xfree(k);
>     }
>
>     return 0;
> @@ -2325,6 +2339,8 @@ static int init_profile(struct userdata *u) {
>
>  /* Run from main thread */
>  static void stop_thread(struct userdata *u) {
> +    char *k;
> +
>     pa_assert(u);
>
>     if (u->thread) {
> @@ -2349,11 +2365,23 @@ static void stop_thread(struct userdata *u) {
>     }
>
>     if (u->sink) {
> +        if (u->profile == PROFILE_HSP) {
> +            k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
> +            pa_shared_remove(u->core, k);
> +            pa_xfree(k);
> +        }
> +
>         pa_sink_unref(u->sink);
>         u->sink = NULL;
>     }
>
>     if (u->source) {
> +        if (u->profile == PROFILE_HSP) {
> +            k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
> +            pa_shared_remove(u->core, k);
> +            pa_xfree(k);
> +        }
> +
>         pa_source_unref(u->source);
>         u->source = NULL;
>     }
> @@ -2383,8 +2411,20 @@ static int start_thread(struct userdata *u) {
>
>     if (USE_SCO_OVER_PCM(u)) {
>         if (sco_over_pcm_state_update(u) < 0) {
> -            u->sink = NULL;
> -            u->source = NULL;
> +            char *k;
> +
> +            if (u->sink) {
> +                k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
> +                pa_shared_remove(u->core, k);
> +                pa_xfree(k);
> +                u->sink = NULL;
> +            }
> +            if (u->source) {
> +                k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
> +                pa_shared_remove(u->core, k);
> +                pa_xfree(k);
> +                u->source = NULL;
> +            }
>             return -1;
>         }
>
> @@ -2421,9 +2461,25 @@ static int start_thread(struct userdata *u) {
>     return 0;
>  }
>
> +static void save_sco_volume_callbacks(struct userdata *u) {
> +    pa_assert(u);
> +    pa_assert(USE_SCO_OVER_PCM(u));
> +
> +    u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume;
> +    u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume;
> +}
> +
> +static void restore_sco_volume_callbacks(struct userdata *u) {
> +    pa_assert(u);
> +    pa_assert(USE_SCO_OVER_PCM(u));
> +
> +    u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume;
> +    u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume;
> +}
> +
>  /* Run from main thread */
>  static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
> -    struct userdata *u;
> +    struct userdata *u, *other_hsp_device;
>     enum profile *d;
>     pa_queue *inputs = NULL, *outputs = NULL;
>     const pa_bluetooth_device *device;
> @@ -2439,6 +2495,9 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
>         return -PA_ERR_IO;
>     }
>
> +    if (u->profile == PROFILE_HSP)
> +        pa_shared_remove(u->core, CURRENT_HSP_DEVICE_KEY);
> +
>     /* The state signal is sent by bluez, so it is racy to check
>        strictly for CONNECTED, we should also accept STREAMING state
>        as being good enough. However, if the profile is used
> @@ -2448,6 +2507,10 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
>         pa_log_warn("HSP is not connected, refused to switch profile");
>         return -PA_ERR_IO;
>     }
> +    else if (*d == PROFILE_HSP && (other_hsp_device = pa_shared_get(u->core, CURRENT_HSP_DEVICE_KEY))) {
> +        pa_log_warn("Another HSP device (%s) is already active, refused to switch profile.", other_hsp_device->card->name);
> +        return -1;
> +    }
>     else if (device->audio_sink_state < PA_BT_AUDIO_STATE_CONNECTED && *d == PROFILE_A2DP) {
>         pa_log_warn("A2DP is not connected, refused to switch profile");
>         return -PA_ERR_IO;
> @@ -2474,9 +2537,18 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
>     stop_thread(u);
>     shutdown_bt(u);
>
> +    if (USE_SCO_OVER_PCM(u))
> +        restore_sco_volume_callbacks(u);
> +
>     u->profile = *d;
>     u->sample_spec = u->requested_sample_spec;
>
> +    if (USE_SCO_OVER_PCM(u))
> +        save_sco_volume_callbacks(u);
> +
> +    if (u->profile == PROFILE_HSP)
> +        pa_shared_set(u->core, CURRENT_HSP_DEVICE_KEY, u);
> +
>     init_bt(u);
>
>     if (u->profile != PROFILE_OFF)
> @@ -2511,6 +2583,7 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
>     const char *ff;
>     char *n;
>     const char *default_profile;
> +    struct userdata *other_hsp_device = NULL;
>
>     pa_assert(u);
>     pa_assert(device);
> @@ -2636,11 +2709,21 @@ static int add_card(struct userdata *u, const pa_bluetooth_device *device) {
>         pa_log_warn("Default profile not connected, selecting off profile");
>         u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
>         u->card->save_profile = FALSE;
> +    } else if (*d == PROFILE_HSP && (other_hsp_device = pa_shared_get(u->core, CURRENT_HSP_DEVICE_KEY))) {
> +        pa_log_warn("Another HSP device (%s) is already active, selecting off profile.", other_hsp_device->card->name);
> +        u->card->active_profile = pa_hashmap_get(u->card->profiles, "off");
> +        u->card->save_profile = FALSE;
>     }
>
>     d = PA_CARD_PROFILE_DATA(u->card->active_profile);
>     u->profile = *d;
>
> +    if (USE_SCO_OVER_PCM(u))
> +        save_sco_volume_callbacks(u);
> +
> +    if (u->profile == PROFILE_HSP)
> +        pa_shared_set(u->core, CURRENT_HSP_DEVICE_KEY, u);
> +
>     return 0;
>  }
>
> @@ -2704,7 +2787,7 @@ int pa__init(pa_module* m) {
>     struct userdata *u;
>     const char *address, *path;
>     DBusError err;
> -    char *mike, *speaker, *transport, *k;
> +    char *mike, *speaker, *transport;
>     const pa_bluetooth_device *device;
>
>     pa_assert(m);
> @@ -2805,20 +2888,6 @@ int pa__init(pa_module* m) {
>     /* Connect to the BT service */
>     init_bt(u);
>
> -    if (u->hsp.sco_sink) {
> -        u->hsp.sco_sink_set_volume = u->hsp.sco_sink->set_volume;
> -        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
> -        pa_shared_set(u->core, k, u);
> -        pa_xfree(k);
> -    }
> -
> -    if (u->hsp.sco_source) {
> -        u->hsp.sco_source_set_volume = u->hsp.sco_source->set_volume;
> -        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
> -        pa_shared_set(u->core, k, u);
> -        pa_xfree(k);
> -    }
> -
>     if (u->profile != PROFILE_OFF)
>         if (init_profile(u) < 0)
>             goto fail;
> @@ -2851,7 +2920,6 @@ int pa__get_n_used(pa_module *m) {
>
>  void pa__done(pa_module *m) {
>     struct userdata *u;
> -    char *k;
>
>     pa_assert(m);
>
> @@ -2866,6 +2934,12 @@ void pa__done(pa_module *m) {
>
>     stop_thread(u);
>
> +    if (USE_SCO_OVER_PCM(u))
> +        restore_sco_volume_callbacks(u);
> +
> +    if (u->profile == PROFILE_HSP)
> +        pa_shared_remove(u->core, CURRENT_HSP_DEVICE_KEY);
> +
>     if (u->connection) {
>
>         if (u->path) {
> @@ -2893,20 +2967,6 @@ void pa__done(pa_module *m) {
>
>     shutdown_bt(u);
>
> -    if (u->hsp.sco_sink) {
> -        u->hsp.sco_sink->set_volume = u->hsp.sco_sink_set_volume;
> -        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_sink);
> -        pa_shared_remove(u->core, k);
> -        pa_xfree(k);
> -    }
> -
> -    if (u->hsp.sco_source) {
> -        u->hsp.sco_source->set_volume = u->hsp.sco_source_set_volume;
> -        k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->hsp.sco_source);
> -        pa_shared_remove(u->core, k);
> -        pa_xfree(k);
> -    }
> -
>     if (u->a2dp.buffer)
>         pa_xfree(u->a2dp.buffer);
>
> --


There is a similar policy in BlueZ already for this and it is
configurable via /etc/bluetooth/audio.conf, so I don't think
hardcoding this on PA would do any better.


-- 
Luiz Augusto von Dentz
Computer Engineer



More information about the pulseaudio-discuss mailing list