From 3aa39726dbe824a9f6e85dd429e64271db8b2849 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 21 Mar 2009 01:19:49 +0100 Subject: rework device discovery to share a single device list among all modules --- src/modules/bluetooth/bluetooth-util.c | 245 +++++++++------------- src/modules/bluetooth/bluetooth-util.h | 19 +- src/modules/bluetooth/module-bluetooth-device.c | 95 +++++---- src/modules/bluetooth/module-bluetooth-discover.c | 57 +++-- 4 files changed, 189 insertions(+), 227 deletions(-) diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 369b08a8..3dfc65e7 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -24,31 +24,19 @@ #endif #include +#include #include #include "bluetooth-util.h" -enum mode { - MODE_FIND, - MODE_GET, - MODE_DISCOVER -}; - struct pa_bluetooth_discovery { - DBusConnection *connection; - PA_LLIST_HEAD(pa_dbus_pending, pending); + PA_REFCNT_DECLARE; - enum mode mode; - - /* If mode == MODE_FIND look for a specific device by its address. - If mode == MODE_GET look for a specific device by its path. */ - const char *looking_for; - pa_bluetooth_device *found_device; - - /* If looking_for is NULL we do long-time discovery */ + pa_core *core; + pa_dbus_connection *connection; + PA_LLIST_HEAD(pa_dbus_pending, pending); pa_hashmap *devices; - pa_bluetooth_device_callback_t callback; - struct userdata *userdata; + pa_hook hook; }; static pa_bluetooth_uuid *uuid_new(const char *uuid) { @@ -73,9 +61,9 @@ static pa_bluetooth_device* device_new(const char *path) { d = pa_xnew(pa_bluetooth_device, 1); - d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0; + d->dead = FALSE; - d->data = NULL; + d->device_info_valid = d->audio_sink_info_valid = d->headset_info_valid = 0; d->name = NULL; d->path = pa_xstrdup(path); @@ -94,7 +82,7 @@ static pa_bluetooth_device* device_new(const char *path) { return d; } -void pa_bluetooth_device_free(pa_bluetooth_device *d) { +static void device_free(pa_bluetooth_device *d) { pa_bluetooth_uuid *u; pa_assert(d); @@ -127,7 +115,8 @@ static pa_bool_t device_is_audio(pa_bluetooth_device *d) { pa_assert(d->audio_sink_info_valid); pa_assert(d->headset_info_valid); - return d->device_info_valid > 0 && + return + d->device_info_valid > 0 && (d->audio_sink_info_valid > 0 || d->headset_info_valid > 0); } @@ -289,20 +278,18 @@ static int parse_audio_property(pa_bluetooth_discovery *u, int *connected, DBusM return 0; } -static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_bool_t good) { +static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_bool_t dead) { pa_assert(y); pa_assert(d); - if (y->mode != MODE_DISCOVER) - return; - if (!device_is_loaded(d)) return; if (!device_is_audio(d)) return; - y->callback(y->userdata, d, good); + d->dead = dead; + pa_hook_fire(&y->hook, d); } static void get_properties_reply(DBusPendingCall *pending, void *userdata) { @@ -377,7 +364,7 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) { } finish: - run_callback(y, d, TRUE); + run_callback(y, d, FALSE); dbus_message_unref(r); @@ -392,9 +379,9 @@ static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, pa_bl pa_assert(y); pa_assert(m); - pa_assert_se(dbus_connection_send_with_reply(y->connection, m, &call, -1)); + pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(y->connection), m, &call, -1)); - p = pa_dbus_pending_new(y->connection, m, call, y, d); + p = pa_dbus_pending_new(pa_dbus_connection_get(y->connection), m, call, y, d); PA_LLIST_PREPEND(pa_dbus_pending, y->pending, p); dbus_pending_call_set_notify(call, func, p, NULL); @@ -410,13 +397,7 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) { d = device_new(path); - if (y->mode == MODE_DISCOVER) { - pa_assert(y->devices); - pa_hashmap_put(y->devices, d->path, d); - } else { - pa_assert(!y->found_device); - y->found_device = d; - } + pa_hashmap_put(y->devices, d->path, d); pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Device", "GetProperties")); send_and_add_to_pending(y, d, m, get_properties_reply); @@ -469,57 +450,11 @@ end: pa_dbus_pending_free(p); } -static void find_device_reply(DBusPendingCall *pending, void *userdata) { - DBusError e; - DBusMessage *r; - char *path = NULL; - pa_dbus_pending *p; - pa_bluetooth_discovery *y; - - pa_assert(pending); - - dbus_error_init(&e); - - pa_assert_se(p = userdata); - pa_assert_se(y = p->context_data); - pa_assert_se(r = dbus_pending_call_steal_reply(pending)); - - if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { - pa_log("Error from FindDevice reply: %s", dbus_message_get_error_name(r)); - goto end; - } - - if (!dbus_message_get_args(r, &e, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { - pa_log("org.bluez.Adapter.FindDevice returned an error: '%s'\n", e.message); - dbus_error_free(&e); - } else - found_device(y, path); - -end: - dbus_message_unref(r); - - PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p); - pa_dbus_pending_free(p); -} - static void found_adapter(pa_bluetooth_discovery *y, const char *path) { DBusMessage *m; - if (y->mode == MODE_FIND) { - pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "FindDevice")); - - pa_assert_se(dbus_message_append_args(m, - DBUS_TYPE_STRING, &y->looking_for, - DBUS_TYPE_INVALID)); - - send_and_add_to_pending(y, NULL, m, find_device_reply); - - } else { - pa_assert(y->mode == MODE_DISCOVER); - - pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "ListDevices")); - send_and_add_to_pending(y, NULL, m, list_devices_reply); - } + pa_assert_se(m = dbus_message_new_method_call("org.bluez", path, "org.bluez.Adapter", "ListDevices")); + send_and_add_to_pending(y, NULL, m, list_devices_reply); } static void list_adapters_reply(DBusPendingCall *pending, void *userdata) { @@ -599,11 +534,8 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us pa_log_debug("Device %s removed", path); if ((d = pa_hashmap_remove(y->devices, path))) { - - pa_assert_se(y->mode == MODE_DISCOVER); - run_callback(y, d, FALSE); - - pa_bluetooth_device_free(d); + run_callback(y, d, TRUE); + device_free(d); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -661,8 +593,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us goto fail; } - pa_assert_se(y->mode == MODE_DISCOVER); - run_callback(y, d, TRUE); + run_callback(y, d, FALSE); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -674,82 +605,81 @@ fail: return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } -pa_bluetooth_device* pa_bluetooth_find_device(DBusConnection *c, const char* address) { - pa_bluetooth_discovery y; - - memset(&y, 0, sizeof(y)); - y.mode = MODE_FIND; - y.looking_for = address; - y.connection = c; - PA_LLIST_HEAD_INIT(pa_dbus_pending, y.pending); - - list_adapters(&y); +const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_discovery *y, const char* address) { + pa_bluetooth_device *d; + void *state = NULL; - pa_dbus_sync_pending_list(&y.pending); - pa_assert(!y.pending); + pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + pa_assert(address); - if (y.found_device) { - pa_assert(device_is_loaded(y.found_device)); + if (!pa_hook_is_firing(&y->hook)) + pa_bluetooth_discovery_sync(y); - if (!device_is_audio(y.found_device)) { - pa_bluetooth_device_free(y.found_device); - return NULL; - } - } + while ((d = pa_hashmap_iterate(y->devices, &state, NULL))) + if (pa_streq(d->address, address)) + return d; - return y.found_device; + return NULL; } -pa_bluetooth_device* pa_bluetooth_get_device(DBusConnection *c, const char* path) { - pa_bluetooth_discovery y; +const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *y, const char* path) { + pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + pa_assert(path); - memset(&y, 0, sizeof(y)); - y.mode = MODE_GET; - y.connection = c; - PA_LLIST_HEAD_INIT(pa_dbus_pending, y.pending); + if (!pa_hook_is_firing(&y->hook)) + pa_bluetooth_discovery_sync(y); - found_device(&y, path); + return pa_hashmap_get(y->devices, path); +} - pa_dbus_sync_pending_list(&y.pending); - pa_assert(!y.pending); +static int setup_dbus(pa_bluetooth_discovery *y) { + DBusError err; - if (y.found_device) { - pa_assert(device_is_loaded(y.found_device)); + dbus_error_init(&err); - if (!device_is_audio(y.found_device)) { - pa_bluetooth_device_free(y.found_device); - return NULL; - } + y->connection = pa_dbus_bus_get(y->core, DBUS_BUS_SYSTEM, &err); + + if (dbus_error_is_set(&err) || !y->connection) { + pa_log("Failed to get D-Bus connection: %s", err.message); + dbus_error_free(&err); + return -1; } - return y.found_device; + return 0; } -pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetooth_device_callback_t cb, struct userdata *u) { +pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { DBusError err; pa_bluetooth_discovery *y; pa_assert(c); - pa_assert(cb); dbus_error_init(&err); + if ((y = pa_shared_get(c, "bluetooth-discovery"))) + return pa_bluetooth_discovery_ref(y); + y = pa_xnew0(pa_bluetooth_discovery, 1); - y->mode = MODE_DISCOVER; - y->connection = c; - y->callback = cb; - y->userdata = u; + PA_REFCNT_INIT(y); + y->core = c; y->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); PA_LLIST_HEAD_INIT(pa_dbus_pending, y->pending); + pa_hook_init(&y->hook, y); + pa_shared_set(c, "bluetooth-discovery", y); + + if (setup_dbus(y) < 0) + goto fail; /* dynamic detection of bluetooth audio devices */ - if (!dbus_connection_add_filter(c, filter_cb, y, NULL)) { + if (!dbus_connection_add_filter(pa_dbus_connection_get(y->connection), filter_cb, y, NULL)) { pa_log_error("Failed to add filter function"); goto fail; } if (pa_dbus_add_matches( - c, &err, + pa_dbus_connection_get(y->connection), &err, "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", @@ -765,28 +695,46 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetoo return y; fail: + + if (y) + pa_bluetooth_discovery_unref(y); + dbus_error_free(&err); + return NULL; } -void pa_bluetooth_discovery_free(pa_bluetooth_discovery *y) { +pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y) { + pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + + PA_REFCNT_INC(y); + + return y; +} + +void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { pa_bluetooth_device *d; pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + + if (PA_REFCNT_DEC(y) > 0) + return; pa_dbus_free_pending_list(&y->pending); if (y->devices) { while ((d = pa_hashmap_steal_first(y->devices))) { - run_callback(y, d, FALSE); - pa_bluetooth_device_free(d); + run_callback(y, d, TRUE); + device_free(d); } pa_hashmap_free(y->devices, NULL, NULL); } if (y->connection) { - pa_dbus_remove_matches(y->connection, + pa_dbus_remove_matches(pa_dbus_connection_get(y->connection), "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", @@ -795,16 +743,31 @@ void pa_bluetooth_discovery_free(pa_bluetooth_discovery *y) { "type='signal',sender='org.bluez',interface='org.bluez.Headset',member='PropertyChanged'", "type='signal',sender='org.bluez',interface='org.bluez.AudioSink',member='PropertyChanged'", NULL); - dbus_connection_remove_filter(y->connection, filter_cb, y); + dbus_connection_remove_filter(pa_dbus_connection_get(y->connection), filter_cb, y); + + pa_dbus_connection_unref(y->connection); } + + pa_hook_done(&y->hook); + + if (y->core) + pa_shared_remove(y->core, "bluetooth-discovery"); } void pa_bluetooth_discovery_sync(pa_bluetooth_discovery *y) { pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); pa_dbus_sync_pending_list(&y->pending); } +pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *y) { + pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + + return &y->hook; +} + const char*pa_bluetooth_get_form_factor(uint32_t class) { unsigned i; const char *r; diff --git a/src/modules/bluetooth/bluetooth-util.h b/src/modules/bluetooth/bluetooth-util.h index 0364c972..1d05e63c 100644 --- a/src/modules/bluetooth/bluetooth-util.h +++ b/src/modules/bluetooth/bluetooth-util.h @@ -40,7 +40,7 @@ struct pa_bluetooth_uuid { }; struct pa_bluetooth_device { - void *data; /* arbitrary information for the one owning the discovery object */ + pa_bool_t dead; int device_info_valid; /* 0: no results yet; 1: good results; -1: bad results ... */ int audio_sink_info_valid; /* ... same here ... */ @@ -64,17 +64,18 @@ struct pa_bluetooth_device { int headset_connected; }; -void pa_bluetooth_device_free(pa_bluetooth_device *d); +pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *core); +pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y); +void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *d); -pa_bluetooth_device* pa_bluetooth_get_device(DBusConnection *c, const char* path); -pa_bluetooth_device* pa_bluetooth_find_device(DBusConnection *c, const char* address); - -typedef void (*pa_bluetooth_device_callback_t)(struct userdata *u, pa_bluetooth_device *d, pa_bool_t good); -pa_bluetooth_discovery* pa_bluetooth_discovery_new(DBusConnection *c, pa_bluetooth_device_callback_t cb, struct userdata *u); -void pa_bluetooth_discovery_free(pa_bluetooth_discovery *d); void pa_bluetooth_discovery_sync(pa_bluetooth_discovery *d); -const char*pa_bluetooth_get_form_factor(uint32_t class); +const pa_bluetooth_device* pa_bluetooth_discovery_get_by_path(pa_bluetooth_discovery *d, const char* path); +const pa_bluetooth_device* pa_bluetooth_discovery_get_by_address(pa_bluetooth_discovery *d, const char* address); + +pa_hook* pa_bluetooth_discovery_hook(pa_bluetooth_discovery *d); + +const char* pa_bluetooth_get_form_factor(uint32_t class); char *pa_bluetooth_cleanup_name(const char *name); diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 7386f8c6..928f33cf 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -122,6 +122,8 @@ struct userdata { pa_core *core; pa_module *module; + char *address; + pa_card *card; pa_sink *sink; pa_source *source; @@ -153,8 +155,6 @@ struct userdata { pa_modargs *modargs; - pa_bluetooth_device *device; - int stream_write_type, stream_read_type; int service_write_type, service_read_type; }; @@ -331,7 +331,7 @@ static int get_caps(struct userdata *u) { msg.getcaps_req.h.name = BT_GET_CAPABILITIES; msg.getcaps_req.h.length = sizeof(msg.getcaps_req); - pa_strlcpy(msg.getcaps_req.device, u->device->address, sizeof(msg.getcaps_req.device)); + pa_strlcpy(msg.getcaps_req.device, u->address, sizeof(msg.getcaps_req.device)); if (u->profile == PROFILE_A2DP) msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP; else { @@ -613,7 +613,7 @@ static int set_conf(struct userdata *u) { msg.setconf_req.h.name = BT_SET_CONFIGURATION; msg.setconf_req.h.length = sizeof(msg.setconf_req); - pa_strlcpy(msg.setconf_req.device, u->device->address, sizeof(msg.setconf_req.device)); + pa_strlcpy(msg.setconf_req.device, u->address, sizeof(msg.setconf_req.device)); msg.setconf_req.access_mode = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_ACCESS_MODE_WRITE : BT_CAPABILITIES_ACCESS_MODE_READWRITE; msg.setconf_req.codec.transport = u->profile == PROFILE_A2DP ? BT_CAPABILITIES_TRANSPORT_A2DP : BT_CAPABILITIES_TRANSPORT_SCO; @@ -1482,7 +1482,7 @@ static int add_sink(struct userdata *u) { pa_sink_new_data_set_sample_spec(&data, &u->sample_spec); pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "sco"); data.card = u->card; - data.name = get_name("sink", u->modargs, u->device->address, &b); + data.name = get_name("sink", u->modargs, u->address, &b); data.namereg_fail = b; u->sink = pa_sink_new(u->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY); @@ -1526,7 +1526,7 @@ static int add_source(struct userdata *u) { pa_source_new_data_set_sample_spec(&data, &u->sample_spec); pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile == PROFILE_A2DP ? "a2dp" : "sco"); data.card = u->card; - data.name = get_name("source", u->modargs, u->device->address, &b); + data.name = get_name("source", u->modargs, u->address, &b); data.namereg_fail = b; u->source = pa_source_new(u->core, &data, PA_SOURCE_HARDWARE|PA_SOURCE_LATENCY); @@ -1768,7 +1768,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { return 0; } -static int add_card(struct userdata *u, const char * default_profile) { +static int add_card(struct userdata *u, const char *default_profile, const pa_bluetooth_device *device) { pa_card_new_data data; pa_bool_t b; pa_card_profile *p; @@ -1780,24 +1780,24 @@ static int add_card(struct userdata *u, const char * default_profile) { data.driver = __FILE__; data.module = u->module; - n = pa_bluetooth_cleanup_name(u->device->name); + n = pa_bluetooth_cleanup_name(device->name); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, n); pa_xfree(n); - pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->device->address); + pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, device->address); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, "bluez"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound"); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_BUS, "bluetooth"); - if ((ff = pa_bluetooth_get_form_factor(u->device->class))) + if ((ff = pa_bluetooth_get_form_factor(device->class))) pa_proplist_sets(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, ff); - pa_proplist_sets(data.proplist, "bluez.path", u->device->path); - pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) u->device->class); - pa_proplist_sets(data.proplist, "bluez.name", u->device->name); - data.name = get_name("card", u->modargs, u->device->address, &b); + pa_proplist_sets(data.proplist, "bluez.path", device->path); + pa_proplist_setf(data.proplist, "bluez.class", "0x%06x", (unsigned) device->class); + pa_proplist_sets(data.proplist, "bluez.name", device->name); + data.name = get_name("card", u->modargs, device->address, &b); data.namereg_fail = b; data.profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - if (u->device->audio_sink_info_valid > 0) { + if (device->audio_sink_info_valid > 0) { p = pa_card_profile_new("a2dp", _("High Fidelity Playback (A2DP)"), sizeof(enum profile)); p->priority = 10; p->n_sinks = 1; @@ -1811,7 +1811,7 @@ static int add_card(struct userdata *u, const char * default_profile) { pa_hashmap_put(data.profiles, p->name, p); } - if (u->device->headset_info_valid > 0) { + if (device->headset_info_valid > 0) { p = pa_card_profile_new("hsp", _("Telephony Duplex (HSP/HFP)"), sizeof(enum profile)); p->priority = 20; p->n_sinks = 1; @@ -1856,47 +1856,39 @@ static int add_card(struct userdata *u, const char * default_profile) { return 0; } -static int setup_dbus(struct userdata *u) { - DBusError error; +static const pa_bluetooth_device* find_device(struct userdata *u, pa_bluetooth_discovery *y, const char *address, const char *path) { + const pa_bluetooth_device *d = NULL; - dbus_error_init(&error); - - u->connection = pa_dbus_bus_get(u->core, DBUS_BUS_SYSTEM, &error); - if (dbus_error_is_set(&error) || (!u->connection)) { - pa_log("Failed to get D-Bus connection: %s", error.message); - dbus_error_free(&error); - return -1; - } - - return 0; -} - -static int find_device(struct userdata *u, const char *address, const char *path) { pa_assert(u); + pa_assert(y); if (!address && !path) { pa_log_error("Failed to get device address/path from module arguments."); - return -1; + return NULL; } if (path) { - if (!(u->device = pa_bluetooth_get_device(pa_dbus_connection_get(u->connection), path))) { + if (!(d = pa_bluetooth_discovery_get_by_path(y, path))) { pa_log_error("%s is not a valid BlueZ audio device.", path); - return -1; + return NULL; } - if (address && !(pa_streq(u->device->address, address))) { + if (address && !(pa_streq(d->address, address))) { pa_log_error("Passed path %s and address %s don't match.", path, address); - return -1; + return NULL; } + } else { - if (!(u->device = pa_bluetooth_find_device(pa_dbus_connection_get(u->connection), address))) { + if (!(d = pa_bluetooth_discovery_get_by_address(y, address))) { pa_log_error("%s is not known.", address); - return -1; + return NULL; } } - return 0; + if (d) + u->address = pa_xstrdup(d->address); + + return d; } int pa__init(pa_module* m) { @@ -1904,6 +1896,8 @@ int pa__init(pa_module* m) { uint32_t channels; struct userdata *u; const char *address, *path; + const pa_bluetooth_device *d; + pa_bluetooth_discovery *y = NULL; pa_assert(m); @@ -1948,21 +1942,22 @@ int pa__init(pa_module* m) { u->sample_spec.channels = (uint8_t) channels; u->requested_sample_spec = u->sample_spec; - if (setup_dbus(u) < 0) - goto fail; - address = pa_modargs_get_value(ma, "address", NULL); path = pa_modargs_get_value(ma, "path", NULL); - if (find_device(u, address, path) < 0) + if (!(y = pa_bluetooth_discovery_get(m->core))) goto fail; - pa_assert(u->device); + if (!(d = find_device(u, y, address, path))) + goto fail; /* Add the card structure. This will also initialize the default profile */ - if (add_card(u, pa_modargs_get_value(ma, "profile", NULL)) < 0) + if (add_card(u, pa_modargs_get_value(ma, "profile", NULL), d) < 0) goto fail; + pa_bluetooth_discovery_unref(y); + y = NULL; + /* Connect to the BT service and query capabilities */ if (init_bt(u) < 0) goto fail; @@ -2014,7 +2009,12 @@ int pa__init(pa_module* m) { return 0; fail: + + if (y) + pa_bluetooth_discovery_unref(y); + pa__done(m); + return -1; } @@ -2080,9 +2080,6 @@ void pa__done(pa_module *m) { shutdown_bt(u); - if (u->device) - pa_bluetooth_device_free(u->device); - if (u->a2dp.buffer) pa_xfree(u->a2dp.buffer); @@ -2091,5 +2088,7 @@ void pa__done(pa_module *m) { if (u->modargs) pa_modargs_free(u->modargs); + pa_xfree(u->address); + pa_xfree(u); } diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c index 4586d8ca..22e8ea30 100644 --- a/src/modules/bluetooth/module-bluetooth-discover.c +++ b/src/modules/bluetooth/module-bluetooth-discover.c @@ -57,19 +57,28 @@ struct userdata { pa_module *module; pa_modargs *modargs; pa_core *core; - pa_dbus_connection *connection; pa_bluetooth_discovery *discovery; + pa_hook_slot *slot; + pa_hashmap *hashmap; }; -static void load_module_for_device(struct userdata *u, pa_bluetooth_device *d, pa_bool_t good) { +static pa_hook_result_t load_module_for_device(pa_bluetooth_discovery *y, const pa_bluetooth_device *d, struct userdata *u) { + uint32_t midx; + pa_assert(u); pa_assert(d); - if (good && + + if (!(midx = PA_PTR_TO_UINT(pa_hashmap_get(u->hashmap, d->path)))) + midx = PA_INVALID_INDEX; + else + midx--; + + if (!d->dead && d->device_connected > 0 && (d->audio_sink_connected > 0 || d->headset_connected > 0)) { - if (((uint32_t) PA_PTR_TO_UINT(d->data))-1 == PA_INVALID_INDEX) { + if (midx == PA_INVALID_INDEX) { pa_module *m = NULL; char *args; @@ -93,38 +102,25 @@ static void load_module_for_device(struct userdata *u, pa_bluetooth_device *d, p pa_xfree(args); if (m) - d->data = PA_UINT_TO_PTR((uint32_t) (m->index+1)); + pa_hashmap_put(u->hashmap, d->path, PA_UINT_TO_PTR((uint32_t) (m->index+1))); else pa_log_debug("Failed to load module for device %s", d->path); } } else { - if (((uint32_t) PA_PTR_TO_UINT(d->data))-1 != PA_INVALID_INDEX) { + if (midx != PA_INVALID_INDEX) { /* Hmm, disconnection? Then let's unload our module */ pa_log_debug("Unloading module for %s", d->path); - pa_module_unload_request_by_index(u->core, (uint32_t) (PA_PTR_TO_UINT(d->data))-1, TRUE); - d->data = NULL; - } - } -} - -static int setup_dbus(struct userdata *u) { - DBusError err; + pa_module_unload_request_by_index(u->core, midx, TRUE); - dbus_error_init(&err); - - u->connection = pa_dbus_bus_get(u->core, DBUS_BUS_SYSTEM, &err); - - if (dbus_error_is_set(&err) || !u->connection) { - pa_log("Failed to get D-Bus connection: %s", err.message); - dbus_error_free(&err); - return -1; + pa_hashmap_remove(u->hashmap, d->path); + } } - return 0; + return PA_HOOK_OK; } int pa__init(pa_module* m) { @@ -149,12 +145,12 @@ int pa__init(pa_module* m) { u->core = m->core; u->modargs = ma; ma = NULL; + u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - if (setup_dbus(u) < 0) + if (!(u->discovery = pa_bluetooth_discovery_get(u->core))) goto fail; - if (!(u->discovery = pa_bluetooth_discovery_new(pa_dbus_connection_get(u->connection), load_module_for_device, u))) - goto fail; + u->slot = pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery), PA_HOOK_NORMAL, (pa_hook_cb_t) load_module_for_device, u); if (!async) pa_bluetooth_discovery_sync(u->discovery); @@ -178,11 +174,14 @@ void pa__done(pa_module* m) { if (!(u = m->userdata)) return; + if (u->slot) + pa_hook_slot_free(u->slot); + if (u->discovery) - pa_bluetooth_discovery_free(u->discovery); + pa_bluetooth_discovery_unref(u->discovery); - if (u->connection) - pa_dbus_connection_unref(u->connection); + if (u->hashmap) + pa_hashmap_free(u->hashmap, NULL, NULL); if (u->modargs) pa_modargs_free(u->modargs); -- cgit