From: Mikel Astiz <mikel.astiz@xxxxxxxxxxxx> bluetooth-util internally implements a backend for BlueZ Media API but it's nevertheless convenient to have the backend-specific data split into separated data structures. --- src/modules/bluetooth/bluetooth-util.c | 108 +++++++++++++++++++++++---------- src/modules/bluetooth/bluetooth-util.h | 4 +- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 34db2ac..be82331 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -97,8 +97,14 @@ struct profile_data { }; typedef struct bluez_backend_private { + pa_hashmap *transports; } bluez_backend_private; +typedef struct bluez_transport_private { + char *owner; + char *path; +} bluez_transport_private; + struct pa_bluetooth_discovery { PA_REFCNT_DECLARE; @@ -108,7 +114,6 @@ struct pa_bluetooth_discovery { pa_bluez_version_t version; bool adapters_listed; pa_hashmap *devices; - pa_hashmap *transports; struct profile_data profiles[PA_BLUETOOTH_PROFILE_COUNT]; pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; bool filter_added; @@ -252,15 +257,32 @@ static pa_bluetooth_device* device_new(pa_bluetooth_discovery *discovery, const return d; } +static void bluez_transport_free(bluez_transport_private *p) { + pa_assert(p); + + pa_xfree(p->owner); + pa_xfree(p->path); + pa_xfree(p); +} + static void transport_free(pa_bluetooth_transport *t) { pa_assert(t); - pa_xfree(t->owner); - pa_xfree(t->path); + bluez_transport_free(t->backend_private); + pa_xfree(t->config); pa_xfree(t); } +static void bluez_backend_transport_removed(bluez_backend_private *bbp, pa_bluetooth_transport *t) { + bluez_transport_private *p; + + pa_assert(t); + pa_assert_se(p = t->backend_private); + + pa_hashmap_remove(bbp->transports, p->path); +} + static void device_free(pa_bluetooth_device *d) { pa_bluetooth_uuid *u; pa_bluetooth_transport *t; @@ -273,7 +295,7 @@ static void device_free(pa_bluetooth_device *d) { continue; d->transports[i] = NULL; - pa_hashmap_remove(d->discovery->transports, t->path); + bluez_backend_transport_removed(&d->discovery->backend_private, t); t->state = PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED; pa_hook_fire(&d->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t); transport_free(t); @@ -1070,6 +1092,10 @@ static void init_bluez(pa_bluetooth_discovery *y) { static int transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter *i) { const char *key; DBusMessageIter variant_i; + bluez_transport_private *p; + + pa_assert(t); + pa_assert_se(p = t->backend_private); key = check_variant_property(i); if (key == NULL) @@ -1099,11 +1125,11 @@ static int transport_parse_property(pa_bluetooth_transport *t, DBusMessageIter * bool old_any_connected = pa_bluetooth_device_any_audio_connected(t->device); if (transport_state_from_string(value, &t->state) < 0) { - pa_log("Transport %s has an invalid state: '%s'", t->path, value); + pa_log("Transport %s has an invalid state: '%s'", p->path, value); return -1; } - pa_log_debug("dbus: transport %s set to state '%s'", t->path, value); + pa_log_debug("dbus: transport %s set to state '%s'", p->path, value); pa_hook_fire(&t->device->discovery->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t); if (old_any_connected != pa_bluetooth_device_any_audio_connected(t->device)) @@ -1138,12 +1164,15 @@ static int parse_transport_properties(pa_bluetooth_transport *t, DBusMessageIter static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *userdata) { DBusError err; pa_bluetooth_discovery *y; + bluez_backend_private *bbp; pa_assert(bus); pa_assert(m); pa_assert_se(y = userdata); + bbp = &y->backend_private; + dbus_error_init(&err); pa_log_debug("dbus: interface=%s, path=%s, member=%s\n", @@ -1262,7 +1291,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us pa_bluetooth_transport *t; DBusMessageIter arg_i; - if (!(t = pa_hashmap_get(y->transports, dbus_message_get_path(m)))) + if (!(t = pa_hashmap_get(bbp->transports, dbus_message_get_path(m)))) goto fail; if (!dbus_message_iter_init(m, &arg_i)) { @@ -1359,7 +1388,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us } else if (pa_streq(interface, "org.bluez.MediaTransport1")) { pa_bluetooth_transport *t; - if (!(t = pa_hashmap_get(y->transports, dbus_message_get_path(m)))) + if (!(t = pa_hashmap_get(bbp->transports, dbus_message_get_path(m)))) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; parse_transport_properties(t, &arg_i); @@ -1443,10 +1472,12 @@ int pa_bluetooth_transport_acquire(pa_bluetooth_transport *t, bool optional, siz int ret; uint16_t i, o; const char *method; + bluez_transport_private *p; pa_assert(t); pa_assert(t->device); pa_assert(t->device->discovery); + pa_assert_se(p = t->backend_private); dbus_error_init(&err); @@ -1461,28 +1492,28 @@ int pa_bluetooth_transport_acquire(pa_bluetooth_transport *t, bool optional, siz suspended in the meantime, so we can't really guarantee that the stream will not be requested with the API in BlueZ 4.x */ if (t->state < PA_BLUETOOTH_TRANSPORT_STATE_PLAYING) { - pa_log_info("Failed optional acquire of unavailable transport %s", t->path); + pa_log_info("Failed optional acquire of unavailable transport %s", p->path); return -1; } } method = "Acquire"; - pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", method)); + pa_assert_se(m = dbus_message_new_method_call(p->owner, p->path, "org.bluez.MediaTransport", method)); pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID)); } else { pa_assert(t->device->discovery->version == BLUEZ_VERSION_5); method = optional ? "TryAcquire" : "Acquire"; - pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport1", method)); + pa_assert_se(m = dbus_message_new_method_call(p->owner, p->path, "org.bluez.MediaTransport1", method)); } r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err); if (!r) { if (optional && pa_streq(err.name, "org.bluez.Error.NotAvailable")) - pa_log_info("Failed optional acquire of unavailable transport %s", t->path); + pa_log_info("Failed optional acquire of unavailable transport %s", p->path); else - pa_log("Transport %s() failed for transport %s (%s)", method, t->path, err.message); + pa_log("Transport %s() failed for transport %s (%s)", method, p->path, err.message); dbus_error_free(&err); return -1; @@ -1510,36 +1541,38 @@ fail: void pa_bluetooth_transport_release(pa_bluetooth_transport *t) { DBusMessage *m; DBusError err; + bluez_transport_private *p; pa_assert(t); pa_assert(t->device); pa_assert(t->device->discovery); + pa_assert_se(p = t->backend_private); dbus_error_init(&err); if (t->device->discovery->version == BLUEZ_VERSION_4) { const char *accesstype = "rw"; - pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport", "Release")); + pa_assert_se(m = dbus_message_new_method_call(p->owner, p->path, "org.bluez.MediaTransport", "Release")); pa_assert_se(dbus_message_append_args(m, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID)); } else { pa_assert(t->device->discovery->version == BLUEZ_VERSION_5); if (t->state <= PA_BLUETOOTH_TRANSPORT_STATE_IDLE) { - pa_log_info("Transport %s auto-released by BlueZ or already released", t->path); + pa_log_info("Transport %s auto-released by BlueZ or already released", p->path); return; } - pa_assert_se(m = dbus_message_new_method_call(t->owner, t->path, "org.bluez.MediaTransport1", "Release")); + pa_assert_se(m = dbus_message_new_method_call(p->owner, p->path, "org.bluez.MediaTransport1", "Release")); } dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(t->device->discovery->connection), m, -1, &err); if (dbus_error_is_set(&err)) { - pa_log("Failed to release transport %s: %s", t->path, err.message); + pa_log("Failed to release transport %s: %s", p->path, err.message); dbus_error_free(&err); } else - pa_log_info("Transport %s released", t->path); + pa_log_info("Transport %s released", p->path); } static void set_property(pa_bluetooth_discovery *y, const char *bus, const char *path, const char *interface, @@ -1600,6 +1633,7 @@ static pa_bluetooth_transport *transport_new(pa_bluetooth_device *d, const char const uint8_t *config, int size) { pa_bluetooth_transport *t; pa_bluetooth_transport_new_data data; + bluez_transport_private *private; data.device = d; data.profile = p; @@ -1613,8 +1647,10 @@ static pa_bluetooth_transport *transport_new(pa_bluetooth_device *d, const char t = pa_bt_backend_notify_transport_added(&data); - t->owner = pa_xstrdup(owner); - t->path = pa_xstrdup(path); + private = pa_xnew0(bluez_transport_private, 1); + private->owner = pa_xstrdup(owner); + private->path = pa_xstrdup(path); + t->backend_private = private; return t; } @@ -1623,6 +1659,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage pa_bluetooth_discovery *y = userdata; pa_bluetooth_device *d; pa_bluetooth_transport *t; + bluez_backend_private *bbp; const char *sender, *path, *dev_path = NULL, *uuid = NULL; uint8_t *config = NULL; int size = 0; @@ -1632,6 +1669,8 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage DBusMessage *r; bool old_any_connected; + bbp = &y->backend_private; + if (!dbus_message_iter_init(m, &args) || !pa_streq(dbus_message_get_signature(m), "oa{sv}")) { pa_log("Invalid signature for method SetConfiguration"); goto fail2; @@ -1639,7 +1678,7 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage dbus_message_iter_get_basic(&args, &path); - if (pa_hashmap_get(y->transports, path)) { + if (pa_hashmap_get(bbp->transports, path)) { pa_log("Endpoint SetConfiguration: Transport %s is already configured.", path); goto fail2; } @@ -1720,9 +1759,9 @@ static DBusMessage *endpoint_set_configuration(DBusConnection *conn, DBusMessage t->nrec = nrec; d->transports[p] = t; - pa_assert_se(pa_hashmap_put(y->transports, t->path, t) >= 0); + pa_assert_se(pa_hashmap_put(bbp->transports, path, t) >= 0); - pa_log_debug("Transport %s profile %d available", t->path, t->profile); + pa_log_debug("Transport %s profile %d available", path, p); pa_assert_se(r = dbus_message_new_method_return(m)); pa_assert_se(dbus_connection_send(pa_dbus_connection_get(y->connection), r, NULL)); @@ -1744,10 +1783,15 @@ fail2: static DBusMessage *endpoint_clear_configuration(DBusConnection *c, DBusMessage *m, void *userdata) { pa_bluetooth_discovery *y = userdata; pa_bluetooth_transport *t; + bluez_backend_private *bbp; DBusMessage *r; DBusError e; const char *path; + pa_assert(y); + + bbp = &y->backend_private; + dbus_error_init(&e); if (!dbus_message_get_args(m, &e, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { @@ -1756,7 +1800,7 @@ static DBusMessage *endpoint_clear_configuration(DBusConnection *c, DBusMessage goto fail; } - if ((t = pa_hashmap_get(y->transports, path))) + if ((t = pa_hashmap_remove(bbp->transports, path))) pa_bt_backend_notify_transport_removed(t); pa_assert_se(r = dbus_message_new_method_return(m)); @@ -1986,6 +2030,8 @@ pa_bluetooth_backend bluez_backend = { static void bluez_backend_init(pa_bluetooth_discovery *y) { bluez_backend_private *bbp = &y->backend_private; + bbp->transports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); + pa_bt_backend_register(y, &bluez_backend, PROFILE_A2DP, bbp); pa_bt_backend_register(y, &bluez_backend, PROFILE_A2DP_SOURCE, bbp); @@ -1997,6 +2043,8 @@ static void bluez_backend_init(pa_bluetooth_discovery *y) { } static void bluez_backend_done(pa_bluetooth_discovery *y) { + bluez_backend_private *bbp = &y->backend_private; + pa_bt_backend_unregister(y, &bluez_backend, PROFILE_A2DP); pa_bt_backend_unregister(y, &bluez_backend, PROFILE_A2DP_SOURCE); @@ -2005,6 +2053,11 @@ static void bluez_backend_done(pa_bluetooth_discovery *y) { pa_bt_backend_unregister(y, &bluez_backend, PROFILE_HSP); pa_bt_backend_unregister(y, &bluez_backend, PROFILE_HFGW); + + if (bbp->transports) { + pa_assert(pa_hashmap_isempty(bbp->transports)); + pa_hashmap_free(bbp->transports, NULL); + } } pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { @@ -2027,7 +2080,6 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { PA_REFCNT_INIT(y); y->core = c; y->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - y->transports = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); PA_LLIST_HEAD_INIT(pa_dbus_pending, y->pending); for (i = 0; i < PA_BLUETOOTH_HOOK_MAX; i++) @@ -2120,11 +2172,6 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { pa_hashmap_free(y->devices, NULL); } - if (y->transports) { - pa_assert(pa_hashmap_isempty(y->transports)); - pa_hashmap_free(y->transports, NULL); - } - if (y->connection) { dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), HFP_AG_ENDPOINT); dbus_connection_unregister_object_path(pa_dbus_connection_get(y->connection), HFP_HS_ENDPOINT); @@ -2346,7 +2393,6 @@ void pa_bt_backend_notify_transport_removed(pa_bluetooth_transport *t) { pa_log_debug("Removing transport for device %s profile %s", d->path, pa_bt_profile_to_string(t->profile)); d->transports[t->profile] = NULL; - pa_hashmap_remove(y->transports, t->path); t->state = PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED; pa_hook_fire(&y->hooks[PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED], t); diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index 1a72ca6..a4d365e 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -91,8 +91,6 @@ typedef enum pa_bluetooth_transport_state { struct pa_bluetooth_transport { pa_bluetooth_device *device; - char *owner; - char *path; enum profile profile; uint8_t codec; uint8_t *config; @@ -102,6 +100,8 @@ struct pa_bluetooth_transport { bool nrec; uint16_t microphone_gain; /* Used for HSP/HFP */ uint16_t speaker_gain; /* Used for HSP/HFP */ + + void *backend_private; }; /* This enum is shared among Audio, Headset, AudioSink, and AudioSource, although not all values are acceptable in all profiles */ -- 1.8.1.4