]> code.delx.au - pulseaudio/blob - src/modules/bluetooth/module-bluetooth-discover.c
Merge commit 'coling/master'
[pulseaudio] / src / modules / bluetooth / module-bluetooth-discover.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2008 Joao Paulo Rechi Vita
5
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.
10
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.
15
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 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
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>
36
37 #include "dbus-util.h"
38 #include "module-bluetooth-discover-symdef.h"
39
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("");
44
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"
49
50 struct uuid {
51 char *uuid;
52 PA_LLIST_FIELDS(struct uuid);
53 };
54
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);
69 };
70
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);
78 };
79
80 struct userdata {
81 pa_module *module;
82 pa_dbus_connection *conn;
83 PA_LLIST_HEAD(struct adapter, adapter_list);
84 };
85
86 static struct uuid *uuid_new(const char *uuid) {
87 struct uuid *node;
88
89 node = pa_xnew(struct uuid, 1);
90 node->uuid = pa_xstrdup(uuid);
91 PA_LLIST_INIT(struct uuid, node);
92
93 return node;
94 }
95
96 static void uuid_free(struct uuid *uuid) {
97 pa_assert(uuid);
98
99 pa_xfree(uuid->uuid);
100 pa_xfree(uuid);
101 }
102
103 static struct device *device_new(struct adapter *adapter, const char *object_path) {
104 struct device *node;
105
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);
120
121 return node;
122 }
123
124 static void device_free(struct device *device) {
125 struct uuid *i;
126
127 pa_assert(device);
128
129 while ((i = device->uuid_list)) {
130 PA_LLIST_REMOVE(struct uuid, device->uuid_list, i);
131 uuid_free(i);
132 }
133
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);
139 }
140
141 static struct adapter *adapter_new(const char *object_path) {
142 struct adapter *node;
143
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;
149
150 PA_LLIST_HEAD_INIT(struct device, node->device_list);
151 PA_LLIST_INIT(struct adapter, node);
152
153 return node;
154 }
155
156 static void adapter_free(struct adapter *adapter) {
157 struct device *i;
158
159 pa_assert(adapter);
160
161 while ((i = adapter->device_list)) {
162 PA_LLIST_REMOVE(struct device, adapter->device_list, i);
163 device_free(i);
164 }
165
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);
171 }
172
173 static struct adapter* adapter_find(struct userdata *u, const char *path) {
174 struct adapter *i;
175
176 for (i = u->adapter_list; i; i = i->next)
177 if (pa_streq(i->object_path, path))
178 return i;
179
180 return NULL;
181 }
182
183 static struct device* device_find(struct userdata *u, const char *path) {
184 struct adapter *j;
185 struct device *i;
186
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;
191
192 return NULL;
193 }
194
195 static const char *yes_no_na(int b) {
196 if (b < 0)
197 return "n/a";
198
199 return pa_yes_no(b);
200 }
201
202 static void print_devices(struct adapter *a) {
203 struct device *i;
204
205 pa_assert(a);
206
207 for (i = a->device_list; i; i = i->next) {
208 struct uuid *j;
209
210 if (pa_streq(i->object_path, "/DEVICE_HEAD"))
211 continue;
212
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));
227
228 pa_log_debug("\t\tUUIDs = ");
229 for (j = i->uuid_list; j; j = j->next) {
230
231 if (pa_streq(j->uuid, "UUID_HEAD"))
232 continue;
233
234 pa_log_debug("\t\t %s", j->uuid);
235 }
236
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));
243 }
244 }
245
246 static void print_adapters(struct userdata *u) {
247 struct adapter *i;
248
249 pa_assert(u);
250
251 for (i = u->adapter_list; i; i = i->next) {
252
253 if (pa_streq(i->object_path, "/ADAPTER_HEAD"))
254 continue;
255
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));
265
266 print_devices(i);
267 }
268 }
269
270 static const char *strip_object_path(const char *op) {
271 const char *slash;
272
273 if ((slash = strrchr(op, '/')))
274 return slash+1;
275
276 return op;
277 }
278
279 static void load_module_for_device(struct userdata *u, struct device *d) {
280 char *args;
281 pa_module *m;
282
283 pa_assert(u);
284 pa_assert(d);
285
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;
290
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;
295 }
296
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);
300
301 if (!m) {
302 pa_log_debug("Failed to load module for device %s", d->object_path);
303 return;
304 }
305
306 d->module_index = m->index;
307 }
308
309 static void load_modules(struct userdata *u) {
310 struct device *d;
311 struct adapter *a;
312
313 pa_assert(u);
314
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);
318 }
319
320 static int parse_adapter_property(struct userdata *u, struct adapter *a, DBusMessageIter *i) {
321 const char *key;
322 DBusMessageIter variant_i;
323
324 pa_assert(u);
325 pa_assert(a);
326 pa_assert(i);
327
328 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
329 pa_log("Property name not a string.");
330 return -1;
331 }
332
333 dbus_message_iter_get_basic(i, &key);
334
335 if (!dbus_message_iter_next(i)) {
336 pa_log("Property value missing");
337 return -1;
338 }
339
340 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
341 pa_log("Property value not a variant.");
342 return -1;
343 }
344
345 dbus_message_iter_recurse(i, &variant_i);
346
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);
350
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);
360 }
361 }
362
363 return 0;
364 }
365
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;
371
372 pa_assert(u);
373 pa_assert(a);
374 dbus_error_init(&e);
375
376 pa_assert_se(m = dbus_message_new_method_call("org.bluez", a->object_path, "org.bluez.Adapter", "GetProperties"));
377
378 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
379
380 if (!r) {
381 pa_log("org.bluez.Adapter.GetProperties failed: %s", e.message);
382 goto finish;
383 }
384
385 if (!dbus_message_iter_init(r, &arg_i)) {
386 pa_log("org.bluez.Adapter.GetProperties reply has no arguments");
387 goto finish;
388 }
389
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;
393 }
394
395 dbus_message_iter_recurse(&arg_i, &element_i);
396 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
397
398 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
399 DBusMessageIter dict_i;
400
401 dbus_message_iter_recurse(&element_i, &dict_i);
402
403 if (parse_adapter_property(u, a, &dict_i) < 0)
404 goto finish;
405 }
406
407 if (!dbus_message_iter_next(&element_i))
408 break;
409 }
410
411 ret = 0;
412
413 finish:
414 if (m)
415 dbus_message_unref(m);
416 if (r)
417 dbus_message_unref(r);
418
419 dbus_error_free(&e);
420
421 return ret;
422 }
423
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;
430
431 pa_assert(u);
432 dbus_error_init(&e);
433
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);
437
438 if (!r) {
439 pa_log("org.bluez.Manager.ListAdapters failed: %s", e.message);
440 goto finish;
441 }
442
443 if (!dbus_message_iter_init(r, &arg_i)) {
444 pa_log("org.bluez.Manager.ListAdapters reply has no arguments");
445 goto finish;
446 }
447
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;
451 }
452
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) {
456
457 struct adapter *node;
458 const char *value;
459
460 dbus_message_iter_get_basic(&element_i, &value);
461 node = adapter_new(value);
462 PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
463 }
464
465 if (!dbus_message_iter_next(&element_i))
466 break;
467 }
468
469 ret = 0;
470
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);
474
475 finish:
476 if (m)
477 dbus_message_unref(m);
478 if (r)
479 dbus_message_unref(r);
480
481 dbus_error_free(&e);
482 return ret;
483 }
484
485 static int parse_device_property(struct userdata *u, struct device *d, DBusMessageIter *i) {
486 const char *key;
487 DBusMessageIter variant_i;
488
489 pa_assert(u);
490 pa_assert(d);
491 pa_assert(i);
492
493 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
494 pa_log("Property name not a string.");
495 return -1;
496 }
497
498 dbus_message_iter_get_basic(i, &key);
499
500 if (!dbus_message_iter_next(i)) {
501 pa_log("Property value missing");
502 return -1;
503 }
504
505 if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
506 pa_log("Property value not a variant.");
507 return -1;
508 }
509
510 dbus_message_iter_recurse(i, &variant_i);
511
512 pa_log_debug("Parsing device property %s", key);
513
514 switch (dbus_message_iter_get_arg_type(&variant_i)) {
515
516 case DBUS_TYPE_STRING: {
517
518 const char *value;
519 dbus_message_iter_get_basic(&variant_i, &value);
520
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);
530 }
531
532 break;
533 }
534
535 case DBUS_TYPE_BOOLEAN: {
536
537 dbus_bool_t value;
538 dbus_message_iter_get_basic(&variant_i, &value);
539
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;
546
547 break;
548 }
549
550 case DBUS_TYPE_UINT32: {
551
552 uint32_t value;
553 dbus_message_iter_get_basic(&variant_i, &value);
554
555 if (pa_streq(key, "Class"))
556 d->class = (int) value;
557
558 break;
559 }
560
561 case DBUS_TYPE_ARRAY: {
562
563 DBusMessageIter ai;
564 dbus_message_iter_recurse(&variant_i, &ai);
565
566 if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING &&
567 pa_streq(key, "UUIDs")) {
568
569 d->audio_profile = NULL;
570
571 while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
572 struct uuid *node;
573 const char *value;
574
575 dbus_message_iter_get_basic(&ai, &value);
576 node = uuid_new(value);
577 PA_LLIST_PREPEND(struct uuid, d->uuid_list, node);
578
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";
586
587 if (!dbus_message_iter_next(&ai))
588 break;
589 }
590 }
591
592 break;
593 }
594 }
595
596 return 0;
597 }
598
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;
604
605 pa_assert(u);
606 pa_assert(d);
607
608 dbus_error_init(&e);
609
610 pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->object_path, "org.bluez.Device", "GetProperties"));
611
612 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
613
614 if (!r) {
615 pa_log("org.bluez.Device.GetProperties failed: %s", e.message);
616 goto finish;
617 }
618
619 if (!dbus_message_iter_init(r, &arg_i)) {
620 pa_log("org.bluez.Device.GetProperties reply has no arguments");
621 goto finish;
622 }
623
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;
627 }
628
629 dbus_message_iter_recurse(&arg_i, &element_i);
630 while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
631
632 if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
633 DBusMessageIter dict_i;
634
635 dbus_message_iter_recurse(&element_i, &dict_i);
636
637 if (parse_device_property(u, d, &dict_i) < 0)
638 goto finish;
639 }
640
641 if (!dbus_message_iter_next(&element_i))
642 break;
643 }
644
645 ret = 0;
646
647 finish:
648 if (m)
649 dbus_message_unref(m);
650 if (r)
651 dbus_message_unref(r);
652
653 dbus_error_free(&e);
654
655 return ret;
656 }
657
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;
666
667 pa_assert(u);
668 dbus_error_init(&e);
669
670 /* get devices of each adapter */
671 for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next) {
672
673 pa_assert_se(m = dbus_message_new_method_call("org.bluez", adapter_list_i->object_path, "org.bluez.Adapter", "ListDevices"));
674
675 r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
676
677 if (!r) {
678 pa_log("org.bluez.Adapter.ListDevices failed: %s", e.message);
679 goto finish;
680 }
681
682 if (!dbus_message_iter_init(r, &arg_i)) {
683 pa_log("org.bluez.Adapter.ListDevices reply has no arguments");
684 goto finish;
685 }
686
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;
690 }
691
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);
699 }
700
701 if (!dbus_message_iter_next(&element_i))
702 break;
703 }
704 }
705
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);
710
711 ret = 0;
712
713 finish:
714 if (m)
715 dbus_message_unref(m);
716 if (r)
717 dbus_message_unref(r);
718
719 dbus_error_free(&e);
720
721 return ret;
722 }
723
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;
729
730 pa_assert(bus);
731 pa_assert(msg);
732 pa_assert(userdata);
733 u = userdata;
734
735 dbus_error_init(&err);
736
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));
741
742 if (dbus_message_is_signal(msg, "org.bluez.Manager", "AdapterAdded")) {
743
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;
750
751 dbus_message_iter_get_basic(&arg_i, &value);
752 pa_log_debug("hcid: adapter %s added", value);
753
754 node = adapter_new(value);
755 PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
756
757 get_adapter_properties(u, node);
758 }
759
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;
767
768 dbus_message_iter_get_basic(&arg_i, &value);
769 pa_log_debug("hcid: adapter %s removed", value);
770
771 if ((a = adapter_find(u, value))) {
772 PA_LLIST_REMOVE(struct adapter, u->adapter_list, a);
773 adapter_free(a);
774 }
775 }
776
777 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "PropertyChanged")) {
778
779 if (!dbus_message_iter_init(msg, &arg_i))
780 pa_log("dbus: message has no parameters");
781 else {
782 struct adapter *a;
783
784 if ((a = adapter_find(u, dbus_message_get_path(msg))))
785 parse_adapter_property(u, a, &arg_i);
786 }
787
788 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceCreated")) {
789
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;
796
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;
801
802 dbus_message_iter_get_basic(&arg_i, &value);
803 pa_log_debug("hcid: device %s created", value);
804
805 node = device_new(adapter, value);
806 PA_LLIST_PREPEND(struct device, adapter->device_list, node);
807
808 get_device_properties(u, node);
809 load_module_for_device(u, node);
810 }
811 }
812
813 } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceRemoved")) {
814
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;
821
822 dbus_message_iter_get_basic(&arg_i, &value);
823 pa_log_debug("hcid: device %s removed", value);
824
825 if ((d = device_find(u, value))) {
826 PA_LLIST_REMOVE(struct device, d->adapter->device_list, d);
827 device_free(d);
828 }
829 }
830
831 } else if (dbus_message_is_signal(msg, "org.bluez.Device", "PropertyChanged")) {
832
833 if (!dbus_message_iter_init(msg, &arg_i))
834 pa_log("dbus: message has no parameters");
835 else {
836 struct device *d;
837
838 if ((d = device_find(u, dbus_message_get_path(msg)))) {
839 parse_device_property(u, d, &arg_i);
840
841 /* Hmm, something changed, let's try to reconnect if we
842 * aren't connected yet */
843 load_module_for_device(u, d);
844 }
845 }
846 }
847
848 dbus_error_free(&err);
849 return DBUS_HANDLER_RESULT_HANDLED;
850 }
851
852 void pa__done(pa_module* m) {
853 struct userdata *u;
854 struct adapter *i;
855
856 pa_assert(m);
857
858 if (!(u = m->userdata))
859 return;
860
861 while ((i = u->adapter_list)) {
862 PA_LLIST_REMOVE(struct adapter, u->adapter_list, i);
863 adapter_free(i);
864 }
865
866 if (u->conn)
867 pa_dbus_connection_unref(u->conn);
868
869 pa_xfree(u);
870 }
871
872 int pa__init(pa_module* m) {
873 DBusError err;
874 struct userdata *u;
875
876 pa_assert(m);
877 dbus_error_init(&err);
878
879 m->userdata = u = pa_xnew(struct userdata, 1);
880 u->module = m;
881 PA_LLIST_HEAD_INIT(struct adapter, u->adapter_list);
882
883 /* connect to the bus */
884 u->conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err);
885 if (dbus_error_is_set(&err) || (u->conn == NULL) ) {
886 pa_log("Failed to get D-Bus connection: %s", err.message);
887 goto fail;
888 }
889
890 /* static detection of bluetooth audio devices */
891 detect_adapters(u);
892 detect_devices(u);
893
894 print_adapters(u);
895 load_modules(u);
896
897 /* dynamic detection of bluetooth audio devices */
898 if (!dbus_connection_add_filter(pa_dbus_connection_get(u->conn), filter_cb, u, NULL)) {
899 pa_log_error("Failed to add filter function");
900 goto fail;
901 }
902
903 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Manager'", &err);
904 if (dbus_error_is_set(&err)) {
905 pa_log_error("Unable to subscribe to org.bluez.Manager signals: %s: %s", err.name, err.message);
906 goto fail;
907 }
908
909 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Adapter'", &err);
910 if (dbus_error_is_set(&err)) {
911 pa_log_error("Unable to subscribe to org.bluez.Adapter signals: %s: %s", err.name, err.message);
912 goto fail;
913 }
914
915 dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Device'", &err);
916 if (dbus_error_is_set(&err)) {
917 pa_log_error("Unable to subscribe to org.bluez.Device signals: %s: %s", err.name, err.message);
918 goto fail;
919 }
920
921 return 0;
922
923 fail:
924 dbus_error_free(&err);
925 pa__done(m);
926
927 return -1;
928 }