summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArun Raghavan <arun.raghavan@collabora.co.uk>2012-06-08 11:10:46 +0530
committerArun Raghavan <arun.raghavan@collabora.co.uk>2012-06-08 11:10:46 +0530
commit612f3385701194a72965bbe0b3e7cd49e35db936 (patch)
tree46d653b092971e4f13aeaa81b70d0214fcc21a55
parent88461fc5ae6d6874408e7e4658c5e522dd6c66db (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.c67
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);
}