[pulseaudio-discuss] [RFC 1/2] bluetooth: Add MediaTransport volume management
Frédéric Danis
frederic.danis at linux.intel.com
Mon Nov 12 07:19:09 PST 2012
With BlueZ 5 volume updates for HFP will go through transport interface.
Note that this is backward compatible.
---
src/modules/bluetooth/bluetooth-util.c | 62 +++++++++++++++----
src/modules/bluetooth/bluetooth-util.h | 4 ++
src/modules/bluetooth/module-bluetooth-device.c | 75 +++++++++++++++++++++++
3 files changed, 130 insertions(+), 11 deletions(-)
diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c
index 272b6ce..c0d5287 100644
--- a/src/modules/bluetooth/bluetooth-util.c
+++ b/src/modules/bluetooth/bluetooth-util.c
@@ -754,21 +754,49 @@ int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessage
dbus_message_iter_recurse(i, &variant_i);
- switch (dbus_message_iter_get_arg_type(&variant_i)) {
+ if (pa_streq(key, "NREC")) {
+ dbus_bool_t value;
- case DBUS_TYPE_BOOLEAN: {
+ if (dbus_message_iter_get_arg_type(&variant_i) != DBUS_TYPE_BOOLEAN) {
+ pa_log("Property value not a boolean.");
+ return -1;
+ }
- dbus_bool_t value;
- dbus_message_iter_get_basic(&variant_i, &value);
+ dbus_message_iter_get_basic(&variant_i, &value);
- if (pa_streq(key, "NREC") && t->nrec != value) {
- t->nrec = value;
- pa_log_debug("Transport %s: Property 'NREC' changed to %s.", t->path, t->nrec ? "True" : "False");
- pa_hook_fire(&t->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_NREC_CHANGED], NULL);
- }
+ if (t->nrec != value) {
+ t->nrec = value;
+ pa_log_debug("Transport %s: Property 'NREC' changed to %s.", t->path, t->nrec ? "True" : "False");
+ pa_hook_fire(&t->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_NREC_CHANGED], NULL);
+ }
+ } else if(pa_streq(key,"OutputGain")) {
+ uint16_t value;
- break;
- }
+ if (dbus_message_iter_get_arg_type(&variant_i) != DBUS_TYPE_UINT16) {
+ pa_log("Property value not an uint16.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (t->output_gain != value) {
+ t->output_gain = value;
+ pa_hook_fire(&t->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_OUTPUT_GAIN_CHANGED], NULL);
+ }
+ } else if(pa_streq(key,"InputGain")) {
+ uint16_t value;
+
+ if (dbus_message_iter_get_arg_type(&variant_i) != DBUS_TYPE_UINT16) {
+ pa_log("Property value not an uint16.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (t->input_gain != value) {
+ t->input_gain = value;
+ pa_hook_fire(&t->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_INPUT_GAIN_CHANGED], NULL);
+ }
}
return 0;
@@ -1104,6 +1132,8 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
uint8_t *config = NULL;
int size = 0;
pa_bool_t nrec = FALSE;
+ uint16_t output_gain = 15;
+ uint16_t input_gain = 15;
enum profile p;
DBusMessageIter args, props;
DBusMessage *r;
@@ -1151,6 +1181,14 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
goto fail;
dbus_message_iter_recurse(&value, &array);
dbus_message_iter_get_fixed_array(&array, &config, &size);
+ } else if (strcasecmp(key, "OutputGain") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ goto fail;
+ dbus_message_iter_get_basic(&value, &output_gain);
+ } else if (strcasecmp(key, "InputGain") == 0) {
+ if (var != DBUS_TYPE_UINT16)
+ goto fail;
+ dbus_message_iter_get_basic(&value, &input_gain);
}
dbus_message_iter_next(&props);
@@ -1172,6 +1210,8 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage
t = transport_new(y, path, p, config, size);
if (nrec)
t->nrec = nrec;
+ t->output_gain = output_gain;
+ t->input_gain = input_gain;
pa_hashmap_put(d->transports, t->path, t);
pa_log_debug("Transport %s profile %d available", t->path, t->profile);
diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h
index 8a3f2ad..5fba105 100644
--- a/src/modules/bluetooth/bluetooth-util.h
+++ b/src/modules/bluetooth/bluetooth-util.h
@@ -67,6 +67,8 @@ enum profile {
typedef enum pa_bluetooth_transport_hook {
PA_BLUETOOTH_TRANSPORT_HOOK_NREC_CHANGED, /* Call data: NULL. */
PA_BLUETOOTH_TRANSPORT_HOOK_REMOVED, /* Call data: NULL. */
+ PA_BLUETOOTH_TRANSPORT_HOOK_OUTPUT_GAIN_CHANGED, /* Call data: NULL. */
+ PA_BLUETOOTH_TRANSPORT_HOOK_INPUT_GAIN_CHANGED, /* Call data: NULL. */
PA_BLUETOOTH_TRANSPORT_HOOK_MAX
} pa_bluetooth_transport_hook_t;
@@ -78,6 +80,8 @@ struct pa_bluetooth_transport {
uint8_t *config;
int config_size;
pa_bool_t nrec;
+ uint16_t output_gain;
+ uint16_t input_gain;
pa_hook hooks[PA_BLUETOOTH_TRANSPORT_HOOK_MAX];
};
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
index 8c2efa4..656852d 100644
--- a/src/modules/bluetooth/module-bluetooth-device.c
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -124,6 +124,8 @@ struct hsp_info {
pa_hook_slot *sink_state_changed_slot;
pa_hook_slot *source_state_changed_slot;
pa_hook_slot *nrec_changed_slot;
+ pa_hook_slot *output_gain_slot;
+ pa_hook_slot *input_gain_slot;
};
struct bluetooth_msg {
@@ -1423,6 +1425,19 @@ fail:
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+static void send_property_update(struct userdata *u, const char *name, int type, void *data)
+{
+ DBusMessage *m;
+ DBusMessageIter iter;
+
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->transport->path, "org.bluez.MediaTransport", "SetProperty"));
+ dbus_message_iter_init_append(m, &iter);
+ pa_assert_se(dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name));
+ pa_dbus_append_basic_variant(&iter, DBUS_TYPE_UINT16, data);
+ pa_assert_se(dbus_connection_send(pa_dbus_connection_get(u->connection), m, NULL));
+ dbus_message_unref(m);
+}
+
/* Run from main thread */
static void sink_set_volume_cb(pa_sink *s) {
DBusMessage *m;
@@ -1430,6 +1445,7 @@ static void sink_set_volume_cb(pa_sink *s) {
pa_volume_t volume;
struct userdata *u;
char *k;
+ const char *name = "OutputGain";
pa_assert(s);
pa_assert(s->core);
@@ -1459,6 +1475,8 @@ static void sink_set_volume_cb(pa_sink *s) {
pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID));
pa_assert_se(dbus_connection_send(pa_dbus_connection_get(u->connection), m, NULL));
dbus_message_unref(m);
+
+ send_property_update(u, name, DBUS_TYPE_UINT16, &gain);
}
/* Run from main thread */
@@ -1468,6 +1486,7 @@ static void source_set_volume_cb(pa_source *s) {
pa_volume_t volume;
struct userdata *u;
char *k;
+ const char *name = "InputGain";
pa_assert(s);
pa_assert(s->core);
@@ -1497,6 +1516,8 @@ static void source_set_volume_cb(pa_source *s) {
pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID));
pa_assert_se(dbus_connection_send(pa_dbus_connection_get(u->connection), m, NULL));
dbus_message_unref(m);
+
+ send_property_update(u, name, DBUS_TYPE_UINT16, &gain);
}
/* Run from main thread */
@@ -1599,6 +1620,44 @@ static pa_hook_result_t nrec_changed_cb(pa_bluetooth_transport *t, void *call_da
return PA_HOOK_OK;
}
+static pa_hook_result_t output_gain_changed_cb(pa_bluetooth_transport *t, void *call_data, struct userdata *u) {
+ pa_volume_t volume;
+ pa_cvolume v;
+
+ pa_assert(t);
+ pa_assert(u);
+
+ volume = (pa_volume_t) (t->output_gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
+
+ /* increment volume by one to correct rounding errors */
+ if (volume < PA_VOLUME_NORM)
+ volume++;
+
+ pa_cvolume_set(&v, u->sample_spec.channels, volume);
+ pa_sink_volume_changed(u->sink, &v);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t input_gain_changed_cb(pa_bluetooth_transport *t, void *call_data, struct userdata *u) {
+ pa_volume_t volume;
+ pa_cvolume v;
+
+ pa_assert(t);
+ pa_assert(u);
+
+ volume = (pa_volume_t) (t->input_gain * PA_VOLUME_NORM / HSP_MAX_GAIN);
+
+ /* increment volume by one to correct rounding errors */
+ if (volume < PA_VOLUME_NORM)
+ volume++;
+
+ pa_cvolume_set(&v, u->sample_spec.channels, volume);
+ pa_source_volume_changed(u->source, &v);
+
+ return PA_HOOK_OK;
+}
+
static void connect_ports(struct userdata *u, void *sink_or_source_new_data, pa_direction_t direction) {
union {
pa_sink_new_data *sink_new_data;
@@ -1748,6 +1807,9 @@ static int add_sink(struct userdata *u) {
k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->sink);
pa_shared_set(u->core, k, u);
pa_xfree(k);
+
+ if (u->transport && !u->hsp.output_gain_slot)
+ u->hsp.output_gain_slot = pa_hook_connect(&u->transport->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_OUTPUT_GAIN_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) output_gain_changed_cb, u);
}
return 0;
@@ -1832,6 +1894,9 @@ static int add_source(struct userdata *u) {
k = pa_sprintf_malloc("bluetooth-device@%p", (void*) u->source);
pa_shared_set(u->core, k, u);
pa_xfree(k);
+
+ if (u->transport && !u->hsp.input_gain_slot)
+ u->hsp.input_gain_slot = pa_hook_connect(&u->transport->hooks[PA_BLUETOOTH_TRANSPORT_HOOK_INPUT_GAIN_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) input_gain_changed_cb, u);
}
return 0;
@@ -2057,6 +2122,16 @@ static void stop_thread(struct userdata *u) {
u->hsp.nrec_changed_slot = NULL;
}
+ if (u->hsp.output_gain_slot) {
+ pa_hook_slot_free(u->hsp.output_gain_slot);
+ u->hsp.output_gain_slot = NULL;
+ }
+
+ if (u->hsp.input_gain_slot) {
+ pa_hook_slot_free(u->hsp.input_gain_slot);
+ u->hsp.input_gain_slot = NULL;
+ }
+
if (u->transport_removed_slot) {
pa_hook_slot_free(u->transport_removed_slot);
u->transport_removed_slot = NULL;
--
1.7.9.5
More information about the pulseaudio-discuss
mailing list