]> code.delx.au - pulseaudio/blob - src/modules/module-device-manager.c
device-manager: Fix the freeing of the datum on prefer/defer.
[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 pa_native_connection *c;
178 uint32_t idx;
179
180 for (c = pa_idxset_first(u->subscribed, &idx); c; c = pa_idxset_next(u->subscribed, &idx)) {
181 pa_tagstruct *t;
182
183 t = pa_tagstruct_new(NULL, 0);
184 pa_tagstruct_putu32(t, PA_COMMAND_EXTENSION);
185 pa_tagstruct_putu32(t, 0);
186 pa_tagstruct_putu32(t, u->module->index);
187 pa_tagstruct_puts(t, u->module->name);
188 pa_tagstruct_putu32(t, SUBCOMMAND_EVENT);
189
190 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), t);
191 }
192
193 if (u->save_time_event)
194 return;
195
196 u->save_time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + SAVE_INTERVAL, save_time_callback, u);
197 }
198
199 static pa_bool_t entries_equal(const struct entry *a, const struct entry *b) {
200 if (strncmp(a->description, b->description, sizeof(a->description)))
201 return FALSE;
202
203 return TRUE;
204 }
205
206 static inline struct entry *load_or_initialize_entry(struct userdata *u, struct entry *entry, const char *name, const char *prefix) {
207 struct entry *old;
208
209 pa_assert(u);
210 pa_assert(entry);
211 pa_assert(name);
212 pa_assert(prefix);
213
214 if ((old = read_entry(u, name)))
215 *entry = *old;
216 else {
217 /* This is a new device, so make sure we write it's priority list correctly */
218 uint32_t max_priority[NUM_ROLES];
219 pa_datum key;
220 pa_bool_t done;
221
222 pa_zero(max_priority);
223 done = !pa_database_first(u->database, &key, NULL);
224
225 /* Find all existing devices with the same prefix so we calculate the current max priority for each role */
226 while (!done) {
227 pa_datum next_key;
228
229 done = !pa_database_next(u->database, &key, &next_key, NULL);
230
231 if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
232 char *name2;
233 struct entry *e;
234
235 name2 = pa_xstrndup(key.data, key.size);
236
237 if ((e = read_entry(u, name2))) {
238 for (uint32_t i = 0; i < NUM_ROLES; ++i) {
239 max_priority[i] = PA_MAX(max_priority[i], e->priority[i]);
240 }
241
242 pa_xfree(e);
243 }
244
245 pa_xfree(name2);
246 }
247 pa_datum_free(&key);
248 key = next_key;
249 }
250
251 /* Actually initialise our entry now we've calculated it */
252 for (uint32_t i = 0; i < NUM_ROLES; ++i) {
253 entry->priority[i] = max_priority[i] + 1;
254 }
255 }
256
257 return old;
258 }
259
260 static void subscribe_callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
261 struct userdata *u = userdata;
262 struct entry entry, *old = NULL;
263 char *name = NULL;
264 pa_datum key, data;
265
266 pa_assert(c);
267 pa_assert(u);
268
269 if (t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW) &&
270 t != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) &&
271 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW) &&
272 t != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE))
273 return;
274
275 pa_zero(entry);
276 entry.version = ENTRY_VERSION;
277
278 if ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
279 pa_sink *sink;
280
281 if (!(sink = pa_idxset_get_by_index(c->sinks, idx)))
282 return;
283
284 name = pa_sprintf_malloc("sink:%s", sink->name);
285
286 old = load_or_initialize_entry(u, &entry, name, "sink:");
287
288 pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
289
290 } else {
291 pa_source *source;
292
293 pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE);
294
295 if (!(source = pa_idxset_get_by_index(c->sources, idx)))
296 return;
297
298 if (source->monitor_of)
299 return;
300
301 name = pa_sprintf_malloc("source:%s", source->name);
302
303 old = load_or_initialize_entry(u, &entry, name, "source:");
304
305 pa_strlcpy(entry.description, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), sizeof(entry.description));
306 }
307
308 if (old) {
309
310 if (entries_equal(old, &entry)) {
311 pa_xfree(old);
312 pa_xfree(name);
313 return;
314 }
315
316 pa_xfree(old);
317 }
318
319 key.data = name;
320 key.size = strlen(name);
321
322 data.data = &entry;
323 data.size = sizeof(entry);
324
325 pa_log_info("Storing device description for %s.", name);
326
327 pa_database_set(u->database, &key, &data, TRUE);
328
329 pa_xfree(name);
330
331 trigger_save(u);
332 }
333
334 static pa_hook_result_t sink_new_hook_callback(pa_core *c, pa_sink_new_data *new_data, struct userdata *u) {
335 char *name;
336 struct entry *e;
337
338 pa_assert(c);
339 pa_assert(new_data);
340 pa_assert(u);
341
342 name = pa_sprintf_malloc("sink:%s", new_data->name);
343
344 if ((e = read_entry(u, name))) {
345 if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
346 pa_log_info("Restoring description for sink %s.", new_data->name);
347 pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
348 }
349
350 pa_xfree(e);
351 }
352
353 pa_xfree(name);
354
355 return PA_HOOK_OK;
356 }
357
358 static pa_hook_result_t source_new_hook_callback(pa_core *c, pa_source_new_data *new_data, struct userdata *u) {
359 char *name;
360 struct entry *e;
361
362 pa_assert(c);
363 pa_assert(new_data);
364 pa_assert(u);
365
366 name = pa_sprintf_malloc("source:%s", new_data->name);
367
368 if ((e = read_entry(u, name))) {
369 if (strncmp(e->description, pa_proplist_gets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION), sizeof(e->description)) != 0) {
370 /* NB, We cannot detect if we are a monitor here... this could mess things up a bit... */
371 pa_log_info("Restoring description for source %s.", new_data->name);
372 pa_proplist_sets(new_data->proplist, PA_PROP_DEVICE_DESCRIPTION, e->description);
373 }
374
375 pa_xfree(e);
376 }
377
378 pa_xfree(name);
379
380 return PA_HOOK_OK;
381 }
382
383 static char *get_name(const char *key, const char *prefix) {
384 char *t;
385
386 if (strncmp(key, prefix, strlen(prefix)))
387 return NULL;
388
389 t = pa_xstrdup(key + strlen(prefix));
390 return t;
391 }
392
393 static void apply_entry(struct userdata *u, const char *name, struct entry *e) {
394 pa_sink *sink;
395 pa_source *source;
396 uint32_t idx;
397 char *n;
398
399 pa_assert(u);
400 pa_assert(name);
401 pa_assert(e);
402
403 if ((n = get_name(name, "sink:"))) {
404 for (sink = pa_idxset_first(u->core->sinks, &idx); sink; sink = pa_idxset_next(u->core->sinks, &idx)) {
405 if (!pa_streq(sink->name, n)) {
406 continue;
407 }
408
409 pa_log_info("Setting description for sink %s.", sink->name);
410 pa_sink_set_description(sink, e->description);
411 }
412 pa_xfree(n);
413 }
414 else if ((n = get_name(name, "source:"))) {
415 for (source = pa_idxset_first(u->core->sources, &idx); source; source = pa_idxset_next(u->core->sources, &idx)) {
416 if (!pa_streq(source->name, n)) {
417 continue;
418 }
419
420 if (source->monitor_of) {
421 pa_log_warn("Cowardly refusing to set the description for monitor source %s.", source->name);
422 continue;
423 }
424
425 pa_log_info("Setting description for source %s.", source->name);
426 pa_source_set_description(source, e->description);
427 }
428 pa_xfree(n);
429 }
430 }
431
432
433 static uint32_t get_role_index(const char* role) {
434 pa_assert(role);
435
436 if (strcmp(role, "") == 0)
437 return ROLE_NONE;
438 if (strcmp(role, "video") == 0)
439 return ROLE_VIDEO;
440 if (strcmp(role, "music") == 0)
441 return ROLE_MUSIC;
442 if (strcmp(role, "game") == 0)
443 return ROLE_GAME;
444 if (strcmp(role, "event") == 0)
445 return ROLE_EVENT;
446 if (strcmp(role, "phone") == 0)
447 return ROLE_PHONE;
448 if (strcmp(role, "animation") == 0)
449 return ROLE_ANIMATION;
450 if (strcmp(role, "production") == 0)
451 return ROLE_PRODUCTION;
452 if (strcmp(role, "a11y") == 0)
453 return ROLE_A11Y;
454 return PA_INVALID_INDEX;
455 }
456
457 #define EXT_VERSION 1
458
459 static int extension_cb(pa_native_protocol *p, pa_module *m, pa_native_connection *c, uint32_t tag, pa_tagstruct *t) {
460 struct userdata *u;
461 uint32_t command;
462 pa_tagstruct *reply = NULL;
463
464 pa_assert(p);
465 pa_assert(m);
466 pa_assert(c);
467 pa_assert(t);
468
469 u = m->userdata;
470
471 if (pa_tagstruct_getu32(t, &command) < 0)
472 goto fail;
473
474 reply = pa_tagstruct_new(NULL, 0);
475 pa_tagstruct_putu32(reply, PA_COMMAND_REPLY);
476 pa_tagstruct_putu32(reply, tag);
477
478 switch (command) {
479 case SUBCOMMAND_TEST: {
480 if (!pa_tagstruct_eof(t))
481 goto fail;
482
483 pa_tagstruct_putu32(reply, EXT_VERSION);
484 break;
485 }
486
487 case SUBCOMMAND_READ: {
488 pa_datum key;
489 pa_bool_t done;
490
491 if (!pa_tagstruct_eof(t))
492 goto fail;
493
494 done = !pa_database_first(u->database, &key, NULL);
495
496 while (!done) {
497 pa_datum next_key;
498 struct entry *e;
499 char *name;
500
501 done = !pa_database_next(u->database, &key, &next_key, NULL);
502
503 name = pa_xstrndup(key.data, key.size);
504 pa_datum_free(&key);
505
506 if ((e = read_entry(u, name))) {
507 pa_tagstruct_puts(reply, name);
508 pa_tagstruct_puts(reply, e->description);
509
510 pa_xfree(e);
511 }
512
513 pa_xfree(name);
514
515 key = next_key;
516 }
517
518 break;
519 }
520
521 case SUBCOMMAND_RENAME: {
522
523 struct entry *e;
524 const char *device, *description;
525
526 if (pa_tagstruct_gets(t, &device) < 0 ||
527 pa_tagstruct_gets(t, &description) < 0)
528 goto fail;
529
530 if (!device || !*device || !description || !*description)
531 goto fail;
532
533 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
534 pa_datum key, data;
535
536 pa_strlcpy(e->description, description, sizeof(e->description));
537
538 key.data = (char *) device;
539 key.size = strlen(device);
540
541 data.data = e;
542 data.size = sizeof(*e);
543
544 if (pa_database_set(u->database, &key, &data, FALSE) == 0) {
545 apply_entry(u, device, e);
546
547 trigger_save(u);
548 }
549 else
550 pa_log_warn("Could not save device");
551
552 pa_xfree(e);
553 }
554 else
555 pa_log_warn("Could not rename device %s, no entry in database", device);
556
557 break;
558 }
559
560 case SUBCOMMAND_DELETE:
561
562 while (!pa_tagstruct_eof(t)) {
563 const char *name;
564 pa_datum key;
565
566 if (pa_tagstruct_gets(t, &name) < 0)
567 goto fail;
568
569 key.data = (char*) name;
570 key.size = strlen(name);
571
572 pa_database_unset(u->database, &key);
573 }
574
575 trigger_save(u);
576
577 break;
578
579 case SUBCOMMAND_ROLE_DEVICE_PRIORITY_ROUTING: {
580
581 pa_bool_t enable;
582 uint32_t sridx = PA_INVALID_INDEX;
583 uint32_t idx;
584 pa_module *module;
585
586 if (pa_tagstruct_get_boolean(t, &enable) < 0)
587 goto fail;
588
589 /* If this is the first run, check for stream restore module */
590 if (!u->checked_stream_restore) {
591 u->checked_stream_restore = TRUE;
592
593 for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
594 if (strcmp(module->name, "module-stream-restore") == 0) {
595 pa_log_debug("Detected module-stream-restore is currently in use");
596 u->stream_restore_used = TRUE;
597 sridx = module->index;
598 }
599 }
600 }
601
602 u->role_device_priority_routing = enable;
603 if (enable) {
604 if (u->stream_restore_used) {
605 if (PA_INVALID_INDEX == sridx) {
606 /* As a shortcut on first load, we have sridx filled in, but otherwise we search for it. */
607 for (module = pa_idxset_first(u->core->modules, &idx); module; module = pa_idxset_next(u->core->modules, &idx)) {
608 if (strcmp(module->name, "module-stream-restore") == 0) {
609 sridx = module->index;
610 }
611 }
612 }
613 if (PA_INVALID_INDEX != sridx) {
614 pa_log_debug("Unloading module-stream-restore to enable role-based device-priority routing");
615 pa_module_unload_request_by_index(u->core, sridx, TRUE);
616 }
617 }
618 } else if (u->stream_restore_used) {
619 /* We want to reload module-stream-restore */
620 if (!pa_module_load(u->core, "module-stream-restore", ""))
621 pa_log_warn("Failed to load module-stream-restore while disabling role-based device-priority routing");
622 }
623
624 break;
625 }
626
627 case SUBCOMMAND_PREFER_DEVICE:
628 case SUBCOMMAND_DEFER_DEVICE: {
629
630 const char *role, *device;
631 struct entry *e;
632 uint32_t role_index;
633
634 if (pa_tagstruct_gets(t, &role) < 0 ||
635 pa_tagstruct_gets(t, &device) < 0)
636 goto fail;
637
638 if (!role || !device || !*device)
639 goto fail;
640
641 role_index = get_role_index(role);
642 if (PA_INVALID_INDEX == role_index)
643 goto fail;
644
645 if ((e = read_entry(u, device)) && ENTRY_VERSION == e->version) {
646 pa_datum key, data;
647 pa_bool_t done;
648 char* prefix;
649 uint32_t priority;
650 pa_bool_t haschanged = FALSE;
651
652 if (strncmp(device, "sink:", 5) == 0)
653 prefix = pa_xstrdup("sink:");
654 else
655 prefix = pa_xstrdup("source:");
656
657 priority = e->priority[role_index];
658
659 /* Now we need to load up all the other entries of this type and shuffle the priroities around */
660
661 done = !pa_database_first(u->database, &key, NULL);
662
663 while (!done && !haschanged) {
664 pa_datum next_key;
665
666 done = !pa_database_next(u->database, &key, &next_key, NULL);
667
668 /* Only read devices with the right prefix */
669 if (key.size > strlen(prefix) && strncmp(key.data, prefix, strlen(prefix)) == 0) {
670 char *name;
671 struct entry *e2;
672
673 name = pa_xstrndup(key.data, key.size);
674
675 if ((e2 = read_entry(u, name))) {
676 if (SUBCOMMAND_PREFER_DEVICE == command) {
677 /* PREFER */
678 if (e2->priority[role_index] == (priority - 1)) {
679 e2->priority[role_index]++;
680 haschanged = TRUE;
681 }
682 } else {
683 /* DEFER */
684 if (e2->priority[role_index] == (priority + 1)) {
685 e2->priority[role_index]--;
686 haschanged = TRUE;
687 }
688 }
689
690 if (haschanged) {
691 data.data = e2;
692 data.size = sizeof(*e2);
693
694 if (pa_database_set(u->database, &key, &data, FALSE))
695 pa_log_warn("Could not save device");
696 }
697
698 pa_xfree(e2);
699 }
700
701 pa_xfree(name);
702 }
703
704 pa_datum_free(&key);
705 key = next_key;
706 }
707
708 /* Now write out our actual entry */
709 if (haschanged) {
710 if (SUBCOMMAND_PREFER_DEVICE == command)
711 e->priority[role_index]--;
712 else
713 e->priority[role_index]++;
714
715 key.data = (char *) device;
716 key.size = strlen(device);
717
718 data.data = e;
719 data.size = sizeof(*e);
720
721 if (pa_database_set(u->database, &key, &data, FALSE))
722 pa_log_warn("Could not save device");
723
724 trigger_save(u);
725 }
726
727 pa_xfree(e);
728
729 pa_xfree(prefix);
730 }
731 else
732 pa_log_warn("Could not reorder device %s, no entry in database", device);
733
734 break;
735 }
736
737 case SUBCOMMAND_SUBSCRIBE: {
738
739 pa_bool_t enabled;
740
741 if (pa_tagstruct_get_boolean(t, &enabled) < 0 ||
742 !pa_tagstruct_eof(t))
743 goto fail;
744
745 if (enabled)
746 pa_idxset_put(u->subscribed, c, NULL);
747 else
748 pa_idxset_remove_by_data(u->subscribed, c, NULL);
749
750 break;
751 }
752
753 default:
754 goto fail;
755 }
756
757 pa_pstream_send_tagstruct(pa_native_connection_get_pstream(c), reply);
758 return 0;
759
760 fail:
761
762 if (reply)
763 pa_tagstruct_free(reply);
764
765 return -1;
766 }
767
768 static pa_hook_result_t connection_unlink_hook_cb(pa_native_protocol *p, pa_native_connection *c, struct userdata *u) {
769 pa_assert(p);
770 pa_assert(c);
771 pa_assert(u);
772
773 pa_idxset_remove_by_data(u->subscribed, c, NULL);
774 return PA_HOOK_OK;
775 }
776
777 int pa__init(pa_module*m) {
778 pa_modargs *ma = NULL;
779 struct userdata *u;
780 char *fname;
781 pa_sink *sink;
782 pa_source *source;
783 uint32_t idx;
784
785 pa_assert(m);
786
787 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
788 pa_log("Failed to parse module arguments");
789 goto fail;
790 }
791
792 m->userdata = u = pa_xnew0(struct userdata, 1);
793 u->core = m->core;
794 u->module = m;
795 u->subscribed = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
796
797 u->protocol = pa_native_protocol_get(m->core);
798 pa_native_protocol_install_ext(u->protocol, m, extension_cb);
799
800 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);
801
802 u->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_SINK|PA_SUBSCRIPTION_MASK_SOURCE, subscribe_callback, u);
803
804 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);
805 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);
806
807 if (!(fname = pa_state_path("device-manager", TRUE)))
808 goto fail;
809
810 if (!(u->database = pa_database_open(fname, TRUE))) {
811 pa_log("Failed to open volume database '%s': %s", fname, pa_cstrerror(errno));
812 pa_xfree(fname);
813 goto fail;
814 }
815
816 pa_log_info("Sucessfully opened database file '%s'.", fname);
817 pa_xfree(fname);
818
819 for (sink = pa_idxset_first(m->core->sinks, &idx); sink; sink = pa_idxset_next(m->core->sinks, &idx))
820 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_NEW, sink->index, u);
821
822 for (source = pa_idxset_first(m->core->sources, &idx); source; source = pa_idxset_next(m->core->sources, &idx))
823 subscribe_callback(m->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_NEW, source->index, u);
824
825 pa_modargs_free(ma);
826 return 0;
827
828 fail:
829 pa__done(m);
830
831 if (ma)
832 pa_modargs_free(ma);
833
834 return -1;
835 }
836
837 void pa__done(pa_module*m) {
838 struct userdata* u;
839
840 pa_assert(m);
841
842 if (!(u = m->userdata))
843 return;
844
845 if (u->subscription)
846 pa_subscription_free(u->subscription);
847
848 if (u->sink_new_hook_slot)
849 pa_hook_slot_free(u->sink_new_hook_slot);
850 if (u->source_new_hook_slot)
851 pa_hook_slot_free(u->source_new_hook_slot);
852
853 if (u->save_time_event)
854 u->core->mainloop->time_free(u->save_time_event);
855
856 if (u->database)
857 pa_database_close(u->database);
858
859 if (u->protocol) {
860 pa_native_protocol_remove_ext(u->protocol, m);
861 pa_native_protocol_unref(u->protocol);
862 }
863
864 if (u->subscribed)
865 pa_idxset_free(u->subscribed, NULL, NULL);
866
867 pa_xfree(u);
868 }