Add signal handlers for Connected signals.
[pulseaudio-mirror.git] / src / modules / bluetooth / module-bluetooth-discover.c
blobae414a70f4cc02d0d9be57c9e258df7b9c7e9d63
1 /***
2 This file is part of PulseAudio.
4 Copyright 2008 Joao Paulo Rechi Vita
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <pulse/xmalloc.h>
31 #include <pulsecore/module.h>
32 #include <pulsecore/modargs.h>
33 #include <pulsecore/macro.h>
34 #include <pulsecore/llist.h>
35 #include <pulsecore/core-util.h>
37 #include "dbus-util.h"
38 #include "module-bluetooth-discover-symdef.h"
40 PA_MODULE_AUTHOR("Joao Paulo Rechi Vita");
41 PA_MODULE_DESCRIPTION("Detect available bluetooth audio devices and load bluetooth audio drivers");
42 PA_MODULE_VERSION(PACKAGE_VERSION);
43 PA_MODULE_USAGE("");
45 #define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
46 #define HFP_HS_UUID "0000111E-0000-1000-8000-00805F9B34FB"
47 #define A2DP_SOURCE_UUID "0000110A-0000-1000-8000-00805F9B34FB"
48 #define A2DP_SINK_UUID "0000110B-0000-1000-8000-00805F9B34FB"
50 struct uuid {
51 char *uuid;
52 PA_LLIST_FIELDS(struct uuid);
55 struct device {
56 char *name;
57 char *object_path;
58 int paired;
59 struct adapter *adapter;
60 char *alias;
61 int connected;
62 PA_LLIST_HEAD(struct uuid, uuid_list);
63 char *address;
64 int class;
65 int trusted;
66 const char *audio_profile;
67 uint32_t module_index;
68 PA_LLIST_FIELDS(struct device);
71 struct adapter {
72 char *object_path;
73 char *name;
74 char *mode;
75 char *address;
76 PA_LLIST_HEAD(struct device, device_list);
77 PA_LLIST_FIELDS(struct adapter);
80 struct userdata {
81 pa_module *module;
82 pa_dbus_connection *conn;
83 PA_LLIST_HEAD(struct adapter, adapter_list);
86 static struct uuid *uuid_new(const char *uuid) {
87 struct uuid *node;
89 node = pa_xnew(struct uuid, 1);
90 node->uuid = pa_xstrdup(uuid);
91 PA_LLIST_INIT(struct uuid, node);
93 return node;
96 static void uuid_free(struct uuid *uuid) {
97 pa_assert(uuid);
99 pa_xfree(uuid->uuid);
100 pa_xfree(uuid);
103 static struct device *device_new(struct adapter *adapter, const char *object_path) {
104 struct device *node;
106 node = pa_xnew(struct device, 1);
107 node->name = NULL;
108 node->object_path = pa_xstrdup(object_path);
109 node->paired = -1;
110 node->adapter = adapter;
111 node->alias = NULL;
112 node->connected = -1;
113 PA_LLIST_HEAD_INIT(struct uuid, node->uuid_list);
114 node->address = NULL;
115 node->class = -1;
116 node->trusted = -1;
117 node->audio_profile = NULL;
118 node->module_index = PA_INVALID_INDEX;
119 PA_LLIST_INIT(struct device, node);
121 return node;
124 static void device_free(struct device *device) {
125 struct uuid *i;
127 pa_assert(device);
129 while ((i = device->uuid_list)) {
130 PA_LLIST_REMOVE(struct uuid, device->uuid_list, i);
131 uuid_free(i);
134 pa_xfree(device->name);
135 pa_xfree(device->object_path);
136 pa_xfree(device->alias);
137 pa_xfree(device->address);
138 pa_xfree(device);
141 static struct adapter *adapter_new(const char *object_path) {
142 struct adapter *node;
144 node = pa_xnew(struct adapter, 1);
145 node->object_path = pa_xstrdup(object_path);
146 node->mode = NULL;
147 node->address = NULL;
148 node->name = NULL;
150 PA_LLIST_HEAD_INIT(struct device, node->device_list);
151 PA_LLIST_INIT(struct adapter, node);
153 return node;
156 static void adapter_free(struct adapter *adapter) {
157 struct device *i;
159 pa_assert(adapter);
161 while ((i = adapter->device_list)) {
162 PA_LLIST_REMOVE(struct device, adapter->device_list, i);
163 device_free(i);
166 pa_xfree(adapter->object_path);
167 pa_xfree(adapter->mode);
168 pa_xfree(adapter->address);
169 pa_xfree(adapter->name);
170 pa_xfree(adapter);
173 static struct adapter* adapter_find(struct userdata *u, const char *path) {
174 struct adapter *i;
176 for (i = u->adapter_list; i; i = i->next)
177 if (pa_streq(i->object_path, path))
178 return i;
180 return NULL;
183 static struct device* device_find(struct userdata *u, const char *path) {
184 struct adapter *j;
185 struct device *i;
187 for (j = u->adapter_list; j; j = j->next)
188 for (i = j->device_list; i; i = i->next)
189 if (pa_streq(i->object_path, path))
190 return i;
192 return NULL;
195 static const char *yes_no_na(int b) {
196 if (b < 0)
197 return "n/a";
199 return pa_yes_no(b);
202 static void print_devices(struct adapter *a) {
203 struct device *i;
205 pa_assert(a);
207 for (i = a->device_list; i; i = i->next) {
208 struct uuid *j;
210 if (pa_streq(i->object_path, "/DEVICE_HEAD"))
211 continue;
213 pa_log_debug("\t[ %s ]\n"
214 "\t\tName = %s\n"
215 "\t\tPaired = %s\n"
216 "\t\tAdapter = %s\n"
217 "\t\tAlias = %s\n"
218 "\t\tConnected = %s\n"
219 "\t\tAudio = %s\n",
220 i->object_path,
221 pa_strnull(i->name),
222 yes_no_na(i->paired),
223 i->adapter->object_path,
224 pa_strnull(i->alias),
225 yes_no_na(i->connected),
226 pa_strnull(i->audio_profile));
228 pa_log_debug("\t\tUUIDs = ");
229 for (j = i->uuid_list; j; j = j->next) {
231 if (pa_streq(j->uuid, "UUID_HEAD"))
232 continue;
234 pa_log_debug("\t\t %s", j->uuid);
237 pa_log_debug("\t\tAddress = %s\n"
238 "\t\tClass = 0x%x\n"
239 "\t\tTrusted = %s",
240 i->address,
241 i->class,
242 yes_no_na(i->trusted));
246 static void print_adapters(struct userdata *u) {
247 struct adapter *i;
249 pa_assert(u);
251 for (i = u->adapter_list; i; i = i->next) {
253 if (pa_streq(i->object_path, "/ADAPTER_HEAD"))
254 continue;
256 pa_log_debug(
257 "[ %s ]\n"
258 "\tName = %s\n"
259 "\tMode = %s\n"
260 "\tAddress = %s\n",
261 i->object_path,
262 pa_strnull(i->name),
263 pa_strnull(i->mode),
264 pa_strnull(i->address));
266 print_devices(i);
270 static const char *strip_object_path(const char *op) {
271 const char *slash;
273 if ((slash = strrchr(op, '/')))
274 return slash+1;
276 return op;
279 static void load_module_for_device(struct userdata *u, struct device *d) {
280 char *args;
281 pa_module *m;
283 pa_assert(u);
284 pa_assert(d);
286 /* Check whether we already loaded a module for this device */
287 if (d->module_index != PA_INVALID_INDEX &&
288 pa_idxset_get_by_index(u->module->core->modules, d->module_index))
289 return;
291 /* Check whether this is an audio device */
292 if (!d->audio_profile) {
293 pa_log_debug("Ignoring %s since it is not an audio device.", d->object_path);
294 return;
297 args = pa_sprintf_malloc("sink_name=%s address=%s profile=%s", strip_object_path(d->object_path), d->address, d->audio_profile);
298 m = pa_module_load(u->module->core, "module-bluetooth-device", args);
299 pa_xfree(args);
301 if (!m) {
302 pa_log_debug("Failed to load module for device %s", d->object_path);
303 return;
306 d->module_index = m->index;
309 static void load_modules(struct userdata *u) {
310 struct device *d;
311 struct adapter *a;
313 pa_assert(u);
315 for (a = u->adapter_list; a; a = a->next)
316 for (d = a->device_list; d; d = d->next)
317 load_module_for_device(u, d);
320 static int parse_adapter_property(struct userdata *u, struct adapter *a, DBusMessageIter *i) {
321 const char *key;
322 DBusMessageIter variant_i;
324 pa_assert(u);
325 pa_assert(a);
326 pa_assert(i);
328 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
329 pa_log("Property name not a string.");
330 return -1;
333 dbus_message_iter_get_basic(i, &key);
335 if (!dbus_message_iter_next(i)) {
336 pa_log("Property value missing");
337 return -1;
340 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
341 pa_log("Property value not a variant.");
342 return -1;
345 dbus_message_iter_recurse(i, &variant_i);
347 if (dbus_message_iter_get_arg_type(&variant_i) == DBUS_TYPE_STRING) {
348 const char *value;
349 dbus_message_iter_get_basic(&variant_i, &value);
351 if (pa_streq(key, "Mode")) {
352 pa_xfree(a->mode);
353 a->mode = pa_xstrdup(value);
354 } else if (pa_streq(key, "Address")) {
355 pa_xstrdup(a->address);
356 a->address = pa_xstrdup(value);
357 } else if (pa_streq(key, "Name")) {
358 pa_xfree(a->name);
359 a->name = pa_xstrdup(value);
363 return 0;
366 static int get_adapter_properties(struct userdata *u, struct adapter *a) {
367 DBusError e;
368 DBusMessage *m = NULL, *r = NULL;
369 DBusMessageIter arg_i, element_i;
370 int ret = -1;
372 pa_assert(u);
373 pa_assert(a);
374 dbus_error_init(&e);
376 pa_assert_se(m = dbus_message_new_method_call("org.bluez", a->object_path, "org.bluez.Adapter", "GetProperties"));
378 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
380 if (!r) {
381 pa_log("org.bluez.Adapter.GetProperties failed: %s", e.message);
382 goto finish;
385 if (!dbus_message_iter_init(r, &arg_i)) {
386 pa_log("org.bluez.Adapter.GetProperties reply has no arguments");
387 goto finish;
390 if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
391 pa_log("org.bluez.Adapter.GetProperties argument is not an array");
392 goto finish;
395 dbus_message_iter_recurse(&arg_i, &element_i);
396 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
398 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
399 DBusMessageIter dict_i;
401 dbus_message_iter_recurse(&element_i, &dict_i);
403 if (parse_adapter_property(u, a, &dict_i) < 0)
404 goto finish;
407 if (!dbus_message_iter_next(&element_i))
408 break;
411 ret = 0;
413 finish:
414 if (m)
415 dbus_message_unref(m);
416 if (r)
417 dbus_message_unref(r);
419 dbus_error_free(&e);
421 return ret;
424 static int detect_adapters(struct userdata *u) {
425 DBusError e;
426 DBusMessage *m = NULL, *r = NULL;
427 DBusMessageIter arg_i, element_i;
428 struct adapter *adapter_list_i;
429 int ret = -1;
431 pa_assert(u);
432 dbus_error_init(&e);
434 /* get adapters */
435 pa_assert_se(m = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "ListAdapters"));
436 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
438 if (!r) {
439 pa_log("org.bluez.Manager.ListAdapters failed: %s", e.message);
440 goto finish;
443 if (!dbus_message_iter_init(r, &arg_i)) {
444 pa_log("org.bluez.Manager.ListAdapters reply has no arguments");
445 goto finish;
448 if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
449 pa_log("org.bluez.Manager.ListAdapters argument is not an array");
450 goto finish;
453 dbus_message_iter_recurse(&arg_i, &element_i);
454 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
455 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_OBJECT_PATH) {
457 struct adapter *node;
458 const char *value;
460 dbus_message_iter_get_basic(&element_i, &value);
461 node = adapter_new(value);
462 PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
465 if (!dbus_message_iter_next(&element_i))
466 break;
469 ret = 0;
471 /* get adapter properties */
472 for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next)
473 get_adapter_properties(u, adapter_list_i);
475 finish:
476 if (m)
477 dbus_message_unref(m);
478 if (r)
479 dbus_message_unref(r);
481 dbus_error_free(&e);
482 return ret;
485 static int parse_device_property(struct userdata *u, struct device *d, DBusMessageIter *i) {
486 const char *key;
487 DBusMessageIter variant_i;
489 pa_assert(u);
490 pa_assert(d);
491 pa_assert(i);
493 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
494 pa_log("Property name not a string.");
495 return -1;
498 dbus_message_iter_get_basic(i, &key);
500 if (!dbus_message_iter_next(i)) {
501 pa_log("Property value missing");
502 return -1;
505 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
506 pa_log("Property value not a variant.");
507 return -1;
510 dbus_message_iter_recurse(i, &variant_i);
512 pa_log_debug("Parsing device property %s", key);
514 switch (dbus_message_iter_get_arg_type(&variant_i)) {
516 case DBUS_TYPE_STRING: {
518 const char *value;
519 dbus_message_iter_get_basic(&variant_i, &value);
521 if (pa_streq(key, "Name")) {
522 pa_xfree(d->name);
523 d->name = pa_xstrdup(value);
524 } else if (pa_streq(key, "Alias")) {
525 pa_xfree(d->alias);
526 d->alias = pa_xstrdup(value);
527 } else if (pa_streq(key, "Address")) {
528 pa_xfree(d->address);
529 d->address = pa_xstrdup(value);
532 break;
535 case DBUS_TYPE_BOOLEAN: {
537 dbus_bool_t value;
538 dbus_message_iter_get_basic(&variant_i, &value);
540 if (pa_streq(key, "Paired"))
541 d->paired = !!value;
542 else if (pa_streq(key, "Connected"))
543 d->connected = !!value;
544 else if (pa_streq(key, "Trusted"))
545 d->trusted = !!value;
547 break;
550 case DBUS_TYPE_UINT32: {
552 uint32_t value;
553 dbus_message_iter_get_basic(&variant_i, &value);
555 if (pa_streq(key, "Class"))
556 d->class = (int) value;
558 break;
561 case DBUS_TYPE_ARRAY: {
563 DBusMessageIter ai;
564 dbus_message_iter_recurse(&variant_i, &ai);
566 if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING &&
567 pa_streq(key, "UUIDs")) {
569 d->audio_profile = NULL;
571 while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
572 struct uuid *node;
573 const char *value;
575 dbus_message_iter_get_basic(&ai, &value);
576 node = uuid_new(value);
577 PA_LLIST_PREPEND(struct uuid, d->uuid_list, node);
579 if ((strcasecmp(value, A2DP_SOURCE_UUID) == 0) ||
580 (strcasecmp(value, A2DP_SINK_UUID) == 0))
581 d->audio_profile = "a2dp";
582 else if (((strcasecmp(value, HSP_HS_UUID) == 0) ||
583 (strcasecmp(value, HFP_HS_UUID) == 0)) &&
584 !d->audio_profile)
585 d->audio_profile = "hsp";
587 if (!dbus_message_iter_next(&ai))
588 break;
592 break;
596 return 0;
599 static int get_device_properties(struct userdata *u, struct device *d) {
600 DBusError e;
601 DBusMessage *m = NULL, *r = NULL;
602 DBusMessageIter arg_i, element_i;
603 int ret = -1;
605 pa_assert(u);
606 pa_assert(d);
608 dbus_error_init(&e);
610 pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->object_path, "org.bluez.Device", "GetProperties"));
612 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
614 if (!r) {
615 pa_log("org.bluez.Device.GetProperties failed: %s", e.message);
616 goto finish;
619 if (!dbus_message_iter_init(r, &arg_i)) {
620 pa_log("org.bluez.Device.GetProperties reply has no arguments");
621 goto finish;
624 if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
625 pa_log("org.bluez.Device.GetProperties argument is not an array");
626 goto finish;
629 dbus_message_iter_recurse(&arg_i, &element_i);
630 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
632 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
633 DBusMessageIter dict_i;
635 dbus_message_iter_recurse(&element_i, &dict_i);
637 if (parse_device_property(u, d, &dict_i) < 0)
638 goto finish;
641 if (!dbus_message_iter_next(&element_i))
642 break;
645 ret = 0;
647 finish:
648 if (m)
649 dbus_message_unref(m);
650 if (r)
651 dbus_message_unref(r);
653 dbus_error_free(&e);
655 return ret;
658 static int detect_devices(struct userdata *u) {
659 DBusError e;
660 DBusMessage *m = NULL, *r = NULL;
661 DBusMessageIter arg_i, element_i;
662 struct adapter *adapter_list_i;
663 struct device *device_list_i;
664 const char *value;
665 int ret = -1;
667 pa_assert(u);
668 dbus_error_init(&e);
670 /* get devices of each adapter */
671 for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next) {
673 pa_assert_se(m = dbus_message_new_method_call("org.bluez", adapter_list_i->object_path, "org.bluez.Adapter", "ListDevices"));
675 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
677 if (!r) {
678 pa_log("org.bluez.Adapter.ListDevices failed: %s", e.message);
679 goto finish;
682 if (!dbus_message_iter_init(r, &arg_i)) {
683 pa_log("org.bluez.Adapter.ListDevices reply has no arguments");
684 goto finish;
687 if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
688 pa_log("org.bluez.Adapter.ListDevices argument is not an array");
689 goto finish;
692 dbus_message_iter_recurse(&arg_i, &element_i);
693 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
694 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_OBJECT_PATH) {
695 struct device *node;
696 dbus_message_iter_get_basic(&element_i, &value);
697 node = device_new(adapter_list_i, value);
698 PA_LLIST_PREPEND(struct device, adapter_list_i->device_list, node);
701 if (!dbus_message_iter_next(&element_i))
702 break;
706 /* get device properties */
707 for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next)
708 for (device_list_i = adapter_list_i->device_list; device_list_i; device_list_i = device_list_i->next)
709 get_device_properties(u, device_list_i);
711 ret = 0;
713 finish:
714 if (m)
715 dbus_message_unref(m);
716 if (r)
717 dbus_message_unref(r);
719 dbus_error_free(&e);
721 return ret;
724 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *msg, void *userdata) {
725 DBusMessageIter arg_i;
726 DBusError err;
727 const char *value;
728 struct userdata *u;
730 pa_assert(bus);
731 pa_assert(msg);
732 pa_assert(userdata);
733 u = userdata;
735 dbus_error_init(&err);
737 pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
738 dbus_message_get_interface(msg),
739 dbus_message_get_path(msg),
740 dbus_message_get_member(msg));
742 if (dbus_message_is_signal(msg, "org.bluez.Manager", "AdapterAdded")) {
744 if (!dbus_message_iter_init(msg, &arg_i))
745 pa_log("dbus: message has no parameters");
746 else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
747 pa_log("dbus: argument is not object path");
748 else {
749 struct adapter *node;
751 dbus_message_iter_get_basic(&arg_i, &value);
752 pa_log_debug("hcid: adapter %s added", value);
754 node = adapter_new(value);
755 PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
757 get_adapter_properties(u, node);
760 } else if (dbus_message_is_signal(msg, "org.bluez.Manager", "AdapterRemoved")) {
761 if (!dbus_message_iter_init(msg, &arg_i))
762 pa_log("dbus: message has no parameters");
763 else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
764 pa_log("dbus: argument is not object path");
765 else {
766 struct adapter *a;
768 dbus_message_iter_get_basic(&arg_i, &value);
769 pa_log_debug("hcid: adapter %s removed", value);
771 if ((a = adapter_find(u, value))) {
772 PA_LLIST_REMOVE(struct adapter, u->adapter_list, a);
773 adapter_free(a);
777 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "PropertyChanged")) {
779 if (!dbus_message_iter_init(msg, &arg_i))
780 pa_log("dbus: message has no parameters");
781 else {
782 struct adapter *a;
784 if ((a = adapter_find(u, dbus_message_get_path(msg))))
785 parse_adapter_property(u, a, &arg_i);
788 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceCreated")) {
790 if (!dbus_message_iter_init(msg, &arg_i))
791 pa_log("dbus: message has no parameters");
792 else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
793 pa_log("dbus: argument is not object path");
794 else {
795 struct adapter *adapter;
797 if (!(adapter = adapter_find(u, dbus_message_get_path(msg))))
798 pa_log("dbus: failed to find adapter for object path");
799 else {
800 struct device *node;
802 dbus_message_iter_get_basic(&arg_i, &value);
803 pa_log_debug("hcid: device %s created", value);
805 node = device_new(adapter, value);
806 PA_LLIST_PREPEND(struct device, adapter->device_list, node);
808 get_device_properties(u, node);
809 load_module_for_device(u, node);
813 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceRemoved")) {
815 if (!dbus_message_iter_init(msg, &arg_i))
816 pa_log("dbus: message has no parameters");
817 else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
818 pa_log("dbus: argument is not object path");
819 else {
820 struct device *d;
822 dbus_message_iter_get_basic(&arg_i, &value);
823 pa_log_debug("hcid: device %s removed", value);
825 if ((d = device_find(u, value))) {
826 PA_LLIST_REMOVE(struct device, d->adapter->device_list, d);
827 device_free(d);
831 } else if (dbus_message_is_signal(msg, "org.bluez.Device", "PropertyChanged")) {
833 if (!dbus_message_iter_init(msg, &arg_i))
834 pa_log("dbus: message has no parameters");
835 else {
836 struct device *d;
838 if ((d = device_find(u, dbus_message_get_path(msg)))) {
839 parse_device_property(u, d, &arg_i);
841 /* Hmm, something changed, let's try to reconnect if we
842 * aren't connected yet */
843 load_module_for_device(u, d);
847 } else if (dbus_message_is_signal(msg, "org.bluez.Headset", "Connected") ||
848 dbus_message_is_signal(msg, "org.bluez.AudioSink", "Connected")) {
850 if (!dbus_message_iter_init(msg, &arg_i))
851 pa_log("dbus: message has no parameters");
852 else {
853 struct device *d;
855 if ((d = device_find(u, dbus_message_get_path(msg))))
856 load_module_for_device(u, d);
860 dbus_error_free(&err);
861 return DBUS_HANDLER_RESULT_HANDLED;
864 void pa__done(pa_module* m) {
865 struct userdata *u;
866 struct adapter *i;
868 pa_assert(m);
870 if (!(u = m->userdata))
871 return;
873 while ((i = u->adapter_list)) {
874 PA_LLIST_REMOVE(struct adapter, u->adapter_list, i);
875 adapter_free(i);
878 if (u->conn)
879 pa_dbus_connection_unref(u->conn);
881 pa_xfree(u);
884 int pa__init(pa_module* m) {
885 DBusError err;
886 struct userdata *u;
888 pa_assert(m);
889 dbus_error_init(&err);
891 m->userdata = u = pa_xnew(struct userdata, 1);
892 u->module = m;
893 PA_LLIST_HEAD_INIT(struct adapter, u->adapter_list);
895 /* connect to the bus */
896 u->conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err);
897 if (dbus_error_is_set(&err) || (u->conn == NULL) ) {
898 pa_log("Failed to get D-Bus connection: %s", err.message);
899 goto fail;
902 /* static detection of bluetooth audio devices */
903 detect_adapters(u);
904 detect_devices(u);
906 print_adapters(u);
907 load_modules(u);
909 /* dynamic detection of bluetooth audio devices */
910 if (!dbus_connection_add_filter(pa_dbus_connection_get(u->conn), filter_cb, u, NULL)) {
911 pa_log_error("Failed to add filter function");
912 goto fail;
915 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Manager'", &err);
916 if (dbus_error_is_set(&err)) {
917 pa_log_error("Unable to subscribe to org.bluez.Manager signals: %s: %s", err.name, err.message);
918 goto fail;
921 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Adapter'", &err);
922 if (dbus_error_is_set(&err)) {
923 pa_log_error("Unable to subscribe to org.bluez.Adapter signals: %s: %s", err.name, err.message);
924 goto fail;
927 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Device'", &err);
928 if (dbus_error_is_set(&err)) {
929 pa_log_error("Unable to subscribe to org.bluez.Device signals: %s: %s", err.name, err.message);
930 goto fail;
933 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Headset,member='Connected''", &err);
934 if (dbus_error_is_set(&err)) {
935 pa_log_error("Unable to subscribe to org.bluez.Headset signals: %s: %s", err.name, err.message);
936 goto fail;
939 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.AudioSink,member='Connected''", &err);
940 if (dbus_error_is_set(&err)) {
941 pa_log_error("Unable to subscribe to org.bluez.AudioSink signals: %s: %s", err.name, err.message);
942 goto fail;
945 return 0;
947 fail:
948 dbus_error_free(&err);
949 pa__done(m);
951 return -1;