diff options
author | Arun Raghavan <arun.raghavan@collabora.co.uk> | 2012-06-08 11:10:46 +0530 |
---|---|---|
committer | Arun Raghavan <arun.raghavan@collabora.co.uk> | 2012-06-08 11:10:46 +0530 |
commit | 612f3385701194a72965bbe0b3e7cd49e35db936 (patch) | |
tree | 46d653b092971e4f13aeaa81b70d0214fcc21a55 | |
parent | 88461fc5ae6d6874408e7e4658c5e522dd6c66db (diff) |
profile-switcher: Bail out if there is more than one Bluetooth devicebluetooth
This enables profile switching only if there is one Bluetooth device
connected at a given time. Policy-wise, deciding the right thing to do
with multiple cards will either require user intervention or some other
mechanism of determining what purpose each device is intended for.
-rw-r--r-- | src/modules/module-profile-switcher.c | 67 |
1 files changed, 60 insertions, 7 deletions
diff --git a/src/modules/module-profile-switcher.c b/src/modules/module-profile-switcher.c index d79bd306b..15ea0494e 100644 --- a/src/modules/module-profile-switcher.c +++ b/src/modules/module-profile-switcher.c @@ -48,12 +48,15 @@ static const char* const valid_modargs[] = { }; struct userdata { + int n_bt_cards; + pa_hook_slot *sink_input_put_slot, *source_output_put_slot, *sink_input_unlink_post_slot, *source_output_unlink_post_slot, - *card_new_slot; + *card_new_slot, + *card_unlink_slot; }; #define GET_ROLE(i) \ @@ -85,13 +88,21 @@ static pa_bool_t card_has_active_source(pa_card *card) { return FALSE; } -static void process_link(pa_core *c, pa_card *this_card, const char *role) { +static void process_link(struct userdata *u, pa_core *c, pa_card *this_card, const char *role) { pa_card *card; uint32_t idx1, idx2, idx3; + if (u->n_bt_cards == 0) + return; + /* Incoming stream -- try to switch connected Bluetooth headsets to HSP/HFP * if this is a "phone" stream, otherwise to A2DP. */ + if (u->n_bt_cards > 1) { + pa_log("More than one Bluetooth card found. Not modifying profile."); + return; + } + PA_IDXSET_FOREACH(card, c->cards, idx1) { pa_sink *sink; pa_bool_t use_a2dp = TRUE; @@ -126,28 +137,40 @@ static void process_link(pa_core *c, pa_card *this_card, const char *role) { } static pa_hook_result_t sink_input_put_cb(pa_core *c, pa_sink_input *i, void *userdata) { + struct userdata *u = (struct userdata *) userdata; + pa_assert(c); pa_assert(i); - process_link(c, i->sink->card, GET_ROLE(i)); + process_link(u, c, i->sink->card, GET_ROLE(i)); return PA_HOOK_OK; } static pa_hook_result_t source_output_put_cb(pa_core *c, pa_source_output *o, void *userdata) { + struct userdata *u = (struct userdata *) userdata; + pa_assert(c); pa_assert(o); - process_link(c, o->source->card, GET_ROLE(o)); + process_link(u, c, o->source->card, GET_ROLE(o)); return PA_HOOK_OK; } -static void process_unlink(pa_core *c, pa_sink *sink) { +static void process_unlink(struct userdata *u, pa_core *c, pa_sink *sink) { pa_sink_input *input; pa_bool_t use_a2dp = TRUE; uint32_t idx; + if (u->n_bt_cards == 0) + return; + + if (u->n_bt_cards > 1) { + pa_log("More than one Bluetooth card found. Not modifying profile."); + return; + } + PA_IDXSET_FOREACH(input, sink->inputs, idx) { if (pa_streq(GET_ROLE(input), "phone")) { /* There's a phone stream attached, don't switch */ @@ -167,6 +190,8 @@ static void process_unlink(pa_core *c, pa_sink *sink) { } static pa_hook_result_t sink_input_unlink_post_cb(pa_core *c, pa_sink_input *i, void *userdata) { + struct userdata *u = (struct userdata *) userdata; + pa_assert(c); pa_assert(i); @@ -177,7 +202,7 @@ static pa_hook_result_t sink_input_unlink_post_cb(pa_core *c, pa_sink_input *i, if (!card_is_bluetooth(i->sink->card)) return PA_HOOK_OK; - process_unlink(c, i->sink); + process_unlink(u, c, i->sink); return PA_HOOK_OK; } @@ -186,6 +211,7 @@ static pa_hook_result_t sink_input_unlink_post_cb(pa_core *c, pa_sink_input *i, * still a source-output connected to the device (since the latter would block * a switch to A2DP in sink_input_unlink_post_cb()) */ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_output *o, void *userdata) { + struct userdata *u = (struct userdata *) userdata; pa_sink *sink; uint32_t idx; @@ -199,7 +225,7 @@ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_outpu return PA_HOOK_OK; PA_IDXSET_FOREACH(sink, o->source->card->sinks, idx) - process_unlink(c, sink); + process_unlink(u, c, sink); return PA_HOOK_OK; } @@ -207,6 +233,7 @@ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_outpu /* Set the initial profile for the card based on currently available * sink-inputs and source-outputs. */ static pa_hook_result_t card_new_cb(pa_core *c, pa_card_new_data *data, void *userdata) { + struct userdata *u = (struct userdata *) userdata; const char *device_api; pa_sink_input *input; pa_source_output *output; @@ -217,6 +244,13 @@ static pa_hook_result_t card_new_cb(pa_core *c, pa_card_new_data *data, void *us if (!device_api || !pa_streq(device_api, "bluez")) return PA_HOOK_OK; + u->n_bt_cards++; + + if (u->n_bt_cards > 1) { + pa_log("More than one Bluetooth card found. Not modifying profile."); + return PA_HOOK_OK; + } + PA_IDXSET_FOREACH(input, c->sink_inputs, idx) { if (pa_streq(GET_ROLE(input), "phone")) { use_a2dp = FALSE; @@ -249,9 +283,20 @@ done: return PA_HOOK_OK; } +static pa_hook_result_t card_unlink_cb(pa_core *c, pa_card *card, void *userdata) { + struct userdata *u = (struct userdata *) userdata; + + if (card_is_bluetooth(card)) + u->n_bt_cards--; + + return PA_HOOK_OK; +} + int pa__init(pa_module*m) { pa_modargs *ma; + pa_card *card; struct userdata *u; + uint32_t idx; pa_assert(m); @@ -262,12 +307,18 @@ int pa__init(pa_module*m) { m->userdata = u = pa_xnew(struct userdata, 1); + u->n_bt_cards = 0; + PA_IDXSET_FOREACH(card, m->core->cards, idx) + if (card_is_bluetooth(card)) + u->n_bt_cards++; + /* Set these all to EARLY so we can trigger profile changes asap */ u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_put_cb, u); u->source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_put_cb, u); u->sink_input_unlink_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], PA_HOOK_EARLY, (pa_hook_cb_t) sink_input_unlink_post_cb, u); u->source_output_unlink_post_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_post_cb, u); u->card_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_CARD_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) card_new_cb, u); + u->card_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_CARD_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) card_unlink_cb, u); pa_modargs_free(ma); return 0; @@ -291,6 +342,8 @@ void pa__done(pa_module*m) { pa_hook_slot_free(u->source_output_unlink_post_slot); if (u->card_new_slot) pa_hook_slot_free(u->card_new_slot); + if (u->card_unlink_slot) + pa_hook_slot_free(u->card_unlink_slot); pa_xfree(u); } |