[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