send_and_add_to_pending(y, NULL, m, list_adapters_reply);
}
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i)
+{
+ const char *key;
+ DBusMessageIter variant_i;
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
+ pa_log("Property name not a string.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(i, &key);
+
+ if (!dbus_message_iter_next(i)) {
+ pa_log("Property value missing");
+ return -1;
+ }
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
+ pa_log("Property value not a variant.");
+ return -1;
+ }
+
+ dbus_message_iter_recurse(i, &variant_i);
+
+ switch (dbus_message_iter_get_arg_type(&variant_i)) {
+
+ case DBUS_TYPE_BOOLEAN: {
+
+ pa_bool_t *value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "NREC"))
+ t->nrec = value;
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) {
DBusError err;
pa_bluetooth_discovery *y;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
+ pa_bluetooth_device *d;
+ pa_bluetooth_transport *t;
+ void *state = NULL;
+ DBusMessageIter arg_i;
+
+ while ((d = pa_hashmap_iterate(y->devices, &state, NULL)))
+ if ((t = pa_hashmap_get(d->transports, dbus_message_get_path(m))))
+ break;
+
+ if (!t)
+ goto fail;
+
+ if (!dbus_message_iter_init(m, &arg_i)) {
+ pa_log("Failed to parse PropertyChanged: %s", err.message);
+ goto fail;
+ }
+
+ if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+ goto fail;
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
fail:
const char *path, *dev_path = NULL, *uuid = NULL;
uint8_t *config = NULL;
int size = 0;
+ pa_bool_t nrec;
enum profile p;
DBusMessageIter args, props;
DBusMessage *r;
if (var != DBUS_TYPE_OBJECT_PATH)
goto fail;
dbus_message_iter_get_basic(&value, &dev_path);
+ } else if (strcasecmp(key, "NREC") == 0) {
+ if (var != DBUS_TYPE_BOOLEAN)
+ goto fail;
+ dbus_message_iter_get_basic(&value, &nrec);
} else if (strcasecmp(key, "Configuration") == 0) {
DBusMessageIter array;
if (var != DBUS_TYPE_ARRAY)
p = PROFILE_A2DP_SOURCE;
t = transport_new(y, path, p, config, size);
+ if (nrec)
+ t->nrec = nrec;
pa_hashmap_put(d->transports, t->path, t);
pa_log_debug("Transport %s profile %d available", t->path, t->profile);
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
+ "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
NULL) < 0) {
pa_log("Failed to add D-Bus matches: %s", err.message);
goto fail;
"type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.AudioSource',member='PropertyChanged'",
"type='signal',sender='org.bluez',interface='org.bluez.HandsfreeGateway',member='PropertyChanged'",
+ "type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'",
NULL);
if (y->filter_added)
uint8_t codec;
uint8_t *config;
int config_size;
+ pa_bool_t nrec;
};
/* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */
int pa_bluetooth_transport_acquire(const pa_bluetooth_transport *t, const char *accesstype, size_t *imtu, size_t *omtu);
void pa_bluetooth_transport_release(const pa_bluetooth_transport *t, const char *accesstype);
+int pa_bluetooth_transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i);
pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *d);
dbus_message_get_path(m),
dbus_message_get_member(m));
- if (!dbus_message_has_path(m, u->path))
+ if (!dbus_message_has_path(m, u->path) && !dbus_message_has_path(m, u->transport))
goto fail;
if (dbus_message_is_signal(m, "org.bluez.Headset", "SpeakerGainChanged") ||
pa_source_volume_changed(u->source, &v);
}
}
+ } else if (dbus_message_is_signal(m, "org.bluez.MediaTransport", "PropertyChanged")) {
+ DBusMessageIter arg_i;
+ pa_bluetooth_transport *t;
+ pa_bool_t nrec;
+
+ t = (pa_bluetooth_transport *) pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+ pa_assert(t);
+
+ if (!dbus_message_iter_init(m, &arg_i)) {
+ pa_log("Failed to parse PropertyChanged: %s", err.message);
+ goto fail;
+ }
+
+ nrec = t->nrec;
+
+ if (pa_bluetooth_transport_parse_property(t, &arg_i) < 0)
+ goto fail;
+
+ if (nrec != t->nrec) {
+ pa_log_debug("dbus: property 'NREC' changed to value '%s'", t->nrec ? "True" : "False");
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+ }
}
fail:
pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP_SOURCE ? "a2dp_source" : "hsp");
if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW))
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
+
data.card = u->card;
data.name = get_name("source", u->modargs, u->address, &b);
data.namereg_fail = b;
pa_bytes_to_usec(u->block_size, &u->sample_spec));
}
- if (u->profile == PROFILE_HSP || u->profile == PROFILE_HFGW)
- pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+ if ((u->profile == PROFILE_HSP) || (u->profile == PROFILE_HFGW)) {
+ if (u->transport) {
+ const pa_bluetooth_transport *t;
+ t = pa_bluetooth_discovery_get_transport(u->discovery, u->transport);
+ pa_assert(t);
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", t->nrec ? "1" : "0");
+ } else
+ pa_proplist_sets(u->source->proplist, "bluetooth.nrec", (u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC) ? "1" : "0");
+ }
if (u->profile == PROFILE_HSP) {
u->source->set_volume = source_set_volume_cb;
return bt_transport_config_a2dp(u);
}
-static int parse_transport_property(struct userdata *u, DBusMessageIter *i) {
- const char *key;
- DBusMessageIter variant_i;
-
- pa_assert(u);
- pa_assert(i);
-
- if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
- pa_log("Property name not a string.");
- return -1;
- }
-
- dbus_message_iter_get_basic(i, &key);
-
- if (!dbus_message_iter_next(i)) {
- pa_log("Property value missing");
- return -1;
- }
-
- if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
- pa_log("Property value not a variant.");
- return -1;
- }
-
- dbus_message_iter_recurse(i, &variant_i);
-
- switch (dbus_message_iter_get_arg_type(&variant_i)) {
-
- case DBUS_TYPE_UINT16: {
-
- uint16_t value;
- dbus_message_iter_get_basic(&variant_i, &value);
-
- if (pa_streq(key, "OMTU"))
- u->link_mtu = value;
-
- break;
- }
-
- }
-
- return 0;
-}
-
/* Run from main thread */
static int bt_transport_open(struct userdata *u) {
if (bt_transport_acquire(u, FALSE) < 0)
struct userdata *u;
const char *address, *path;
DBusError err;
- char *mike, *speaker;
+ char *mike, *speaker, *transport;
const pa_bluetooth_device *device;
pa_assert(m);
speaker = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='SpeakerGainChanged',path='%s'", u->path);
mike = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.Headset',member='MicrophoneGainChanged',path='%s'", u->path);
+ transport = pa_sprintf_malloc("type='signal',sender='org.bluez',interface='org.bluez.MediaTransport',member='PropertyChanged'");
if (pa_dbus_add_matches(
pa_dbus_connection_get(u->connection), &err,
speaker,
mike,
+ transport,
NULL) < 0) {
pa_xfree(speaker);
pa_xfree(mike);
+ pa_xfree(transport);
pa_log("Failed to add D-Bus matches: %s", err.message);
goto fail;
pa_xfree(speaker);
pa_xfree(mike);
+ pa_xfree(transport);
/* Connect to the BT service */
init_bt(u);