summaryrefslogtreecommitdiffstats
path: root/src/modules/bluetooth/bluetooth-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2009-03-21 01:19:49 +0100
committerLennart Poettering <lennart@poettering.net>2009-03-21 01:19:49 +0100
commit3aa39726dbe824a9f6e85dd429e64271db8b2849 (patch)
tree9509298a8515e9b5c25374ddf67d2ba34dab9bfe /src/modules/bluetooth/bluetooth-util.c
parent20488fbe3ed068d095d637763555e37af8d16322 (diff)
rework device discovery to share a single device list among all modules
Diffstat (limited to 'src/modules/bluetooth/bluetooth-util.c')
-rw-r--r--src/modules/bluetooth/bluetooth-util.c245
1 files changed, 104 insertions, 141 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 <pulsecore/core-util.h>
+#include <pulsecore/shared.h>
#include <modules/dbus-util.h>
#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;