]> code.delx.au - pulseaudio/blob - src/modules/module-device-manager.c
device-manager: Change the write function to a rename function.
[pulseaudio] / src / modules / module-device-manager.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2006-2008 Lennart Poettering
5 Copyright 2009 Colin Guthrie
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <unistd.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34
35 #include <pulse/xmalloc.h>
36 #include <pulse/volume.h>
37 #include <pulse/timeval.h>
38 #include <pulse/util.h>
39 #include <pulse/rtclock.h>
40
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/module.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/modargs.h>
45 #include <pulsecore/log.h>
46 #include <pulsecore/core-subscribe.h>
47 #include <pulsecore/sink-input.h>
48 #include <pulsecore/source-output.h>
49 #include <pulsecore/namereg.h>
50 #include <pulsecore/protocol-native.h>
51 #include <pulsecore/pstream.h>
52 #include <pulsecore/pstream-util.h>
53 #include <pulsecore/database.h>
54
55 #include "module-device-manager-symdef.h"
56
57 PA_MODULE_AUTHOR("Colin Guthrie");
58 PA_MODULE_DESCRIPTION("Keep track of devices (and their descriptions) both past and present");
59 PA_MODULE_VERSION(PACKAGE_VERSION);
60 PA_MODULE_LOAD_ONCE(TRUE);
61 PA_MODULE_USAGE("This module does not take any arguments");
62
63 #define SAVE_INTERVAL (10 * PA_USEC_PER_SEC)
64
65 static const char* const valid_modargs[] = {
66 NULL
67 };
68
69 struct userdata {
70 pa_core *core;
71 pa_module *module;
72 pa_subscription *subscription;
73 pa_hook_slot
74 *sink_new_hook_slot,
75 *source_new_hook_slot,
76 *connection_unlink_hook_slot;
77 pa_time_event *save_time_event;
78 pa_database *database;
79
80 pa_native_protocol *protocol;
81 pa_idxset *subscribed;
82
83 pa_bool_t role_device_priority_routing;
84 pa_bool_t stream_restore_used;
85 pa_bool_t checked_stream_restore;
86 };
87
88 #define ENTRY_VERSION 1
89
90 #define NUM_ROLES 9
91 enum {
92 ROLE_NONE,
93 ROLE_VIDEO,
94 ROLE_MUSIC,
95 ROLE_GAME,
96 ROLE_EVENT,
97 ROLE_PHONE,
98 ROLE_ANIMATION,
99 ROLE_PRODUCTION,
100 ROLE_A11Y,
101 };
102
103 struct entry {
104 uint8_t version;
105 char description[PA_NAME_MAX];
106 uint32_t priority[NUM_ROLES];
107 } PA_GCC_PACKED;
108
109 enum {
110 SUBCOMMAND_TEST,
111 SUBCOMMAND_READ,
112 SUBCOMMAND_RENAME,
113 SUBCOMMAND_DELETE,
114 SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING,
115 SUBCOMMAND_PREFER_DEVICE,
116 SUBCOMMAND_DEFER_DEVICE,
117 SUBCOMMAND_SUBSCRIBE,
118 SUBCOMMAND_EVENT
119 };
120
121 static void save_time_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
122 struct userdata *u = userdata;
123
124 pa_assert(a);
125 pa_assert(e);
126 pa_assert(u);
127
128 pa_assert(e == u->save_time_event);
129 u->core->mainloop->time_free(u->save_time_event);
130 u->save_time_event = NULL;
131
132 pa_database_sync(u->database);
133 pa_log_info("Synced.");
134 }
135
136 static struct entry* read_entry(struct userdata *u, const char *name) {
137 pa_datum key, data;
138 struct entry *e;
139
140 pa_assert(u);
141 pa_assert(name);
142
143 key.data = (char*) name;
144 key.size = strlen(name);
145
146 pa_zero(data);
147
148 if (!pa_database_get(u->database, &key, &data))
149 goto fail;
150
151 if (data.size != sizeof(struct entry)) {
152 pa_log_debug("Database contains entry for device %s of wrong size %lu != %lu. Probably due to upgrade, ignoring.", name, (unsigned long) data.size, (unsigned long) sizeof(struct entry));
153 goto fail;
154 }
155
156 e = (struct entry*) data.data;
157
158 if (e->version != ENTRY_VERSION) {
159 pa_log_debug("Version of database entry for device %s doesn't match our version. Probably due to upgrade, ignoring.", name);
160 goto fail;
161 }
162
163 if (!memchr(e->description, 0, sizeof(e->description))) {
164 pa_log_warn("Database contains entry for device %s with missing NUL byte in description", name);
165 goto fail;
166 }
167
168 return e;
169
170 fail:
171
172 pa_datum_free(&data);
173 return NULL;
174 }
175
176 static void trigger_save(struct userdata *u) {
177 if (u->save_time_event)
178 return;
179
180 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
181 }
182
183 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
184 if (strncmp(a->description, b->description, sizeof(a->description)))
185 return FALSE;
186
187 return TRUE;
188 }
189
190 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
191 struct userdata *u = userdata;
192 struct entry entry, *old = NULL;
193 char *name = NULL;
194 pa_datum key, data;
195
196 pa_assert(c);
197 pa_assert(u);
198
199 if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
200 t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
201 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
202 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
203 return;
204
205 pa_zero(entry);
206 entry.version = ENTRY_VERSION;
207
208 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
209 pa_sink *sink;
210
211 if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
212 return;
213
214 name = pa_sprintf_malloc("sink:%s", sink->name);
215
216 if ((old = read_entry(u, name)))
217 entry = *old;
218
219 pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
220
221 } else {
222 pa_source *source;
223
224 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
225
226 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
227 return;
228
229 if (source->monitor_of)
230 return;
231
232 name = pa_sprintf_malloc("source:%s", source->name);
233
234 if ((old = read_entry(u, name)))
235 entry = *old;
236
237 pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
238 }
239
240 if (old) {
241
242 if (entries_equal(old, &entry)) {
243 pa_xfree(old);
244 pa_xfree(name);
245 return;
246 }
247
248 pa_xfree(old);
249 }
250
251 key.data = name;
252 key.size = strlen(name);
253
254 data.data = &entry;
255 data.size = sizeof(entry);
256
257 pa_log_info("Storing device description for %s.", name);
258
259 pa_database_set(u->database, &key, &data, TRUE);
260
261 pa_xfree(name);
262
263 trigger_save(u);
264 }
265
266 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
267 char *name;
268 struct entry *e;
269
270 pa_assert(c);
271 pa_assert(new_data);
272 pa_assert(u);
273
274 name = pa_sprintf_malloc("sink:%s", new_data->name);
275
276 if ((e = read_entry(u, name))) {
277 if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
278 pa_log_info("Restoring description for sink %s.", new_data->name);
279 pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
280 }
281
282 pa_xfree(e);
283 }
284
285 pa_xfree(name);
286
287 return PA_HOOK_OK;
288 }
289
290 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
291 char *name;
292 struct entry *e;
293
294 pa_assert(c);
295 pa_assert(new_data);
296 pa_assert(u);
297
298 name = pa_sprintf_malloc("source:%s", new_data->name);
299
300 if ((e = read_entry(u, name))) {
301
302 if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
303 /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
304 pa_log_info("Restoring description for sink %s.", new_data->name);
305 pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
306 }
307
308 pa_xfree(e);
309 }
310
311 pa_xfree(name);
312
313 return PA_HOOK_OK;
314 }
315
316 static char *get_name(const char *key, const char *prefix) {
317 char *t;
318
319 if (strncmp(key, prefix, strlen(prefix)))
320 return NULL;
321
322 t = pa_xstrdup(key + strlen(prefix));
323 return t;
324 }
325
326 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
327 pa_sink *sink;
328 pa_source *source;
329 uint32_t idx;
330 char *n;
331
332 pa_assert(u);
333 pa_assert(name);
334 pa_assert(e);
335
336 if ((n = get_name(name, "sink:"))) {
337 for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
338 if (!pa_streq(sink->name, n)) {
339 continue;
340 }
341
342 pa_log_info("Setting description for sink %s.", sink->name);
343 pa_sink_set_description(sink, e->description);
344 }
345 pa_xfree(n);
346 }
347 else if ((n = get_name(name, "source:"))) {
348 for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
349 if (!pa_streq(source->name, n)) {
350 continue;
351 }
352
353 if (source->monitor_of) {
354 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
355 continue;
356 }
357
358 pa_log_info("Setting description for source %s.", source->name);
359 pa_source_set_description(source, e->description);
360 }
361 pa_xfree(n);
362 }
363 }
364
365
366 static uint32_t get_role_index(const char* role) {
367 pa_assert(role);
368
369 if (strcmp(role, "") == 0)
370 return ROLE_NONE;
371 if (strcmp(role, "video") == 0)
372 return ROLE_VIDEO;
373 if (strcmp(role, "music") == 0)
374 return ROLE_MUSIC;
375 if (strcmp(role, "game") == 0)
376 return ROLE_GAME;
377 if (strcmp(role, "event") == 0)
378 return ROLE_EVENT;
379 if (strcmp(role, "phone") == 0)
380 return ROLE_PHONE;
381 if (strcmp(role, "animation") == 0)
382 return ROLE_ANIMATION;
383 if (strcmp(role, "production") == 0)
384 return ROLE_PRODUCTION;
385 if (strcmp(role, "a11y") == 0)
386 return ROLE_A11Y;
387 return PA_INVALID_INDEX;
388 }
389
390 #define EXT_VERSION 1
391
392 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
393 struct userdata *u;
394 uint32_t command;
395 pa_tagstruct *reply = NULL;
396
397 pa_assert(p);
398 pa_assert(m);
399 pa_assert(c);
400 pa_assert(t);
401
402 u = m->userdata;
403
404 if (pa_tagstruct_getu32(t, &command) < 0)
405 goto fail;
406
407 reply = pa_tagstruct_new(NULL, 0);
408 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
409 pa_tagstruct_putu32(reply, tag);
410
411 switch (command) {
412 case SUBCOMMAND_TEST: {
413 if (!pa_tagstruct_eof(t))
414 goto fail;
415
416 pa_tagstruct_putu32(reply, EXT_VERSION);
417 break;
418 }
419
420 case SUBCOMMAND_READ: {
421 pa_datum key;
422 pa_bool_t done;
423
424 if (!pa_tagstruct_eof(t))
425 goto fail;
426
427 done = !pa_database_first(u->database, &key, NULL);
428
429 while (!done) {
430 pa_datum next_key;
431 struct entry *e;
432 char *name;
433
434 done = !pa_database_next(u->database, &key, &next_key, NULL);
435
436 name = pa_xstrndup(key.data, key.size);
437 pa_datum_free(&key);
438
439 if ((e = read_entry(u, name))) {
440 pa_tagstruct_puts(reply, name);
441 pa_tagstruct_puts(reply, e->description);
442
443 pa_xfree(e);
444 }
445
446 pa_xfree(name);
447
448 key = next_key;
449 }
450
451 break;
452 }
453
454 case SUBCOMMAND_RENAME: {
455
456 struct entry *e;
457 const char *device, *description;
458
459 if (pa_tagstruct_gets(t, &device) < 0 ||
460 pa_tagstruct_gets(t, &description) < 0)
461 goto fail;
462
463 if (!device || !*device || !description || !*description)
464 goto fail;
465
466 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
467 pa_datum key, data;
468
469 pa_strlcpy(e->description, description, sizeof(e->description));
470
471 key.data = (char *) device;
472 key.size = strlen(device);
473
474 data.data = e;
475 data.size = sizeof(*e);
476
477 if (pa_database_set(u->database, &key, &data, FALSE) == 0) {
478 apply_entry(u, device, e);
479
480 trigger_save(u);
481 }
482 else
483 pa_log_warn("Could not save device");
484
485 pa_xfree(e);
486 }
487 else
488 pa_log_warn("Could not rename device %s, no entry in database", device);
489
490 break;
491 }
492
493 case SUBCOMMAND_DELETE:
494
495 while (!pa_tagstruct_eof(t)) {
496 const char *name;
497 pa_datum key;
498
499 if (pa_tagstruct_gets(t, &name) < 0)
500 goto fail;
501
502 key.data = (char*) name;
503 key.size = strlen(name);
504
505 pa_database_unset(u->database, &key);
506 }
507
508 trigger_save(u);
509
510 break;
511
512 case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
513
514 pa_bool_t enable;
515 uint32_t sridx = PA_INVALID_INDEX;
516 uint32_t idx;
517 pa_module *module;
518
519 if (pa_tagstruct_get_boolean(t, &enable) < 0)
520 goto fail;
521
522 /* If this is the first run, check for stream restore module */
523 if (!u->checked_stream_restore) {
524 u->checked_stream_restore = TRUE;
525
526 for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
527 if (strcmp(module->name, "module-stream-restore") == 0) {
528 pa_log_debug("Detected module-stream-restore is currently in use");
529 u->stream_restore_used = TRUE;
530 sridx = module->index;
531 }
532 }
533 }
534
535 u->role_device_priority_routing = enable;
536 if (enable) {
537 if (u->stream_restore_used) {
538 if (PA_INVALID_INDEX == sridx) {
539 /* As a shortcut on first load, we have sridx filled in, but otherwise we search for it. */
540 for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
541 if (strcmp(module->name, "module-stream-restore") == 0) {
542 sridx = module->index;
543 }
544 }
545 }
546 if (PA_INVALID_INDEX != sridx) {
547 pa_log_debug("Unloading module-stream-restore to enable role-based device-priority routing");
548 pa_module_unload_request_by_index(u->core, sridx, TRUE);
549 }
550 }
551 } else if (u->stream_restore_used) {
552 /* We want to reload module-stream-restore */
553 if (!pa_module_load(u->core, "module-stream-restore", ""))
554 pa_log_warn("Failed to load module-stream-restore while disabling role-based device-priority routing");
555 }
556
557 break;
558 }
559
560 case SUBCOMMAND_PREFER_DEVICE:
561 case SUBCOMMAND_DEFER_DEVICE: {
562
563 const char *role, *device;
564 struct entry *e;
565 uint32_t role_index;
566
567 if (pa_tagstruct_gets(t, &role) < 0 ||
568 pa_tagstruct_gets(t, &device) < 0)
569 goto fail;
570
571 if (!role || !device || !*device)
572 goto fail;
573
574 role_index = get_role_index(role);
575 if (PA_INVALID_INDEX == role_index)
576 goto fail;
577
578 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
579 pa_datum key;
580 pa_datum data;
581 pa_bool_t done;
582 char* prefix;
583 uint32_t priority;
584 pa_bool_t haschanged = FALSE;
585
586 if (strncmp(device, "sink:", 5) == 0)
587 prefix = pa_xstrdup("sink:");
588 else
589 prefix = pa_xstrdup("source:");
590
591 priority = e->priority[role_index];
592
593 /* Now we need to load up all the other entries of this type and shuffle the priroities around */
594
595 done = !pa_database_first(u->database, &key, NULL);
596
597 while (!done && !haschanged) {
598 pa_datum next_key;
599
600 done = !pa_database_next(u->database, &key, &next_key, NULL);
601
602 /* Only read devices with the right prefix */
603 if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
604 char *name;
605 struct entry *e2;
606
607 name = pa_xstrndup(key.data, key.size);
608 pa_datum_free(&key);
609
610 if ((e2 = read_entry(u, name))) {
611 if (SUBCOMMAND_PREFER_DEVICE == command) {
612 /* PREFER */
613 if (e2->priority[role_index] == (priority - 1)) {
614 e2->priority[role_index]++;
615 haschanged = TRUE;
616 }
617 } else {
618 /* DEFER */
619 if (e2->priority[role_index] == (priority + 1)) {
620 e2->priority[role_index]--;
621 haschanged = TRUE;
622 }
623 }
624
625 if (haschanged) {
626 data.data = e2;
627 data.size = sizeof(*e2);
628
629 if (pa_database_set(u->database, &key, &data, FALSE))
630 pa_log_warn("Could not save device");
631 }
632 pa_xfree(e2);
633 }
634
635 pa_xfree(name);
636 }
637
638 key = next_key;
639 }
640
641 /* Now write out our actual entry */
642 if (haschanged) {
643 if (SUBCOMMAND_PREFER_DEVICE == command)
644 e->priority[role_index]--;
645 else
646 e->priority[role_index]++;
647
648 key.data = (char *) device;
649 key.size = strlen(device);
650
651 data.data = e;
652 data.size = sizeof(*e);
653
654 if (pa_database_set(u->database, &key, &data, FALSE))
655 pa_log_warn("Could not save device");
656
657 trigger_save(u);
658 }
659
660 pa_xfree(e);
661
662 pa_xfree(prefix);
663 }
664 else
665 pa_log_warn("Could not reorder device %s, no entry in database", device);
666
667 break;
668 }
669
670 case SUBCOMMAND_SUBSCRIBE: {
671
672 pa_bool_t enabled;
673
674 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
675 !pa_tagstruct_eof(t))
676 goto fail;
677
678 if (enabled)
679 pa_idxset_put(u->subscribed, c, NULL);
680 else
681 pa_idxset_remove_by_data(u->subscribed, c, NULL);
682
683 break;
684 }
685
686 default:
687 goto fail;
688 }
689
690 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
691 return 0;
692
693 fail:
694
695 if (reply)
696 pa_tagstruct_free(reply);
697
698 return -1;
699 }
700
701 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
702 pa_assert(p);
703 pa_assert(c);
704 pa_assert(u);
705
706 pa_idxset_remove_by_data(u->subscribed, c, NULL);
707 return PA_HOOK_OK;
708 }
709
710 int pa__init(pa_module*m) {
711 pa_modargs *ma = NULL;
712 struct userdata *u;
713 char *fname;
714 pa_sink *sink;
715 pa_source *source;
716 uint32_t idx;
717
718 pa_assert(m);
719
720 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
721 pa_log("Failed to parse module arguments");
722 goto fail;
723 }
724
725 m->userdata = u = pa_xnew0(struct userdata, 1);
726 u->core = m->core;
727 u->module = m;
728 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
729
730 u->protocol = pa_native_protocol_get(m->core);
731 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
732
733 u->connection_unlink_hook_slot = pa_hook_connect(&pa_native_protocol_hooks(u->protocol)[PA_NATIVE_HOOK_CONNECTION_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) connection_unlink_hook_cb, u);
734
735 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
736
737 u->sink_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) sink_new_hook_callback, u);
738 u->source_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) source_new_hook_callback, u);
739
740 if (!(fname = pa_state_path("device-manager", TRUE)))
741 goto fail;
742
743 if (!(u->database = pa_database_open(fname, TRUE))) {
744 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
745 pa_xfree(fname);
746 goto fail;
747 }
748
749 pa_log_info("Sucessfully opened database file '%s'.", fname);
750 pa_xfree(fname);
751
752 for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
753 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
754
755 for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
756 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
757
758 pa_modargs_free(ma);
759 return 0;
760
761 fail:
762 pa__done(m);
763
764 if (ma)
765 pa_modargs_free(ma);
766
767 return -1;
768 }
769
770 void pa__done(pa_module*m) {
771 struct userdata* u;
772
773 pa_assert(m);
774
775 if (!(u = m->userdata))
776 return;
777
778 if (u->subscription)
779 pa_subscription_free(u->subscription);
780
781 if (u->sink_new_hook_slot)
782 pa_hook_slot_free(u->sink_new_hook_slot);
783 if (u->source_new_hook_slot)
784 pa_hook_slot_free(u->source_new_hook_slot);
785
786 if (u->save_time_event)
787 u->core->mainloop->time_free(u->save_time_event);
788
789 if (u->database)
790 pa_database_close(u->database);
791
792 if (u->protocol) {
793 pa_native_protocol_remove_ext(u->protocol, m);
794 pa_native_protocol_unref(u->protocol);
795 }
796
797 if (u->subscribed)
798 pa_idxset_free(u->subscribed, NULL, NULL);
799
800 pa_xfree(u);
801 }