merge glitch-free branch back into trunk
[profile/ivi/pulseaudio.git] / src / modules / module-hal-detect.c
1 /* $Id$ */
2
3 /***
4     This file is part of PulseAudio.
5
6     Copyright 2006 Lennart Poettering
7     Copyright 2006 Shams E. King
8
9     PulseAudio is free software; you can redistribute it and/or modify
10     it under the terms of the GNU Lesser General Public License as published
11     by the Free Software Foundation; either version 2 of the License,
12     or (at your option) any later version.
13
14     PulseAudio is distributed in the hope that it will be useful, but
15     WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17     General Public License for more details.
18
19     You should have received a copy of the GNU Lesser General Public License
20     along with PulseAudio; if not, write to the Free Software
21     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22     USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37
38 #include <pulse/xmalloc.h>
39 #include <pulse/timeval.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/hashmap.h>
45 #include <pulsecore/idxset.h>
46 #include <pulsecore/core-util.h>
47 #include <pulsecore/namereg.h>
48 #include <pulsecore/core-scache.h>
49 #include <pulsecore/modargs.h>
50
51 #include <hal/libhal.h>
52
53 #include "dbus-util.h"
54 #include "module-hal-detect-symdef.h"
55
56 PA_MODULE_AUTHOR("Shahms King");
57 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
58 PA_MODULE_VERSION(PACKAGE_VERSION);
59 PA_MODULE_LOAD_ONCE(TRUE);
60 #if defined(HAVE_ALSA) && defined(HAVE_OSS)
61 PA_MODULE_USAGE("api=<alsa or oss>");
62 #elif defined(HAVE_ALSA)
63 PA_MODULE_USAGE("api=<alsa>");
64 #elif defined(HAVE_OSS)
65 PA_MODULE_USAGE("api=<oss>");
66 #endif
67
68 struct device {
69     uint32_t index;
70     char *udi;
71     char *sink_name, *source_name;
72     int acl_race_fix;
73 };
74
75 struct userdata {
76     pa_core *core;
77     LibHalContext *context;
78     pa_dbus_connection *connection;
79     pa_hashmap *devices;
80     const char *capability;
81 };
82
83 struct timerdata {
84     struct userdata *u;
85     char *udi;
86 };
87
88 #define CAPABILITY_ALSA "alsa"
89 #define CAPABILITY_OSS "oss"
90
91 static const char* const valid_modargs[] = {
92     "api",
93     NULL
94 };
95
96 static void hal_device_free(struct device* d) {
97     pa_assert(d);
98
99     pa_xfree(d->udi);
100     pa_xfree(d->sink_name);
101     pa_xfree(d->source_name);
102     pa_xfree(d);
103 }
104
105 static void hal_device_free_cb(void *d, PA_GCC_UNUSED void *data) {
106     hal_device_free(d);
107 }
108
109 static const char *strip_udi(const char *udi) {
110     const char *slash;
111
112     if ((slash = strrchr(udi, '/')))
113         return slash+1;
114
115     return udi;
116 }
117
118 #ifdef HAVE_ALSA
119
120 typedef enum {
121     ALSA_TYPE_SINK,
122     ALSA_TYPE_SOURCE,
123     ALSA_TYPE_OTHER,
124     ALSA_TYPE_MAX
125 } alsa_type_t;
126
127 static alsa_type_t hal_alsa_device_get_type(LibHalContext *context, const char *udi, DBusError *error) {
128     char *type;
129     alsa_type_t t;
130
131     if (!(type = libhal_device_get_property_string(context, udi, "alsa.type", error)))
132         return ALSA_TYPE_OTHER;
133
134     if (!strcmp(type, "playback"))
135         t = ALSA_TYPE_SINK;
136     else if (!strcmp(type, "capture"))
137         t = ALSA_TYPE_SOURCE;
138     else
139         t = ALSA_TYPE_OTHER;
140
141     libhal_free_string(type);
142
143     return t;
144 }
145
146 static int hal_alsa_device_is_modem(LibHalContext *context, const char *udi, DBusError *error) {
147     char *class;
148     int r;
149
150     if (!(class = libhal_device_get_property_string(context, udi, "alsa.pcm_class", error)))
151         return 0;
152
153     r = strcmp(class, "modem") == 0;
154     pa_xfree(class);
155
156     return r;
157 }
158
159 static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, char **sink_name, char **source_name) {
160     char *args;
161     alsa_type_t type;
162     int device, card;
163     const char *module_name;
164     DBusError error;
165     pa_module *m;
166
167     dbus_error_init(&error);
168
169     pa_assert(u);
170     pa_assert(sink_name);
171     pa_assert(source_name);
172
173     *sink_name = *source_name = NULL;
174
175     type = hal_alsa_device_get_type(u->context, udi, &error);
176     if (dbus_error_is_set(&error) || type == ALSA_TYPE_OTHER)
177         goto fail;
178
179     device = libhal_device_get_property_int(u->context, udi, "alsa.device", &error);
180     if (dbus_error_is_set(&error) || device != 0)
181         goto fail;
182
183     card = libhal_device_get_property_int(u->context, udi, "alsa.card", &error);
184     if (dbus_error_is_set(&error))
185         goto fail;
186
187     if (hal_alsa_device_is_modem(u->context, udi, &error))
188         goto fail;
189
190     if (type == ALSA_TYPE_SINK) {
191         *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi));
192
193         module_name = "module-alsa-sink";
194         args = pa_sprintf_malloc("device_id=%u sink_name=%s", card, *sink_name);
195     } else {
196         *source_name = pa_sprintf_malloc("alsa_input.%s", strip_udi(udi));
197
198         module_name = "module-alsa-source";
199         args = pa_sprintf_malloc("device_id=%u source_name=%s", card, *source_name);
200     }
201
202     pa_log_debug("Loading %s with arguments '%s'", module_name, args);
203
204     m = pa_module_load(u->core, module_name, args);
205
206     pa_xfree(args);
207
208     if (!m) {
209         pa_xfree(*sink_name);
210         pa_xfree(*source_name);
211         *sink_name = *source_name = NULL;
212     }
213
214     return m;
215
216 fail:
217     if (dbus_error_is_set(&error)) {
218         pa_log_error("D-Bus error while parsing ALSA data: %s: %s", error.name, error.message);
219         dbus_error_free(&error);
220     }
221
222     return NULL;
223 }
224
225 #endif
226
227 #ifdef HAVE_OSS
228
229 static int hal_oss_device_is_pcm(LibHalContext *context, const char *udi, DBusError *error) {
230     char *class = NULL, *dev = NULL, *e;
231     int device;
232     int r = 0;
233
234     class = libhal_device_get_property_string(context, udi, "oss.type", error);
235     if (dbus_error_is_set(error) || !class)
236         goto finish;
237
238     if (strcmp(class, "pcm"))
239         goto finish;
240
241     dev = libhal_device_get_property_string(context, udi, "oss.device_file", error);
242     if (dbus_error_is_set(error) || !dev)
243         goto finish;
244
245     if ((e = strrchr(dev, '/')))
246         if (pa_startswith(e + 1, "audio"))
247             goto finish;
248
249     device = libhal_device_get_property_int(context, udi, "oss.device", error);
250     if (dbus_error_is_set(error) || device != 0)
251         goto finish;
252
253     r = 1;
254
255 finish:
256
257     libhal_free_string(class);
258     libhal_free_string(dev);
259
260     return r;
261 }
262
263 static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, char **sink_name, char **source_name) {
264     char* args;
265     char* device;
266     DBusError error;
267     pa_module *m;
268
269     dbus_error_init(&error);
270
271     pa_assert(u);
272     pa_assert(sink_name);
273     pa_assert(source_name);
274
275     *sink_name = *source_name = NULL;
276
277     if (!hal_oss_device_is_pcm(u->context, udi, &error) || dbus_error_is_set(&error))
278         goto fail;
279
280     device = libhal_device_get_property_string(u->context, udi, "oss.device_file", &error);
281     if (!device || dbus_error_is_set(&error))
282         goto fail;
283
284     *sink_name = pa_sprintf_malloc("oss_output.%s", strip_udi(udi));
285     *source_name = pa_sprintf_malloc("oss_input.%s", strip_udi(udi));
286
287     args = pa_sprintf_malloc("device=%s sink_name=%s source_name=%s", device, *sink_name, *source_name);
288     libhal_free_string(device);
289
290     pa_log_debug("Loading module-oss with arguments '%s'", args);
291     m = pa_module_load(u->core, "module-oss", args);
292     pa_xfree(args);
293
294     if (!m) {
295         pa_xfree(*sink_name);
296         pa_xfree(*source_name);
297         *sink_name = *source_name = NULL;
298     }
299
300     return m;
301
302 fail:
303     if (dbus_error_is_set(&error)) {
304         pa_log_error("D-Bus error while parsing OSS data: %s: %s", error.name, error.message);
305         dbus_error_free(&error);
306     }
307
308     return NULL;
309 }
310 #endif
311
312 static struct device* hal_device_add(struct userdata *u, const char *udi) {
313     pa_module* m = NULL;
314     struct device *d;
315     char *sink_name = NULL, *source_name = NULL;
316
317     pa_assert(u);
318     pa_assert(u->capability);
319     pa_assert(!pa_hashmap_get(u->devices, udi));
320
321 #ifdef HAVE_ALSA
322     if (strcmp(u->capability, CAPABILITY_ALSA) == 0)
323         m = hal_device_load_alsa(u, udi, &sink_name, &source_name);
324 #endif
325 #ifdef HAVE_OSS
326     if (strcmp(u->capability, CAPABILITY_OSS) == 0)
327         m = hal_device_load_oss(u, udi, &sink_name, &source_name);
328 #endif
329
330     if (!m)
331         return NULL;
332
333     d = pa_xnew(struct device, 1);
334     d->acl_race_fix = 0;
335     d->udi = pa_xstrdup(udi);
336     d->index = m->index;
337     d->sink_name = sink_name;
338     d->source_name = source_name;
339     pa_hashmap_put(u->devices, d->udi, d);
340
341     return d;
342 }
343
344 static int hal_device_add_all(struct userdata *u, const char *capability) {
345     DBusError error;
346     int i, n, count = 0;
347     char** udis;
348
349     pa_assert(u);
350
351     dbus_error_init(&error);
352
353     if (u->capability && strcmp(u->capability, capability) != 0)
354         return 0;
355
356     pa_log_info("Trying capability %s", capability);
357
358     udis = libhal_find_device_by_capability(u->context, capability, &n, &error);
359     if (dbus_error_is_set(&error)) {
360         pa_log_error("Error finding devices: %s: %s", error.name, error.message);
361         dbus_error_free(&error);
362         return -1;
363     }
364
365     if (n > 0) {
366         u->capability = capability;
367
368         for (i = 0; i < n; i++) {
369             struct device *d;
370
371             if (!(d = hal_device_add(u, udis[i])))
372                 pa_log_debug("Not loaded device %s", udis[i]);
373             else {
374                 if (d->sink_name)
375                     pa_scache_play_item_by_name(u->core, "pulse-coldplug", d->sink_name, FALSE, PA_VOLUME_NORM, NULL, NULL);
376                 count++;
377             }
378         }
379     }
380
381     libhal_free_string_array(udis);
382     return count;
383 }
384
385 static dbus_bool_t device_has_capability(LibHalContext *context, const char *udi, const char* cap, DBusError *error){
386     dbus_bool_t has_prop;
387
388     has_prop = libhal_device_property_exists(context, udi, "info.capabilities", error);
389     if (!has_prop || dbus_error_is_set(error))
390         return FALSE;
391
392     return libhal_device_query_capability(context, udi, cap, error);
393 }
394
395 static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, const struct timeval *tv, void *userdata) {
396     DBusError error;
397     struct timerdata *td = userdata;
398
399     dbus_error_init(&error);
400
401     if (!pa_hashmap_get(td->u->devices, td->udi)) {
402         int b;
403         struct device *d;
404
405         b = libhal_device_exists(td->u->context, td->udi, &error);
406
407         if (dbus_error_is_set(&error)) {
408             pa_log_error("Error adding device: %s: %s", error.name, error.message);
409             dbus_error_free(&error);
410         } else if (b) {
411             if (!(d = hal_device_add(td->u, td->udi)))
412                 pa_log_debug("Not loaded device %s", td->udi);
413             else {
414                 if (d->sink_name)
415                     pa_scache_play_item_by_name(td->u->core, "pulse-hotplug", d->sink_name, FALSE, PA_VOLUME_NORM, NULL, NULL);
416             }
417         }
418     }
419
420     pa_xfree(td->udi);
421     pa_xfree(td);
422     ea->time_free(ev);
423 }
424
425 static void device_added_cb(LibHalContext *context, const char *udi) {
426     DBusError error;
427     struct timeval tv;
428     struct timerdata *t;
429     struct userdata *u;
430     int good = 0;
431
432     pa_assert_se(u = libhal_ctx_get_user_data(context));
433
434     if (pa_hashmap_get(u->devices, udi))
435         return;
436
437     pa_log_debug("HAL Device added: %s", udi);
438
439     dbus_error_init(&error);
440
441     if (u->capability) {
442
443         good = device_has_capability(context, udi, u->capability, &error);
444
445         if (dbus_error_is_set(&error)) {
446             pa_log_error("Error getting capability: %s: %s", error.name, error.message);
447             dbus_error_free(&error);
448             return;
449         }
450
451     } else {
452
453 #ifdef HAVE_ALSA
454         good = device_has_capability(context, udi, CAPABILITY_ALSA, &error);
455
456         if (dbus_error_is_set(&error)) {
457             pa_log_error("Error getting capability: %s: %s", error.name, error.message);
458             dbus_error_free(&error);
459             return;
460         }
461
462         if (good)
463             u->capability = CAPABILITY_ALSA;
464 #endif
465 #if defined(HAVE_OSS) && defined(HAVE_ALSA)
466         if (!good) {
467 #endif
468 #ifdef HAS_OSS
469             good = device_has_capability(context, udi, CAPABILITY_OSS, &error);
470
471             if (dbus_error_is_set(&error)) {
472                 pa_log_error("Error getting capability: %s: %s", error.name, error.message);
473                 dbus_error_free(&error);
474                 return;
475             }
476
477             if (good)
478                 u->capability = CAPABILITY_OSS;
479
480 #endif
481 #if defined(HAVE_OSS) && defined(HAVE_ALSA)
482         }
483 #endif
484     }
485
486     if (!good)
487         return;
488
489     /* actually add the device 1/2 second later */
490     t = pa_xnew(struct timerdata, 1);
491     t->u = u;
492     t->udi = pa_xstrdup(udi);
493
494     pa_gettimeofday(&tv);
495     pa_timeval_add(&tv, 500000);
496     u->core->mainloop->time_new(u->core->mainloop, &tv, device_added_time_cb, t);
497 }
498
499 static void device_removed_cb(LibHalContext* context, const char *udi) {
500     struct device *d;
501     struct userdata *u;
502
503     pa_assert_se(u = libhal_ctx_get_user_data(context));
504
505     pa_log_debug("Device removed: %s", udi);
506
507     if ((d = pa_hashmap_remove(u->devices, udi))) {
508         pa_module_unload_by_index(u->core, d->index);
509         hal_device_free(d);
510     }
511 }
512
513 static void new_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
514     struct userdata *u;
515
516     pa_assert_se(u = libhal_ctx_get_user_data(context));
517
518     if (!u->capability || strcmp(u->capability, capability) == 0)
519         /* capability we care about, pretend it's a new device */
520         device_added_cb(context, udi);
521 }
522
523 static void lost_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
524     struct userdata *u;
525
526     pa_assert_se(u = libhal_ctx_get_user_data(context));
527
528     if (u->capability && strcmp(u->capability, capability) == 0)
529         /* capability we care about, pretend it was removed */
530         device_removed_cb(context, udi);
531 }
532
533 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
534     struct userdata*u = userdata;
535     DBusError error;
536
537     pa_assert(bus);
538     pa_assert(message);
539     pa_assert(u);
540
541     dbus_error_init(&error);
542
543     pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
544                  dbus_message_get_interface(message),
545                  dbus_message_get_path(message),
546                  dbus_message_get_member(message));
547
548     if (dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLAdded") ||
549         dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLRemoved")) {
550         uint32_t uid;
551         int suspend = strcmp(dbus_message_get_member(message), "ACLRemoved") == 0;
552
553         if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
554             pa_log_error("Failed to parse ACL message: %s: %s", error.name, error.message);
555             goto finish;
556         }
557
558         if (uid == getuid() || uid == geteuid()) {
559             struct device *d;
560             const char *udi;
561
562             udi = dbus_message_get_path(message);
563
564             if ((d = pa_hashmap_get(u->devices, udi))) {
565                 int send_acl_race_fix_message = 0;
566
567                 d->acl_race_fix = 0;
568
569                 if (d->sink_name) {
570                     pa_sink *sink;
571
572                     if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) {
573                         int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED;
574
575                         if (prev_suspended && !suspend) {
576                             /* resume */
577                             if (pa_sink_suspend(sink, 0) >= 0)
578                                 pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, FALSE, PA_VOLUME_NORM, NULL, NULL);
579                             else
580                                 d->acl_race_fix = 1;
581
582                         } else if (!prev_suspended && suspend) {
583                             /* suspend */
584                             if (pa_sink_suspend(sink, 1) >= 0)
585                                 send_acl_race_fix_message = 1;
586                         }
587                     }
588                 }
589
590                 if (d->source_name) {
591                     pa_source *source;
592
593                     if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) {
594                         int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED;
595
596                         if (prev_suspended && !suspend) {
597                             /* resume */
598                             if (pa_source_suspend(source, 0) < 0)
599                                 d->acl_race_fix = 1;
600
601                         } else if (!prev_suspended && suspend) {
602                             /* suspend */
603                             if (pa_source_suspend(source, 0) >= 0)
604                                 send_acl_race_fix_message = 1;
605                         }
606                     }
607                 }
608
609                 if (send_acl_race_fix_message) {
610                     DBusMessage *msg;
611                     msg = dbus_message_new_signal(udi, "org.pulseaudio.Server", "DirtyGiveUpMessage");
612                     dbus_connection_send(pa_dbus_connection_get(u->connection), msg, NULL);
613                     dbus_message_unref(msg);
614                 }
615
616             } else if (!suspend)
617                 device_added_cb(u->context, udi);
618         }
619
620     } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) {
621         /* We use this message to avoid a dirty race condition when we
622            get an ACLAdded message before the previously owning PA
623            sever has closed the device. We can remove this as
624            soon as HAL learns frevoke() */
625
626         const char *udi;
627         struct device *d;
628
629         udi = dbus_message_get_path(message);
630
631         if ((d = pa_hashmap_get(u->devices, udi)) && d->acl_race_fix) {
632             pa_log_debug("Got dirty give up message for '%s', trying resume ...", udi);
633
634             d->acl_race_fix = 0;
635
636             if (d->sink_name) {
637                 pa_sink *sink;
638
639                 if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) {
640
641                     int prev_suspended = pa_sink_get_state(sink) == PA_SINK_SUSPENDED;
642
643                     if (prev_suspended) {
644                         /* resume */
645                         if (pa_sink_suspend(sink, 0) >= 0)
646                             pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, FALSE, PA_VOLUME_NORM, NULL, NULL);
647                     }
648                 }
649             }
650
651             if (d->source_name) {
652                 pa_source *source;
653
654                 if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) {
655
656                     int prev_suspended = pa_source_get_state(source) == PA_SOURCE_SUSPENDED;
657
658                     if (prev_suspended)
659                         pa_source_suspend(source, 0);
660                 }
661             }
662
663         } else
664             /* Yes, we don't check the UDI for validity, but hopefully HAL will */
665             device_added_cb(u->context, udi);
666     }
667
668 finish:
669     dbus_error_free(&error);
670
671     return DBUS_HANDLER_RESULT_HANDLED;
672 }
673
674 static void hal_context_free(LibHalContext* hal_context) {
675     DBusError error;
676
677     dbus_error_init(&error);
678
679     libhal_ctx_shutdown(hal_context, &error);
680     libhal_ctx_free(hal_context);
681
682     dbus_error_free(&error);
683 }
684
685 static LibHalContext* hal_context_new(pa_core* c, DBusConnection *conn) {
686     DBusError error;
687     LibHalContext *hal_context = NULL;
688
689     dbus_error_init(&error);
690
691     if (!(hal_context = libhal_ctx_new())) {
692         pa_log_error("libhal_ctx_new() failed");
693         goto fail;
694     }
695
696     if (!libhal_ctx_set_dbus_connection(hal_context, conn)) {
697         pa_log_error("Error establishing DBUS connection: %s: %s", error.name, error.message);
698         goto fail;
699     }
700
701     if (!libhal_ctx_init(hal_context, &error)) {
702         pa_log_error("Couldn't connect to hald: %s: %s", error.name, error.message);
703         goto fail;
704     }
705
706     return hal_context;
707
708 fail:
709     if (hal_context)
710         hal_context_free(hal_context);
711
712     dbus_error_free(&error);
713
714     return NULL;
715 }
716
717 int pa__init(pa_module*m) {
718     DBusError error;
719     pa_dbus_connection *conn;
720     struct userdata *u = NULL;
721     LibHalContext *hal_context = NULL;
722     int n = 0;
723     pa_modargs *ma;
724     const char *api;
725
726     pa_assert(m);
727
728     dbus_error_init(&error);
729
730     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
731         pa_log("Failed to parse module arguments");
732         goto fail;
733     }
734
735     if ((api = pa_modargs_get_value(ma, "api", NULL))) {
736         int good = 0;
737
738 #ifdef HAVE_ALSA
739         if (strcmp(api, CAPABILITY_ALSA) == 0) {
740             good = 1;
741             api = CAPABILITY_ALSA;
742         }
743 #endif
744 #ifdef HAVE_OSS
745         if (strcmp(api, CAPABILITY_OSS) == 0) {
746             good = 1;
747             api = CAPABILITY_OSS;
748         }
749 #endif
750
751         if (!good) {
752             pa_log_error("Invalid API specification.");
753             goto fail;
754         }
755     }
756
757     if (!(conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
758         if (conn)
759             pa_dbus_connection_unref(conn);
760         pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message);
761         goto fail;
762     }
763
764     if (!(hal_context = hal_context_new(m->core, pa_dbus_connection_get(conn)))) {
765         /* pa_hal_context_new() logs appropriate errors */
766         pa_dbus_connection_unref(conn);
767         goto fail;
768     }
769
770     u = pa_xnew(struct userdata, 1);
771     u->core = m->core;
772     u->context = hal_context;
773     u->connection = conn;
774     u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
775     u->capability = api;
776     m->userdata = u;
777
778 #ifdef HAVE_ALSA
779     n = hal_device_add_all(u, CAPABILITY_ALSA);
780 #endif
781 #if defined(HAVE_ALSA) && defined(HAVE_OSS)
782     if (n <= 0)
783 #endif
784 #ifdef HAVE_OSS
785         n += hal_device_add_all(u, CAPABILITY_OSS);
786 #endif
787
788     libhal_ctx_set_user_data(hal_context, u);
789     libhal_ctx_set_device_added(hal_context, device_added_cb);
790     libhal_ctx_set_device_removed(hal_context, device_removed_cb);
791     libhal_ctx_set_device_new_capability(hal_context, new_capability_cb);
792     libhal_ctx_set_device_lost_capability(hal_context, lost_capability_cb);
793
794     if (!libhal_device_property_watch_all(hal_context, &error)) {
795         pa_log_error("Error monitoring device list: %s: %s", error.name, error.message);
796         goto fail;
797     }
798
799     if (!dbus_connection_add_filter(pa_dbus_connection_get(conn), filter_cb, u, NULL)) {
800         pa_log_error("Failed to add filter function");
801         goto fail;
802     }
803
804     dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error);
805     if (dbus_error_is_set(&error)) {
806         pa_log_error("Unable to subscribe to HAL ACL signals: %s: %s", error.name, error.message);
807         goto fail;
808     }
809
810     dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',interface='org.pulseaudio.Server'", &error);
811     if (dbus_error_is_set(&error)) {
812         pa_log_error("Unable to subscribe to PulseAudio signals: %s: %s", error.name, error.message);
813         goto fail;
814     }
815
816     pa_log_info("Loaded %i modules.", n);
817
818     pa_modargs_free(ma);
819
820     return 0;
821
822 fail:
823     if (ma)
824         pa_modargs_free(ma);
825
826     dbus_error_free(&error);
827     pa__done(m);
828
829     return -1;
830 }
831
832
833 void pa__done(pa_module *m) {
834     struct userdata *u;
835
836     pa_assert(m);
837
838     if (!(u = m->userdata))
839         return;
840
841     if (u->context)
842         hal_context_free(u->context);
843
844     if (u->devices)
845         pa_hashmap_free(u->devices, hal_device_free_cb, NULL);
846
847     if (u->connection)
848         pa_dbus_connection_unref(u->connection);
849
850     pa_xfree(u);
851 }